Error executing template "Designs/Swift-v2/Paragraph/Swift-v2_MenuRelatedContent/Menu.cshtml"
System.ArgumentException: An item with the same key has already been added. Key: GROUP161
at System.Collections.Generic.Dictionary`2.TryInsert(TKey key, TValue value, InsertionBehavior behavior)
at Dynamicweb.Ecommerce.Products.GroupService.GetSubgroups(Group group, Boolean showUnTranslated)
at Dynamicweb.Ecommerce.Frontend.Navigation.GroupNavigationTreeNodeProvider.GetNodes(NavigationContext context, NavigationSettings settings, NavigationTreeNode parent)
at System.Linq.Enumerable.SelectManySingleSelectorIterator`2.MoveNext()
at System.Linq.Enumerable.SelectEnumerableIterator`2.MoveNext()
at System.Linq.Enumerable.<Any>g__WithEnumerator|36_0[TSource](IEnumerable`1 source)
at System.Linq.Enumerable.Any[TSource](IEnumerable`1 source)
at CompiledRazorTemplates.Dynamic.RazorEngine_6cbcbc0b4d164f47aaa22d38203131f3.NavigationTreeHasChildren(NavigationTreeNodeViewModel rootNode)
at CompiledRazorTemplates.Dynamic.RazorEngine_6cbcbc0b4d164f47aaa22d38203131f3.IsMegaMenu(NavigationTreeNodeViewModel rootNode, String submenuType)
at CompiledRazorTemplates.Dynamic.RazorEngine_6cbcbc0b4d164f47aaa22d38203131f3.ExecuteAsync()
at RazorEngine.Templating.TemplateBase.Run(ExecuteContext context, TextWriter reader)
at RazorEngine.Templating.RazorEngineCore.RunTemplate(ICompiledTemplate template, TextWriter writer, Object model, DynamicViewBag viewBag)
at RazorEngine.Templating.RazorEngineService.Run(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag)
at RazorEngine.Templating.DynamicWrapperService.Run(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag)
at RazorEngine.Templating.RazorEngineServiceExtensions.Run(IRazorEngineService service, String name, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag)
at RazorEngine.Templating.RazorEngineServiceExtensions.<>c__DisplayClass23_0.<Run>b__0(TextWriter writer)
at RazorEngine.Templating.RazorEngineServiceExtensions.WithWriter(Action`1 withWriter)
at RazorEngine.Templating.RazorEngineServiceExtensions.Run(IRazorEngineService service, String name, Type modelType, Object model, DynamicViewBag viewBag)
at Dynamicweb.Rendering.RazorTemplateRenderingProvider.Render(Template template)
at Dynamicweb.Rendering.TemplateRenderingService.Render(Template template)
at Dynamicweb.Rendering.Template.RenderRazorTemplate()
1 @inherits Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.ParagraphViewModel>
2 @using Dynamicweb.Frontend.Navigation
3 @using Dynamicweb.Ecommerce.ProductCatalog
4
5 @functions {
6
7 NavigationTreeViewModel GetNavigationTreeFromPageId(int pageId = 0, bool includeFolders = false, int startLevel = 1, int stopLevel = 9)
8 {
9 var navigationSettings = new NavigationSettings()
10 {
11 StartLevel = startLevel,
12 StopLevel = stopLevel,
13 RootPageId = pageId,
14 IncludeFoldersAndHidden = includeFolders,
15 ExpandMode = ExpandMode.All,
16 };
17
18 return Navigation.GetNavigationViewModel(navigationSettings);
19 }
20
21 string GetGroupFieldValue(string fieldSystemName, NavigationTreeNodeViewModel node)
22 {
23 var productGroup = node.GetProductGroup();
24 string fieldValue = string.Empty;
25 if (productGroup.GroupFields is not null)
26 {
27 foreach (var field in productGroup.GroupFields)
28 {
29 if (field.SystemName == fieldSystemName)
30 {
31 fieldValue = field.Value?.ToString() ?? string.Empty;
32 }
33 }
34 }
35 return fieldValue;
36 }
37
38 bool NavigationTreeHasChildren(NavigationTreeNodeViewModel rootNode)
39 {
40 foreach (var subNode in rootNode.Nodes)
41 {
42 if (subNode.Nodes.Any())
43 {
44 return true;
45 }
46 }
47 return false;
48 }
49
50 int GetPageIdFromLink(string pageLink)
51 {
52 return !string.IsNullOrEmpty(pageLink) ? Convert.ToInt32(pageLink.Substring(pageLink.LastIndexOf('=') + 1)) : 0;
53
54 }
55 string GetSubmenuType(NavigationTreeNodeViewModel rootNode)
56 {
57 string submenuType = string.Empty;
58 var nodePage = Dynamicweb.Content.Services.Pages.GetPage(rootNode.PageId);
59 var pageType = !string.IsNullOrEmpty(nodePage.ItemType) ? nodePage.ItemType : "Swift-v2_Page";
60 if (nodePage.PropertyItem is object && nodePage.PropertyItem.TryGetValue("SubmenuType", out object submenuTypeValue))
61 {
62 submenuType = Dynamicweb.Core.Converter.ToString(submenuTypeValue);
63 }
64 return submenuType;
65 }
66
67 bool IsMegaMenu(NavigationTreeNodeViewModel rootNode, string submenuType)
68 {
69 switch (submenuType)
70 {
71 case "dropdown":
72 return false;
73 case "auto":
74 return NavigationTreeHasChildren(rootNode);
75 default:
76 return true;
77 }
78 }
79
80 string isActive(NavigationTreeNodeViewModel node)
81 {
82 return node.IsActive ? "aria-current='page'" : string.Empty;
83 }
84
85 string isActiveDropdown(NavigationTreeNodeViewModel node)
86 {
87 return node.IsActive ? "class=\"active\"" : string.Empty;
88 }
89
90 bool GetRelatedContentStructure(IEnumerable<NavigationTreeNodeViewModel> relatedContentNodes)
91 {
92 bool relatedContentIsNested = false;
93
94 foreach (var relatedContentNode in relatedContentNodes.Where(node => node.ShowInMenu))
95 {
96 if (relatedContentNode.Nodes.Any())
97 {
98 return relatedContentIsNested = true;
99 }
100 }
101
102 return relatedContentIsNested;
103 }
104 }
105
106 @{
107 // Page settings
108 int navigationRootPageId = 0;
109 if (Model.Item.TryGetLink("NavigationRoot", out var link))
110 {
111 navigationRootPageId = link.PageId;
112 }
113 var rootNavigation = GetNavigationTreeFromPageId(navigationRootPageId);
114 int maxEndNodes = 100;
115 if (Model.Item.TryGetString("MaxEndNodes", out var maxEndNodesValue))
116 {
117 maxEndNodes = Dynamicweb.Core.Converter.ToInt32(maxEndNodesValue);
118 }
119 string maxEndNodesText = Model.Item.GetString("ShowAllLinkLabel");
120 string clickable = "text-decoration-underline-hover text-decoration-accent-hover";
121 }
122
123 <div class="nav-wrapper megamenu-wrapper" data-swift-menu="@Model.ID">
124 <nav class="d-flex gap-2">
125 @foreach (var rootNode in rootNavigation.Nodes.Where(node => node.ShowInMenu))
126 {
127 string? relatedContentNavigationRoot = GetGroupFieldValue("ProductGroupRelatedContent", rootNode);
128 int relatedContentPageId = !string.IsNullOrEmpty(relatedContentNavigationRoot) ? GetPageIdFromLink(relatedContentNavigationRoot) : 0;
129 var relatedContentNodes = GetNavigationTreeFromPageId(relatedContentPageId, true).Nodes;
130 bool hasRelatedContent = relatedContentNodes.Any() && relatedContentPageId != 0;
131 bool relatedContentIsNested = hasRelatedContent ? GetRelatedContentStructure(relatedContentNodes) : false;
132 bool nodesExist = rootNode.Nodes.Any() || hasRelatedContent;
133
134 string submenuType = GetSubmenuType(rootNode);
135 bool isMegaMenu = IsMegaMenu(rootNode, submenuType);
136 string submenuTypeCss = isMegaMenu ? "position-static" : string.Empty;
137 string dropdown = nodesExist ? "dropdown" : string.Empty;
138 string dropdownAttributes = nodesExist ? "role=\"button\" data-bs-toggle=\"dropdown\" data-bs-offset=\"0,0\" aria-expanded=\"false\"" : string.Empty;
139
140 <div class="nav-item @dropdown @submenuTypeCss">
141 @if (rootNode.IsClickable)
142 {
143 <a class="nav-link p-2 @clickable" href="@rootNode.Link" @dropdownAttributes @isActive(rootNode)>
144 <span class="text-wrap-nowrap">@rootNode.Name</span>
145 </a>
146 }
147 else
148 {
149 <span class="nav-link p-2" role="button" @dropdownAttributes>
150 <span class="text-wrap-nowrap">@rootNode.Name</span>
151 </span>
152 }
153
154 @if (nodesExist)
155 {
156 if (isMegaMenu)
157 {
158 <div class="dropdown-menu border-0 megamenu border-bottom" data-dw-colorscheme="@Model.ColorScheme?.Id">
159 <div data-swift-container class="overflow-y-auto">
160 <div class="d-flex py-4 gap-4">
161
162 @if (hasRelatedContent)
163 {
164 <div class="col-auto megamenu-col d-flex flex-column pe-4 border-end gap-3">
165 @foreach (var relatedContentNode in relatedContentNodes.Where(node => node.ShowInMenu))
166 {
167 <nav>
168 @if (relatedContentNode.IsClickable)
169 {
170 <a class="nav-link px-0 lh-1 pb-1 mb-1 @clickable" href="@relatedContentNode.Link" @isActive(relatedContentNode)>
171 <strong>@relatedContentNode.Name</strong>
172 </a>
173 }
174 else
175 {
176 <div class="nav-link px-0 lh-1 pb-1 mb-1 pe-none" @isActive(relatedContentNode)>
177 <strong>@relatedContentNode.Name</strong>
178 </div>
179 }
180
181 @foreach (var relatedContentSubNode in relatedContentNode.Nodes.Where(node => node.ShowInMenu))
182 {
183 if (relatedContentSubNode.IsClickable)
184 {
185 <a class="nav-link px-0 lh-1 pb-1 @clickable" href="@relatedContentSubNode.Link" @isActive(relatedContentSubNode)>
186 <span>@relatedContentSubNode.Name</span>
187 </a>
188 }
189 else
190 {
191 <div class="nav-link px-0 lh-1 pb-1 pe-none">
192 <span>@relatedContentSubNode.Name</span>
193 </div>
194 }
195 }
196 </nav>
197 }
198 </div>
199
200 }
201
202 <div class="col megamenu-grid d-grid gap-3">
203
204 @foreach (var subNode in rootNode.Nodes.Where(node => node.ShowInMenu))
205 {
206 <div class="megamenu-col">
207 @if (subNode.IsClickable)
208 {
209 <a class="nav-link px-0 lh-1 pb-1 mb-1 @clickable" href="@subNode.Link" @isActive(subNode)>
210 <strong>@subNode.Name</strong>
211 </a>
212 }
213 else
214 {
215 <div class="nav-link px-0 lh-1 pb-1 mb-1 pe-none">
216 <strong>@subNode.Name</strong>
217 </div>
218 }
219
220 @foreach (var (endNode, index) in subNode.Nodes.Select((node, i) => (node, i)))
221 {
222 if (index < maxEndNodes && endNode.ShowInMenu)
223 {
224 if (endNode.IsClickable)
225 {
226 <a class="nav-link px-0 lh-1 pb-1 @clickable" href="@endNode.Link" @isActive(endNode)>
227 @endNode.Name
228 </a>
229 }
230 else
231 {
232 <div class="nav-link px-0 lh-1 pb-1 pe-none">
233 @endNode.Name
234 </div>
235 }
236
237 continue;
238 }
239
240 if (!string.IsNullOrWhiteSpace(maxEndNodesText))
241 {
242 <a class="nav-link px-0 text-decoration-underline mt-1 lh-1" href="@subNode.Link">
243 @Translate(maxEndNodesText)
244 </a>
245 }
246
247 break;
248 }
249 </div>
250
251 }
252 </div>
253 </div>
254 </div>
255 </div>
256 }
257 else
258 {
259 <ul class="dropdown-menu dropdown-menu-shadow" data-dw-colorscheme="@Model.ColorScheme?.Id">
260
261 @if (hasRelatedContent)
262 {
263 foreach (var relatedContentNode in relatedContentNodes)
264 {
265 if (relatedContentNode.IsClickable)
266 {
267 <li @isActiveDropdown(relatedContentNode)>
268 <a class="dropdown-item py-2 lh-1 @clickable" href="@relatedContentNode.Link" @isActive(relatedContentNode)>
269 <strong>@relatedContentNode.Name</strong>
270 </a>
271 </li>
272 }
273 else
274 {
275 <li>
276 <span class="dropdown-item py-2 lh-1 pe-none">
277 <strong>@relatedContentNode.Name</strong>
278 </span>
279 </li>
280
281 }
282
283 foreach (var relatedContentSubNode in relatedContentNode.Nodes.Where(node => node.ShowInMenu))
284 {
285 if (relatedContentSubNode.IsClickable)
286 {
287 <li @isActiveDropdown(relatedContentSubNode)>
288 <a class="dropdown-item py-2 lh-1 @clickable" href="@relatedContentSubNode.Link" @isActive(relatedContentSubNode)>
289 <strong>@relatedContentSubNode.Name</strong>
290 </a>
291 </li>
292 }
293 else
294 {
295 <li>
296 <span class="dropdown-item py-2 lh-1 pe-none">
297 <strong>@relatedContentSubNode.Name</strong>
298 </span>
299 </li>
300 }
301 }
302 }
303
304 <li class="dropdown-divider"></li>
305 }
306
307 @foreach (var subNode in rootNode.Nodes.Where(node => node.ShowInMenu))
308 {
309 if (subNode.IsClickable)
310 {
311
312 <li @isActiveDropdown(subNode)>
313 <a class="dropdown-item py-2 lh-1 @clickable" href="@subNode.Link" @isActive(subNode)>
314 <strong>@subNode.Name</strong>
315 </a>
316 </li>
317 }
318 else
319 {
320 <li>
321 <span class="dropdown-item py-2 lh-1 pe-none">
322 <strong>@subNode.Name</strong>
323 </span>
324 </li>
325 }
326 }
327 </ul>
328 }
329 }
330 </div>
331 }
332 </nav>
333 </div>
334