Error executing template "Designs/Swift/Paragraph/Swift_ProductListItemRepeater_Custom.cshtml"
System.NullReferenceException: Object reference not set to an instance of an object.
at CompiledRazorTemplates.Dynamic.RazorEngine_4d6005f3f24d41b98817e0cb36642944.Execute() in D:\dynamicweb.net\Solutions\Wineshop\Files\Templates\Designs\Swift\Paragraph\Swift_ProductListItemRepeater_Custom.cshtml:line 51
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 System.Web
5 @using Dynamicweb.Environment
6 @using Smartpage.PhilipsonWine.Ecommerce.ProductInformation @*CUSTOM*@
7
8 @* CUSTOMIZED SWIFT (v1.25.0) TEMPLATE *@
9
10 @{
11 string theme = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("Theme")) ? " theme " + Model.Item.GetRawValueString("Theme").Replace(" ", "").Trim().ToLower() : "";
12 //CUSTOM
13 string gridCardBackgroundColor = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("TopGradientColor")) && !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("BottomGradientColor")) ? "background: linear-gradient(" + Model.Item.GetRawValueString("TopGradientColor") + ", " + Model.Item.GetRawValueString("BottomGradientColor") + ");" : ""; //Custom code
14 string borderRadius = Model.Item.GetInt32("BorderRadius") != 0 ? "border-radius: " + Model.Item.GetInt32("BorderRadius").ToString() + "px;" : ""; //Custom code
15 string boxShadow = !string.IsNullOrEmpty(Model.Item.GetRawValueString("BoxShadow")) ? "box-shadow: " + Dynamicweb.Core.Encoders.HtmlEncoder.HtmlAttributeEncode(Model.Item.GetRawValueString("BoxShadow")) + ";" : ""; //Custom code
16 string hoverEffect = Model.Item.GetBoolean("ActivateHoverEffect") ? "list-item-article-hover" : ""; //Custom code
17 //--CUSTOM
18 int productsCount = 0;
19 int maxProductsCounter = 0;
20
21 string productInfoFeed = "";
22 bool isLazyLoadingForProductInfoEnabled = Dynamicweb.Core.Converter.ToBoolean(Dynamicweb.Context.Current.Items["IsLazyLoadingForProductInfoEnabled"]);
23 if (isLazyLoadingForProductInfoEnabled)
24 {
25 if (Dynamicweb.Context.Current.Items.Contains("ProductInfoFeed"))
26 {
27 productInfoFeed = Dynamicweb.Context.Current.Items["ProductInfoFeed"]?.ToString();
28 if (!string.IsNullOrEmpty(productInfoFeed))
29 {
30 productInfoFeed = $"data-product-info-feed=\"{productInfoFeed}\"";
31 }
32 }
33 }
34
35 ProductListViewModel productList = null;
36 if (Dynamicweb.Context.Current.Items.Contains("ProductList"))
37 {
38 productList = (ProductListViewModel)Dynamicweb.Context.Current.Items["ProductList"];
39 }
40 else if (Pageview.Item["DummyProductGroup"] != null && Pageview.IsVisualEditorMode) //NOTE: Standard Swift (v1.21.0)
41 {
42 var pageViewModel = Dynamicweb.Frontend.ContentViewModelFactory.CreatePageInfoViewModel(Pageview.Page);
43 ProductListViewModel groupList = pageViewModel.Item.GetValue("DummyProductGroup") != null ? pageViewModel.Item.GetValue("DummyProductGroup") as ProductListViewModel : new ProductListViewModel();//NOTE: Standard Swift (v1.21.0)
44
45 if (groupList?.Products is object)
46 {
47 productList = groupList;
48 }
49 }
50
51 bool useAsSlider = productList.TotalProductsCount > 1 && Model.Item.GetBoolean("UseAsSlider");
52 }
53
54 @if (productList is object)
55 {
56 string positionRelativeClass = useAsSlider ? "position-relative" : "";
57
58 <div class="h-100@(theme) @positionRelativeClass product-list item_@Model.Item.SystemName.ToLower()" @productInfoFeed>
59
60 @if (useAsSlider)
61 {
62 int sliderAutoTime = Model.Item.GetInt32("SliderAutoTime");
63 <button class="js-list-item-previous-slide list-item-slide-btn list-item-slide-btn-prev"></button>
64 <button class="js-list-item-next-slide list-item-slide-btn list-item-slide-btn-next"></button>
65 <input type="hidden" class="js-auto-slide-millisecondsInput" value="@sliderAutoTime" />
66 }
67
68 @{
69 bool isVisualEditor = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString.Get("VisualEdit")) ? Convert.ToBoolean(Dynamicweb.Context.Current.Request.QueryString.Get("VisualEdit")) : false;
70
71 string googleTagManagerID = Pageview.AreaSettings.GetString("GoogleTagManagerID");
72 string googleAnalyticsMeasurementID = Pageview.AreaSettings.GetString("GoogleAnalyticsMeasurementID");
73
74 bool allowTracking = true;
75 if (CookieManager.IsCookieManagementActive)
76 {
77 var cookieOptInLevel = CookieManager.GetCookieOptInLevel();
78 allowTracking = cookieOptInLevel == CookieOptInLevel.All || (cookieOptInLevel == CookieOptInLevel.Functional && CookieManager.GetCookieOptInCategories().Contains("Statistical"));
79 }
80
81 string groupId = productList?.Group?.Id != null ? productList.Group.Id : "";
82 string url = Dynamicweb.Context.Current.Request.RawUrl;
83
84 if (productList.TotalProductsCount > 0)
85 {
86 int pageSizeSetting = Converter.ToInt32(Dynamicweb.Context.Current.Request.QueryString.Get("OriginalPageSize")) > 0 ? Converter.ToInt32(Dynamicweb.Context.Current.Request.QueryString.Get("OriginalPageSize")) : productList.PageSize;
87 int pageNumber = Converter.ToInt32(Dynamicweb.Context.Current.Request.QueryString.Get("PageNum")) > 0 ? Converter.ToInt32(Dynamicweb.Context.Current.Request.QueryString.Get("PageNum")) : productList.CurrentPage;
88 int pageSize = Converter.ToInt32(Dynamicweb.Context.Current.Request.QueryString.Get("PageSize")) > 0 ? Converter.ToInt32(Dynamicweb.Context.Current.Request.QueryString.Get("PageSize")) : productList.PageSize;
89 pageNumber = pageSize != pageSizeSetting ? (pageSize / pageSizeSetting) : pageNumber;
90 int loadedProducts = productList.PageSize > productList.TotalProductsCount ? productList.TotalProductsCount : pageSizeSetting * pageNumber;
91 loadedProducts = loadedProducts > productList.TotalProductsCount ? productList.TotalProductsCount : loadedProducts;
92
93 pageNumber += 1;
94
95 string searchQuery = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString.Get("q")) ? Dynamicweb.Context.Current.Request.QueryString.Get("q") : "";
96 string searchLayout = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString.Get("SearchLayout")) ? Dynamicweb.Context.Current.Request.QueryString.Get("SearchLayout") : "";
97
98 int itemSourcePageId = Convert.ToInt32(Model.Item.GetRawValueString("ListComponentSource", "0"));
99
100 var pageService = new Dynamicweb.Content.PageService();
101 itemSourcePageId = itemSourcePageId > 0 && pageService.GetPageOrLanguage(itemSourcePageId, Pageview.AreaID) != null ? pageService.GetPageOrLanguage(itemSourcePageId, Pageview.AreaID).ID : itemSourcePageId;
102
103 var page = Dynamicweb.Content.Services.Pages.GetPage(itemSourcePageId);
104
105 bool useForSingleProduct = Model.Item.GetBoolean("UseForSingleProduct");
106
107 if (page != null)
108 {
109 var pageViewModel = Dynamicweb.Frontend.ContentViewModelFactory.CreatePageInfoViewModel(page);
110
111
112 string gridColumnSize = Model.Item.GetRawValueString("GridLayoutDesktop", "3-columns");
113 gridColumnSize = gridColumnSize == "2-columns" ? "g-col-lg-6" : gridColumnSize;
114 gridColumnSize = gridColumnSize == "3-columns" ? "g-col-lg-4" : gridColumnSize;
115 gridColumnSize = gridColumnSize == "4-columns" ? "g-col-lg-3" : gridColumnSize;
116 gridColumnSize = gridColumnSize == "6-columns" ? "g-col-lg-2" : gridColumnSize;
117 gridColumnSize = gridColumnSize == "list" ? "" : gridColumnSize;
118
119 //CUSTOM
120 int gridGapPageNumber = Converter.ToInt32(Dynamicweb.Context.Current.Request.QueryString.Get("PageNum")) > 0 ? Converter.ToInt32(Dynamicweb.Context.Current.Request.QueryString.Get("PageNum")) : productList.CurrentPage;
121 int horizontalGap = Model.Item.GetInt32("HorizontalGridGap");
122 int verticalGap = Model.Item.GetInt32("VerticalGridGap");
123 string topMargin = (gridGapPageNumber > 1 ? horizontalGap.ToString() : "0");
124 string customStyle = horizontalGap != 0 && verticalGap != 0 ? $"style=\"--horizontal-grid-gap: {horizontalGap.ToString()}px; --vertical-grid-gap: {verticalGap.ToString()}px; --top-margin: {topMargin.ToString()}px;\"" : "";
125
126 string gridColumnMobileSize = Model.Item.GetRawValueString("GridLayoutMobile", "2-columns");
127 gridColumnMobileSize = gridColumnMobileSize == "list" ? "g-col-12" : gridColumnMobileSize;
128 gridColumnMobileSize = gridColumnMobileSize == "2-columns" ? "g-col-6" : gridColumnMobileSize;
129
130 string listItemTheme = " theme " + pageViewModel.Item.GetRawValueString("Theme", string.Empty).Replace(" ", "").Trim().ToLower();
131 string listItemPadding = pageViewModel.Item.GetRawValueString("ContentPadding", string.Empty);
132 string listItemPaddingClass = string.Empty;
133
134 switch (listItemPadding)
135 {
136 case "small":
137 listItemPaddingClass = " p-2 p-xl-3";
138 break;
139 case "large":
140 listItemPaddingClass = " p-3 p-xl-4";
141 break;
142 case "small-x":
143 listItemPaddingClass = " px-2 px-md-3";
144 break;
145 case "large-x":
146 listItemPaddingClass = " px-3 px-md-4";
147 break;
148 }
149
150 <div class="list-item-article-container grid pb-" @customStyle>
151 @*//CUSTOM*@
152 @if ((!string.IsNullOrWhiteSpace(googleAnalyticsMeasurementID) || !string.IsNullOrWhiteSpace(googleTagManagerID)) && allowTracking)
153 {
154 <script>
155 window.dataLayer = window.dataLayer || []; //CUSTOM
156 window.dataLayer.push({ //CUSTOM
157 event: "view_item_list", //CUSTOM
158 item_list_id: "product_list_item_repeater",
159 item_list_name: "Product list (Item Repeater)",
160 items: [
161 @foreach (ProductViewModel product in productList.Products)
162 {
163 <text>{
164 item_id: "@product.Number",
165 item_name: "@Dynamicweb.Core.Encoders.HtmlEncoder.JavaScriptStringEncode(product.Name)",
166 currency: "@product.Price.CurrencyCode",
167 price: @PriceViewModelExtensions.ToStringInvariant(product.Price)
168 },</text>
169 }
170 ]
171 });
172 </script>
173 }
174
175 @foreach (ExtendedProductViewModel product in productList.Products) //CUSTOM
176 {
177 if (maxProductsCounter == 0 || (productsCount < maxProductsCounter))
178 {
179 string link = product.GetProductLink(GetPageIdByNavigationTag("Shop")); //CUSTOM
180
181 if (Dynamicweb.Context.Current.Items.Contains("ProductDetails"))
182 {
183 Dynamicweb.Context.Current.Items["ProductDetails"] = product;
184 }
185 else
186 {
187 Dynamicweb.Context.Current.Items.Add("ProductDetails", product);
188 }
189
190 if (Model.Item.GetString("ListComponentSource") != null)
191 {
192 string sliderItemClass = useAsSlider ? "slider-list-item-article js-slider-list-item-article" : "";
193 string sliderActiveItemClass = useAsSlider && product == productList.Products[0] ? "active-slider-item" : "";
194 string positionRelative = !useAsSlider ? "position-relative" : "";
195
196 <article class="@gridColumnMobileSize @gridColumnSize @listItemTheme @listItemPaddingClass @hoverEffect @sliderItemClass @sliderActiveItemClass d-flex flex-column @positionRelative @(!useForSingleProduct ? "list-item-article" : "") product js-product" style="@HttpUtility.HtmlAttributeEncode(gridCardBackgroundColor) @HttpUtility.HtmlAttributeEncode(borderRadius) @HttpUtility.HtmlAttributeEncode(boxShadow)" data-product-id="@product.Id" data-variant-id="@product.VariantId" itemscope itemtype="https://schema.org/Product">
197 @*//CUSTOM*@
198 @{
199 string clickProductLink = string.Empty;
200 if ((!string.IsNullOrWhiteSpace(googleAnalyticsMeasurementID) || !string.IsNullOrWhiteSpace(googleTagManagerID)) && allowTracking)
201 {
202 clickProductLink = "onclick=\"return clickProductLink('" + @product.Id + "', '" + @product.Name + "', '" + @product.VariantName + "', '" + @product.Price.CurrencyCode + "', '" + @PriceViewModelExtensions.ToStringInvariant(product.Price) + "')\"";
203 }
204 }
205 <a href="@link" class="stretched-link" onmouseover="swift.Image.swapImage(event)" onmouseout="swift.Image.swapImage(event)" @clickProductLink>
206 <span class="visually-hidden">@product.Name</span>
207 </a>
208 @if ((!string.IsNullOrWhiteSpace(googleAnalyticsMeasurementID) || !string.IsNullOrWhiteSpace(googleTagManagerID)) && allowTracking)
209 {
210 <script>
211 function clickProductLink(productId, productName, productVariant, productCurrency, productPrice) {
212 //if (typeof gtag !== "undefined") { //CUSTOM
213 window.dataLayer = window.dataLayer || []; //CUSTOM
214 window.dataLayer.push({ //CUSTOM
215 event: "select_item",
216 item_list_id: "product_list_item_repeater",
217 item_list_name: "Product list (Item Repeater)",
218 items: [
219 {
220 item_id: productId,
221 item_name: productName,
222 currency: productCurrency,
223 item_list_id: "product_list_item_repeater",
224 item_list_name: "Product list (Item Repeater)",
225 item_variant: productVariant,
226 price: productPrice
227 }
228 ]
229 });
230 //} //CUSTOM
231 }
232 </script>
233 }
234 @RenderGrid(itemSourcePageId)
235 </article>
236 }
237
238 productsCount++;
239 }
240 }
241
242 @if (useAsSlider)
243 {
244 <div class="js-slider-indicators slider-indicators"></div>
245 }
246 </div>
247
248 if (!useForSingleProduct)
249 {
250 <div class="my-3" id="ProductListLoadMore">
251 <div class="text-center">
252 <div class="opacity-85 mb-3">@loadedProducts @Translate("out of") @productList.TotalProductsCount @Translate("products")</div>
253 @if (productList.PageCount != 1 && maxProductsCounter == 0 && loadedProducts < productList.TotalProductsCount)
254 {
255 string sortBySelection = Dynamicweb.Context.Current.Request?.Form["SortBy"] ?? "";
256 sortBySelection = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString.Get("SortBy")) ? Dynamicweb.Context.Current.Request.QueryString.Get("SortBy") : sortBySelection;
257 string mainProductId = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString.Get("MainProductID")) ? Dynamicweb.Context.Current.Request.QueryString.Get("MainProductID") : "";
258
259 <form method="get" action="@url" data-response-target-element=".product-list" data-swap="afterend" class="w-100">
260 @if (productList?.FacetGroups != null)
261 {
262 foreach (FacetGroupViewModel facetGroup in productList.FacetGroups)
263 {
264 foreach (FacetViewModel facetItem in facetGroup.Facets)
265 {
266 foreach (FacetOptionViewModel facetOption in facetItem.Options)
267 {
268 if (facetOption.Selected)
269 {
270 <input type="hidden" name="@facetItem.QueryParameter" value="[@facetOption.Value]">
271 }
272 }
273 }
274 }
275 }
276
277 @if (!string.IsNullOrEmpty(searchQuery))
278 {
279 <input type="hidden" name="q" value="@Dynamicweb.Core.Encoders.HtmlEncoder.HtmlAttributeEncode(searchQuery)">@*//CUSTOM*@
280 <input type="hidden" name="SearchLayout" value="@searchLayout">
281 }
282
283 @if (!string.IsNullOrEmpty(mainProductId))
284 {
285 <input type="hidden" name="MainProductID" value="@mainProductId">
286 }
287
288 @if (productList?.Group?.Id != null)
289 {
290 <input type="hidden" name="GroupId" value="@groupId">
291 }
292
293 <input type="hidden" name="OriginalPageSize" value="@pageSizeSetting">
294 <input type="hidden" name="PageSize" value="@(loadedProducts + pageSizeSetting)">
295 <input type="hidden" name="PageNum" value="@pageNumber">
296 <input type="hidden" name="SortBy" value="@sortBySelection">
297 <input type="hidden" name="RequestType" value="UpdateList">
298 <input type="hidden" name="ParagraphID" value="@Model.ID">
299
300 @if (productList?.FacetGroups is object)
301 {
302 string nextPageLink = $"/Default.aspx?ID={Pageview.Page.ID}&PageNum={pageNumber}&SortBy={sortBySelection}";
303
304 foreach (FacetGroupViewModel facetGroup in productList.FacetGroups)
305 {
306 foreach (FacetViewModel facetItem in facetGroup.Facets)
307 {
308 foreach (FacetOptionViewModel facetOption in facetItem.Options)
309 {
310 if (facetOption.Selected)
311 {
312 nextPageLink += "&" + facetItem.QueryParameter + "=[" + facetOption.Value + "]";
313 }
314 }
315 }
316 }
317
318 nextPageLink += !string.IsNullOrEmpty(searchQuery) ? "&q=" + searchQuery : "";
319 string disableLoadMore = isLazyLoadingForProductInfoEnabled ? "d-none" : "";
320
321 <a href="@nextPageLink" class="btn btn-primary swift_load_more_button @disableLoadMore" onclick="swift.ProductList.Update(event)" id="LoadMoreButton_@Model.ID">@Translate("Load more products")</a>
322 }
323 </form>
324 }
325 </div>
326 </div>
327 }
328
329 <script>
330 function switchVariantProduct(id, price, imagesrc) {
331 var productImageElement = document.querySelector("#ProductImage_" + id);
332 var productPriceElement = document.querySelector("#ProductPrice_" + id + " .text-price");
333
334 if (productPriceElement) {
335 productPriceElement.innerText = price;
336 }
337
338 if (productImageElement) {
339 productImageElement.src = imagesrc;
340
341 var imageSrcset = productImageElement.srcset;
342 imageSrcset = imageSrcset.replace(/image=.*?&/g, 'image=' + imagesrc + "&");
343
344 productImageElement.srcset = imageSrcset;
345 }
346 }
347 </script>
348 }
349 else if (Pageview.IsVisualEditorMode)
350 {
351 <div class="alert alert-dark m-0" role="alert">
352 <span>@Translate("The selected component does not exist anymore")</span>
353 </div>
354 }
355 }
356 else
357 {
358 string noProductsFoundMessage = !string.IsNullOrEmpty(Model.Item.GetString("NoProductsFoundMessage")) ? Model.Item.GetString("NoProductsFoundMessage") : Translate("We did not find anything matching your search result");
359 bool hasSubgroups = false;
360
361 if (productList.SubGroups != null)
362 {
363 hasSubgroups = productList.SubGroups.Any();
364 }
365
366 if (!Model.Item.GetBoolean("HideNoProductsFoundMessage"))
367 {
368 if (!isVisualEditor)
369 {
370 <div class="alert alert-dark m-0" role="alert">
371 @noProductsFoundMessage
372 </div>
373 }
374 else
375 {
376 <div class="alert alert-dark m-0" role="alert">
377 @Translate("Product list: The list will be shown here, if any")
378 </div>
379 }
380 }
381 else if (!hasSubgroups)
382 {
383 <div class="alert alert-dark m-0" role="alert">
384 @noProductsFoundMessage
385 </div>
386 }
387 }
388 }
389 </div>
390 }
391 else if (Pageview.IsVisualEditorMode)
392 {
393 <div class="alert alert-dark m-0" role="alert">
394 <span>@Translate("Product list item repeater: The repeater paragraph will be shown here, if any products are available")</span>
395 </div>
396 }
397