Error executing template "Designs/Swift_custom/Paragraph/Swift_ProductListItemRepeater.cshtml"
System.NullReferenceException: Object reference not set to an instance of an object.
at CompiledRazorTemplates.Dynamic.RazorEngine_673627df026647d18e0022870badc34c.Execute() in D:\dynamicweb.net\Solutions\S_DW_Expotape\Files\Templates\Designs\Swift_custom\Paragraph\Swift_ProductListItemRepeater.cshtml:line 73
at RazorEngine.Templating.TemplateBase.RazorEngine.Templating.ITemplate.Run(ExecuteContext context, TextWriter reader)
at RazorEngine.Templating.RazorEngineService.RunCompile(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag)
at RazorEngine.Templating.RazorEngineServiceExtensions.<>c__DisplayClass16_0.<RunCompile>b__0(TextWriter writer)
at RazorEngine.Templating.RazorEngineServiceExtensions.WithWriter(Action`1 withWriter)
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.Ecommerce.ProductCatalog
3 @using Dynamicweb.Core
4 @using Dynamicweb.Ecommerce.CustomerExperienceCenter.Favorites
5 @using Dynamicweb.Environment
6
7 @functions
8 {
9 string liveInfoClass = "";
10 }
11
12 @{
13 bool isDetailPage = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString.Get("ProductID"));
14 string theme = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("Theme")) ? " theme " + Model.Item.GetRawValueString("Theme").Replace(" ", "").Trim().ToLower() : "";
15
16 string productInfoFeed = "";
17 bool isLazyLoadingForProductInfoEnabled = Dynamicweb.Core.Converter.ToBoolean(Dynamicweb.Context.Current.Items["IsLazyLoadingForProductInfoEnabled"]);
18 if (isLazyLoadingForProductInfoEnabled)
19 {
20 if (Dynamicweb.Context.Current.Items.Contains("ProductInfoFeed"))
21 {
22 productInfoFeed = Dynamicweb.Context.Current.Items["ProductInfoFeed"]?.ToString();
23 if (!string.IsNullOrEmpty(productInfoFeed))
24 {
25 productInfoFeed = $"data-product-info-feed=\"{productInfoFeed}\"";
26 }
27 }
28 liveInfoClass = "js-live-info";
29 }
30
31 }
32
33 @if (!isDetailPage)
34 {
35 <div class="h-100@(theme) item_@Model.Item.SystemName.ToLower()" @productInfoFeed>
36 @{
37 bool isVisualEditor = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString.Get("VisualEdit")) ? Convert.ToBoolean(Dynamicweb.Context.Current.Request.QueryString.Get("VisualEdit")) : false;
38
39 ProductListViewModel productList = new ProductListViewModel();
40
41 string googleTagManagerID = Pageview.AreaSettings.GetString("GoogleTagManagerID");
42 string googleAnalyticsMeasurementID = Pageview.AreaSettings.GetString("GoogleAnalyticsMeasurementID");
43 var cookieOptInLevel = CookieManager.GetCookieOptInLevel();
44 bool allowTracking = cookieOptInLevel == CookieOptInLevel.All || (cookieOptInLevel == CookieOptInLevel.Functional && CookieManager.GetCookieOptInCategories().Contains("Statistical"));
45
46 ProductListViewModelSettings productListSetting = new ProductListViewModelSettings
47 {
48 LanguageId = Dynamicweb.Ecommerce.Common.Context.LanguageID,
49 CurrencyCode = Dynamicweb.Ecommerce.Common.Context.Currency.Code,
50 CountryCode = Dynamicweb.Ecommerce.Common.Context.Country.Code2,
51 ShopId = Pageview.Area.EcomShopId
52 };
53
54 int productsCount = 0;
55 int maxProductsCounter = 0;
56
57 if (Dynamicweb.Context.Current.Items.Contains("ProductList"))
58 {
59 productList = (ProductListViewModel)Dynamicweb.Context.Current.Items["ProductList"];
60 }
61 else if (Pageview.Item["DummyProductGroup"] != null)
62 {
63 var pageViewModel = Dynamicweb.Frontend.ContentViewModelFactory.CreatePageInfoViewModel(Pageview.Page);
64 ProductListViewModel groupList = pageViewModel.Item.GetValue("DummyProductGroup") != null ? pageViewModel.Item.GetValue("DummyProductGroup") as ProductListViewModel : new ProductListViewModel();
65
66 if (groupList?.Group?.Id != null)
67 {
68 productList = ViewModelFactory.CreateView(productListSetting, groupList.Group.Id);
69 Dynamicweb.Context.Current.Items.Add("ProductList", productList);
70 }
71 else
72 {
73 productList = ViewModelFactory.CreateView(productListSetting, Dynamicweb.Ecommerce.Services.ProductGroups.GetGroups(Dynamicweb.Ecommerce.Common.Context.LanguageID).FirstOrDefault().Id);
74
75 Dynamicweb.Context.Current.Items.Add("ProductList", productList);
76 }
77 }
78 else if (Pageview.Item["DummyProductGroup"] == null)
79 {
80 productList = ViewModelFactory.CreateView(productListSetting, Dynamicweb.Ecommerce.Services.ProductGroups.GetGroups(Dynamicweb.Ecommerce.Common.Context.LanguageID).FirstOrDefault().Id);
81 Dynamicweb.Context.Current.Items.Add("ProductList", productList);
82 }
83
84 if (Pageview.Page.Item.SystemName == "Swift_ProductListComponentEdit")
85 {
86 if (productList.TotalProductsCount == 0)
87 {
88 ProductViewModelSettings productSetting = new ProductViewModelSettings
89 {
90 LanguageId = Dynamicweb.Ecommerce.Common.Context.LanguageID,
91 CurrencyCode = Dynamicweb.Ecommerce.Common.Context.Currency.Code,
92 CountryCode = Dynamicweb.Ecommerce.Common.Context.Country.Code2,
93 ShopId = Pageview.Area.EcomShopId
94 };
95
96 foreach (var product in Dynamicweb.Ecommerce.Services.Products.GetLastActiveProducts(3, Dynamicweb.Ecommerce.Common.Context.LanguageID, false))
97 {
98 var productView = ViewModelFactory.CreateView(productSetting, product.Id);
99 productList.Products.Add(productView);
100 }
101
102 Dynamicweb.Context.Current.Items["ProductList"] = productList;
103 }
104
105 productList.TotalProductsCount = 3;
106 productList.PageSize = 3;
107 maxProductsCounter = 3;
108 }
109
110 string groupId = productList?.Group?.Id != null ? productList.Group.Id : "";
111 string url = Dynamicweb.Context.Current.Request.RawUrl;
112
113 if (productList.TotalProductsCount > 0)
114 {
115 int pageSizeSetting = 30;
116 int pageSize = productList.PageSize;
117 pageSize += pageSizeSetting;
118
119 int loadedProducts = productList.PageSize > productList.TotalProductsCount ? productList.TotalProductsCount : productList.PageSize;
120 string searchQuery = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString.Get("q")) ? Dynamicweb.Context.Current.Request.QueryString.Get("q") : "";
121 string searchLayout = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString.Get("SearchLayout")) ? Dynamicweb.Context.Current.Request.QueryString.Get("SearchLayout") : "";
122
123 int listItemSourcePageId = Model.Item.GetInt32("ListComponentSource");
124 var page = Dynamicweb.Content.Services.Pages.GetPage(listItemSourcePageId);
125
126 if (page != null)
127 {
128 var pageViewModel = Dynamicweb.Frontend.ContentViewModelFactory.CreatePageInfoViewModel(page);
129
130 string gridColumnSize = Model.Item.GetRawValueString("GridLayoutDesktop", "3-columns");
131 gridColumnSize = gridColumnSize == "2-columns" ? "g-col-lg-6" : gridColumnSize;
132 gridColumnSize = gridColumnSize == "3-columns" ? "g-col-lg-4" : gridColumnSize;
133 gridColumnSize = gridColumnSize == "4-columns" ? "g-col-lg-3" : gridColumnSize;
134 gridColumnSize = gridColumnSize == "6-columns" ? "g-col-lg-2" : gridColumnSize;
135 gridColumnSize = gridColumnSize == "list" ? "" : gridColumnSize;
136
137 string gridColumnMobileSize = Model.Item.GetRawValueString("GridLayoutMobile", "2-columns");
138 gridColumnMobileSize = gridColumnMobileSize == "list" ? "g-col-12" : gridColumnMobileSize;
139 gridColumnMobileSize = gridColumnMobileSize == "2-columns" ? "g-col-6" : gridColumnMobileSize;
140
141 string listItemTheme = " theme " + pageViewModel.Item.GetRawValueString("Theme", string.Empty).Replace(" ", "").Trim().ToLower();
142 string listItemPadding = pageViewModel.Item.GetRawValueString("ContentPadding", string.Empty);
143 string listItemPaddingClass = string.Empty;
144
145 switch (listItemPadding)
146 {
147 case "small":
148 listItemPaddingClass = " p-2 p-xl-3";
149 break;
150 case "large":
151 listItemPaddingClass = " p-3 p-xl-4";
152 break;
153 case "small-x":
154 listItemPaddingClass = " px-2 px-md-3";
155 break;
156 case "large-x":
157 listItemPaddingClass = " px-3 px-md-4";
158 break;
159 }
160
161 <div class="grid">
162 @if ((!string.IsNullOrWhiteSpace(googleAnalyticsMeasurementID) || !string.IsNullOrWhiteSpace(googleTagManagerID)))
163 {
164 <script>
165 gtag("event", "view_item_list", {
166 item_list_id: "product_list_item_repeater",
167 item_list_name: "Product list (Item Repeater)",
168 items: [
169 @foreach (ProductViewModel product in productList.Products)
170 {
171 <text>{
172 item_id: "@product.Number",
173 item_name: "@Dynamicweb.Core.Encoders.HtmlEncoder.JavaScriptStringEncode(product.Name)",
174 currency: "@product.Price.CurrencyCode",
175 price: @product.Price.Price.ToString("0.00", System.Globalization.CultureInfo.InvariantCulture)
176 },</text>
177 }
178 ]
179 });
180
181 // CUSTOM BLOCK ADD START
182 function clickProductLink(productId, productName, productVariant, productCurrency, productPrice) {
183 if (typeof gtag !== "undefined") {
184 gtag("event", "select_item", {
185 item_list_id: "product_list_item_repeater",
186 item_list_name: "Product list (Item Repeater)",
187 items: [
188 {
189 item_id: productId,
190 item_name: productName,
191 currency: productCurrency,
192 item_list_id: "product_list_item_repeater",
193 item_list_name: "Product list (Item Repeater)",
194 item_variant: productVariant,
195 price: productPrice
196 }
197 ]
198 });
199 }
200 }
201 // CUSTOM BLOCK ADD END
202 </script>
203 }
204
205 @foreach (ProductViewModel product in productList.Products)
206 {
207 if (maxProductsCounter == 0 || (productsCount < maxProductsCounter))
208 {
209 string link = product.GetProductLink(GetPageIdByNavigationTag("Shop"), false);
210
211 if (Dynamicweb.Context.Current.Items.Contains("ProductDetails"))
212 {
213 Dynamicweb.Context.Current.Items["ProductDetails"] = product;
214 }
215 else
216 {
217 Dynamicweb.Context.Current.Items.Add("ProductDetails", product);
218 }
219 if (Convert.ToBoolean(product.ProductFields.FirstOrDefault(x => x.Key == "IsInspiration").Value?.Value))
220 {
221 string inspirationlink = product.ProductFields.FirstOrDefault(x => x.Key == "InspirationLink").Value?.Value.ToString();
222 string inspirationOnClickEvent = string.IsNullOrEmpty(inspirationlink) ? "" : $"onclick=\"location.href = '{inspirationlink}'\"";
223 string inspirationImage = product.DefaultImage.Value;
224
225 <article class="@gridColumnMobileSize @gridColumnSize @listItemTheme @listItemPaddingClass d-flex flex-column position-relative product inspiration-product">
226 <a href="@inspirationlink">
227 <img src="@inspirationImage" srcset="" alt="@product.Name"/>
228 </a>
229 </article>
230 }
231 else if (Model.Item.GetString("ListComponentSource") != null)
232 {
233 <article class="@gridColumnMobileSize @gridColumnSize @listItemTheme @listItemPaddingClass d-flex flex-column position-relative product js-product @liveInfoClass" data-product-id="@product.Id" itemscope itemtype="https://schema.org/Product">
234 @{
235 string clickProductLink = string.Empty;
236 if ((!string.IsNullOrWhiteSpace(googleAnalyticsMeasurementID) || !string.IsNullOrWhiteSpace(googleTagManagerID)))
237 {
238 clickProductLink = "onclick=\"return clickProductLink('" + @product.Id + "', '" + @Dynamicweb.Core.Encoders.HtmlEncoder.JavaScriptStringEncode(product.Name) + "', '" + @product.VariantName + "', '" + @product.Price.CurrencyCode + "', '" + @product.Price.Price.ToString("0.00", System.Globalization.CultureInfo.InvariantCulture) + "')\"";
239 }
240 }
241 <a href="@link" class="stretched-link" onmouseover="swift.Image.swapImage(event)" onmouseout="swift.Image.swapImage(event)" @clickProductLink>
242 <span class="visually-hidden">@product.Name</span>
243 </a>
244 @* CUSTOM BLOCK REMOVE START *@
245 @*@if ((!string.IsNullOrWhiteSpace(googleAnalyticsMeasurementID) || !string.IsNullOrWhiteSpace(googleTagManagerID)))
246 {
247 <script>
248 function clickProductLink(productId, productName, productVariant, productCurrency, productPrice) {
249 if (typeof gtag !== "undefined") {
250 gtag("event", "select_item", {
251 item_list_id: "product_list_item_repeater",
252 item_list_name: "Product list (Item Repeater)",
253 items: [
254 {
255 item_id: productId,
256 item_name: productName,
257 currency: productCurrency,
258 item_list_id: "product_list_item_repeater",
259 item_list_name: "Product list (Item Repeater)",
260 item_variant: productVariant,
261 price: productPrice
262 }
263 ]
264 });
265 }
266 }
267 </script>
268 }*@
269 @* CUSTOM BLOCK REMOVE END *@
270
271 @RenderGrid(listItemSourcePageId)
272 </article>
273 }
274
275 productsCount++;
276 }
277 }
278 </div>
279
280 <div class="my-3">
281 <div class="text-center">
282 <div class="opacity-85 mb-3">@loadedProducts @Translate("out of") @productList.TotalProductsCount @Translate("products")</div>
283 @if (productList.PageCount != 1 && maxProductsCounter == 0)
284 {
285 string sortBySelection = Dynamicweb.Context.Current.Request?.Form["SortBy"] ?? "";
286 sortBySelection = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString.Get("SortBy")) ? Dynamicweb.Context.Current.Request.QueryString.Get("SortBy") : sortBySelection;
287
288 <form method="get" action="@url" data-response-target-element="content" class="w-100">
289 @if (productList?.FacetGroups != null)
290 {
291 foreach (FacetGroupViewModel facetGroup in productList.FacetGroups)
292 {
293 foreach (FacetViewModel facetItem in facetGroup.Facets)
294 {
295 foreach (FacetOptionViewModel facetOption in facetItem.Options)
296 {
297 if (facetOption.Selected)
298 {
299 <input type="hidden" name="@facetItem.QueryParameter" value="[@facetOption.Value]">
300 }
301 }
302 }
303 }
304 }
305
306 @if (!string.IsNullOrEmpty(searchQuery))
307 {
308 <input type="hidden" name="q" value="@searchQuery">
309 <input type="hidden" name="SearchLayout" value="@searchLayout">
310 }
311
312 @if (productList?.Group?.Id != null)
313 {
314 <input type="hidden" name="GroupId" value="@productList.Group.Id">
315 }
316
317 <input type="hidden" name="PageSize" value="@pageSize">
318 <input type="hidden" name="SortBy" value="@sortBySelection">
319 <input type="hidden" name="RequestType" value="UpdateList">
320
321 @{
322 string nextPageLink = "/Default.aspx?ID=" + Pageview.Page.ID + "&PageSize=" + pageSize + "&SortBy=" + sortBySelection;
323
324 foreach (FacetGroupViewModel facetGroup in productList.FacetGroups)
325 {
326 foreach (FacetViewModel facetItem in facetGroup.Facets)
327 {
328 foreach (FacetOptionViewModel facetOption in facetItem.Options)
329 {
330 if (facetOption.Selected)
331 {
332 nextPageLink += "&" + facetItem.QueryParameter + "=[" + facetOption.Value + "]";
333 }
334 }
335 }
336 }
337
338 nextPageLink += productList?.Group?.Id != null ? "&GroupID=" + productList.Group.Id : "";
339 nextPageLink += !string.IsNullOrEmpty(searchQuery) ? "&q=" + searchQuery : "";
340 }
341
342 <a href="@nextPageLink" class="btn btn-primary" type="button" onclick="swift.ProductList.Update(event)" id="LoadMoreButton_@Model.ID">@Translate("Load more products")</a>
343 </form>
344 }
345 </div>
346 </div>
347
348 <script>
349 function switchVariantProduct(id, price, imagesrc) {
350 var productImageElement = document.querySelector("#ProductImage_" + id);
351 var productPriceElement = document.querySelector("#ProductPrice_" + id + " .text-price");
352
353 if (productPriceElement) {
354 productPriceElement.innerText = price;
355 }
356
357 if (productImageElement) {
358 productImageElement.src = imagesrc;
359
360 var imageSrcset = productImageElement.srcset;
361 imageSrcset = imageSrcset.replace(/image=.*?&/g, 'image=' + imagesrc + "&");
362
363 productImageElement.srcset = imageSrcset;
364 }
365 }
366 </script>
367 }
368 else if (Pageview.IsVisualEditorMode)
369 {
370 <div class="alert alert-dark m-0" role="alert">
371 <span>@Translate("The selected component does not exist anymore")</span>
372 </div>
373 }
374 }
375 else
376 {
377 string noProductsFoundMessage = !string.IsNullOrEmpty(Model.Item.GetString("NoProductsFoundMessage")) ? Model.Item.GetString("NoProductsFoundMessage") : Translate("We did not find anything matching your search result");
378 bool hasSubgroups = false;
379
380 if (productList.SubGroups != null)
381 {
382 hasSubgroups = productList.SubGroups.Any();
383 }
384
385 if (!Model.Item.GetBoolean("HideNoProductsFoundMessage"))
386 {
387 if (!isVisualEditor)
388 {
389 <div class="alert alert-dark m-0" role="alert">
390 @noProductsFoundMessage
391 </div>
392 }
393 else
394 {
395 <div class="alert alert-dark m-0" role="alert">
396 @Translate("Product list: The list will be shown here, if any")
397 </div>
398 }
399 }
400 else if (!hasSubgroups)
401 {
402 <div class="alert alert-dark m-0" role="alert">
403 @noProductsFoundMessage
404 </div>
405 }
406 }
407 }
408 </div>
409 }
410