Component builder for: Expotape List Area

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_76c856083374453ca407c02f0d7a4636.Execute() in D:\dynamicweb.net\Solutions\S_DW_Expotape\Files\Templates\Designs\Swift_custom\Paragraph\Swift_ProductListItemRepeater.cshtml:line 80
   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