Komponent editor til: Product list area

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