Error executing template "Designs/Swift/Paragraph/Swift_ProductDetailsGallery.cshtml"
System.ArgumentNullException: Value cannot be null.
Parameter name: source
   at System.Linq.Enumerable.Where[TSource](IEnumerable`1 source, Func`2 predicate)
   at CompiledRazorTemplates.Dynamic.RazorEngine_75582a8a54854b6d95452fdb31ee0095.Execute() in D:\dynamicweb.net\Solutions\scanoffice.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_ProductDetailsGallery.cshtml:line 18
   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.Frontend 4 5 @{ 6 ProductViewModel product = new ProductViewModel(); 7 8 if (Dynamicweb.Context.Current.Items.Contains("ProductDetails")) 9 { 10 product = (ProductViewModel)Dynamicweb.Context.Current.Items["ProductDetails"]; 11 } 12 13 @* Collect the images *@ 14 var selectedImageCategories = Model.Item.GetList("ImageAssets").SelectedValues; 15 bool includeImagePatternImages = Model.Item.GetBoolean("ImagePatternImages"); 16 17 @* Needed image data collection to support both DefaultImage, ImagePatterns and Image Assets *@ 18 IEnumerable<MediaViewModel> assetsImages = product.AssetCategories.Where(x => selectedImageCategories.Contains(x.SystemName)).SelectMany(x => x.Assets); 19 IEnumerable<MediaViewModel> images = new MediaViewModel[]{}; 20 images = includeImagePatternImages && assetsImages.Count() == 0 ? images.Append(product.DefaultImage) : images; 21 images = images.Union(assetsImages); 22 images = includeImagePatternImages ? images.Union(product.ImagePatternImages) : images; 23 24 bool defaultImageFallback = Model.Item.GetBoolean("DefaultImageFallback"); 25 26 int totalImages = 0; 27 foreach (MediaViewModel asset in images) { 28 var assetName = asset.Value.ToLower(); 29 if (assetName.Contains(".jpg") || assetName.Contains(".webp") || assetName.Contains(".png") || assetName.Contains(".gif")) { 30 totalImages++; 31 } 32 } 33 34 if (totalImages == 0) 35 { 36 if (defaultImageFallback) { 37 images = new List<MediaViewModel>(){ product.DefaultImage }; 38 totalImages = 1; 39 } else { 40 images = new List<MediaViewModel>(){ }; 41 totalImages = 0; 42 } 43 } 44 45 @* Layout settings *@ 46 string spacing = Model.Item.GetRawValueString("Spacing", "4"); 47 spacing = spacing == "none" ? "gap-0" : spacing; 48 spacing = spacing == "small" ? "gap-3" : spacing; 49 spacing = spacing == "large" ? "gap-4" : spacing; 50 51 string layout = Model.Item.GetRawValueString("Layout", "grid"); 52 } 53 54 @* Get images from selected categories or get all images *@ 55 @if (totalImages != 0 && images.Count() != 0) 56 { 57 string theme = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("Theme")) ? " theme " + Model.Item.GetRawValueString("Theme").Replace(" ", "").Trim().ToLower() : ""; 58 59 if (layout != "custom-slider") 60 { 61 62 @* Show the gallery on large screens *@ 63 <div class="d-none d-lg-block h-100 @theme"> 64 <div class="grid @spacing"> 65 @{ 66 int imageNumber = 0; 67 68 foreach (MediaViewModel asset in images) 69 { 70 var assetName = asset.Value.ToLower(); 71 72 if (assetName.Contains(".jpg") || assetName.Contains(".webp") || assetName.Contains(".png") || assetName.Contains(".gif")) 73 { 74 string colClass = totalImages > 1 ? "g-col-lg-6" : "g-col-12"; 75 colClass = layout == "full-first" && imageNumber == 0 ? "g-col-12" : colClass; 76 colClass = layout == "full-last" && imageNumber == (totalImages - 1) ? "g-col-12" : colClass; 77 colClass = layout == "advanced-grid" && imageNumber > 1 ? "g-col-4" : colClass; 78 79 colClass = layout == "advanced-grid" && totalImages == 1 ? "g-col-12" : colClass; 80 colClass = layout == "advanced-grid" && totalImages == 3 && imageNumber == 2 ? "g-col-12" : colClass; 81 colClass = layout == "advanced-grid" && totalImages == 4 && imageNumber == 2 ? "g-col-6" : colClass; 82 colClass = layout == "advanced-grid" && totalImages == 4 && imageNumber == 3 ? "g-col-6" : colClass; 83 colClass = layout == "advanced-grid" && totalImages == 6 && imageNumber == 5 ? "g-col-12" : colClass; 84 colClass = layout == "advanced-grid" && totalImages == 7 && imageNumber == 5 ? "g-col-6" : colClass; 85 colClass = layout == "advanced-grid" && totalImages == 7 && imageNumber == 6 ? "g-col-6" : colClass; 86 colClass = layout == "advanced-grid" && totalImages == 9 && imageNumber == 8 ? "g-col-12" : colClass; 87 88 <div class="@colClass"> 89 @RenderImage(asset, product, imageNumber) 90 </div> 91 92 imageNumber++; 93 } 94 } 95 } 96 </div> 97 </div> 98 99 } 100 101 @* Modal *@ 102 <div class="modal fade" id="modal_@Model.ID" tabindex="-1" aria-labelledby="productDetailsGalleryModalTitle" aria-hidden="true"> 103 <div class="modal-dialog modal-dialog-centered modal-xl"> 104 <div class="modal-content"> 105 <div class="modal-header visually-hidden"> 106 <h5 class="modal-title" id="productDetailsGalleryModalTitle">@Translate("Full image")</h5> 107 </div> 108 <div class="modal-body"> 109 <div id="FullImages_@Model.ID" class="d-flex align-items-center justify-content-center"> 110 @foreach (MediaViewModel asset in images) 111 { 112 var assetName = asset.Value.ToLower(); 113 if (assetName.Contains(".jpg") || assetName.Contains(".webp") || assetName.Contains(".png") || assetName.Contains(".gif")) 114 { 115 string imagePath = !string.IsNullOrEmpty(asset.Value) ? asset.Value : product.DefaultImage.Value; 116 var parms = new Dictionary<string, object>(); 117 parms.Add("columns", Model.GridRowColumnCount); 118 parms.Add("cssClass", "mw-100 mh-100"); 119 <span class="d-flex align-items-center justify-content-center overflow-hidden h-100"> 120 @RenderPartial("Components/Image.cshtml", new FileViewModel { Path = imagePath }, parms) 121 </span> 122 } 123 } 124 </div> 125 <script type="module"> 126 var sliderFull_@(Model.ID) = tns({ 127 container: '#FullImages_@Model.ID', 128 items: 1, 129 gutter: 16, 130 mouseDrag: true, 131 touch: true, 132 arrowKeys: true, 133 nav: false, 134 loop: false, 135 speed: 10, 136 controls: false, 137 swipeAngle: 30, 138 preventScrollOnTouch: 'auto' 139 }); 140 141 if (document.getElementById('modal_@Model.ID')) { 142 document.getElementById('modal_@Model.ID').addEventListener('show.bs.modal', function (event) { 143 var slideNumber = event.relatedTarget.getAttribute("data-image-number"); 144 sliderFull_@(Model.ID).goTo(slideNumber); 145 }); 146 } 147 </script> 148 </div> 149 </div> 150 </div> 151 </div> 152 153 154 155 @* Show the thumbs on small screens *@ 156 string defaultSliderClass = "d-block d-lg-none mini-product-image-slider mx-lg-0" + theme; 157 string customSliderClass = "d-block d-lg-flex flex-lg-row mini-product-image-slider mx-lg-0" + theme; 158 string sliderClass = layout == "custom-slider" ? @customSliderClass : @defaultSliderClass; 159 <div class="@sliderClass"> 160 <div class="custom-slider d-lg-flex flex-lg-column flex-lg-fill border me-lg-2"> 161 <div id="SmallScreenImages_@Model.ID"> 162 @{ 163 var smallImageNumber = 0; 164 165 foreach (MediaViewModel asset in images) 166 { 167 var assetName = asset.Value.ToLower(); 168 169 if (assetName.Contains(".jpg") || assetName.Contains(".webp") || assetName.Contains(".png") || assetName.Contains(".gif")) 170 { 171 @RenderImage(asset, product, smallImageNumber, "small") 172 smallImageNumber++; 173 } 174 } 175 } 176 </div> 177 </div> 178 179 180 @{ 181 if (images.Count() > 1) 182 { 183 <div id="SmallScreenImagesThumbnails_@Model.ID" class="custom-thumbnails tns-nav-thumbnails grid gap-2 my-3 m-lg-0 d-lg-flex flex-lg-column h-100"> 184 @{ 185 foreach (MediaViewModel asset in images) { 186 var assetName = asset.Value.ToLower(); 187 if (assetName.Contains(".jpg") || assetName.Contains(".webp") || assetName.Contains(".png") || assetName.Contains(".gif")) { 188 189 string imagePath = Dynamicweb.Context.Current.Server.UrlEncode(assetName); 190 string imagePathThumb = $"/Admin/Public/GetImage.ashx?image={imagePath}&width=160&format=webp"; 191 192 <div class="tns-nav-thumbnail-item ratio ratio-4x3 border outline-none" style="width:80px;"><img src="@imagePathThumb" class="p-2" style="object-fit: cover;"></div> 193 } 194 } 195 } 196 </div> 197 } 198 } 199 200 @* Tiny slider *@ 201 <script type="module"> 202 var slider_@Model.ID = tns({ 203 container: '#SmallScreenImages_@Model.ID', 204 items: 1, 205 gutter: 16, 206 mouseDrag: true, 207 touch: true, 208 arrowKeys: true, 209 nav: true, 210 navContainer: "#SmallScreenImagesThumbnails_@Model.ID", 211 navAsThumbnails: true, 212 loop: false, 213 controls: false, 214 swipeAngle: 30, 215 preventScrollOnTouch: 'auto', 216 autoHeight: false, 217 }); 218 </script> 219 </div> 220 } 221 222 @helper RenderImage(MediaViewModel asset, ProductViewModel product, int number, string screenSize = "large") { 223 string layout = Model.Item.GetRawValueString("Layout", "grid"); 224 string padding = ""; 225 string theme = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("ImageTheme")) ? " theme " + Model.Item.GetRawValueString("ImageTheme").Replace(" ", "").Trim().ToLower() : ""; 226 227 if (theme != "") 228 { 229 padding = "p-3"; 230 } 231 232 string ratio = Model.Item.GetRawValueString("ImageAspectRatio", ""); 233 ratio = ratio != "0" ? ratio : ""; 234 string ratioCssClass = ratio != "" && ratio != "fill" ? " ratio" : ""; 235 string ratioVariable = ratio != "" && ratio != "fill" ? "--bs-aspect-ratio: " + ratio : ""; 236 ratioCssClass = ratio != "" && ratio == "fill" && screenSize == "small" ? " ratio" : ratioCssClass; 237 ratioVariable = ratio != "" && ratio == "fill" && screenSize == "small" ? "--bs-aspect-ratio: 66%" : ratioVariable; 238 string fillClass = ratio == "fill" ? " h-100" : ""; 239 240 string imagePath = !string.IsNullOrEmpty(asset.Value) ? asset.Value : product.DefaultImage.Value; 241 string imageLinkPath = Dynamicweb.Context.Current.Server.UrlEncode(imagePath); 242 string productName = product.Name; 243 244 var parms = new Dictionary<string, object>(); 245 parms.Add("alt", product.Name); 246 parms.Add("itemprop", "image"); 247 parms.Add("columns", Model.GridRowColumnCount); 248 249 if (ratio == "fill" && layout != "grid") { 250 parms.Add("cssClass", "w-100 h-100 image-zoom-lg"); 251 } 252 else 253 { 254 parms.Add("cssClass", "mw-100 mh-100"); 255 } 256 257 258 <div class="h-100 @(padding)@(theme)"> 259 <a href="@imageLinkPath" class="d-block h-100 @(ratioCssClass)@(fillClass)" data-bs-toggle="modal" data-bs-target="#modal_@Model.ID" data-image-number="@number"> 260 <span class="d-flex align-items-center justify-content-center overflow-hidden h-100"> 261 @RenderPartial("Components/Image.cshtml", new FileViewModel { Path = imagePath }, parms) 262 </span> 263 </a> 264 </div> 265 } 266
Error executing template "Designs/Swift/Paragraph/Swift_ProductDetailsInfo.cshtml"
System.ArgumentNullException: Value cannot be null.
Parameter name: source
   at System.Linq.Enumerable.Where[TSource](IEnumerable`1 source, Func`2 predicate)
   at CompiledRazorTemplates.Dynamic.RazorEngine_fee972662edd421a993e766cdf3486a3.Execute() in D:\dynamicweb.net\Solutions\scanoffice.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_ProductDetailsInfo.cshtml:line 18
   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.Ecommerce.Products.FieldDisplayGroups 4 @using Dynamicweb.Frontend 5 @using Dynamicweb.Ecommerce.Products 6 @using ScanOffice.CustomModules 7 @{ 8 bool isVisualEditor = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString.Get("VisualEdit")) ? Convert.ToBoolean(Dynamicweb.Context.Current.Request.QueryString.Get("VisualEdit")) : false; 9 bool userIsLoggedIn = Pageview.User != null && Pageview.User.ID > 0 ? true : false; 10 ProductViewModel product = new ProductViewModel(); 11 12 if (Dynamicweb.Context.Current.Items.Contains("ProductDetails")) 13 { 14 product = (ProductViewModel)Dynamicweb.Context.Current.Items["ProductDetails"]; 15 } 16 string ItemAvailabilityIdentifier = string.Join(".", product.Id, Dynamicweb.Ecommerce.Common.Context.LanguageID, "itemAvailableDate"); 17 18 var _customerServiceETA = product.ProductFields.Where(x => x.Key == "CustomerServiceETA").FirstOrDefault().Value.Value; 19 bool customerServiceETA = _customerServiceETA == null ? false : Convert.ToBoolean(_customerServiceETA); 20 21 //SQSCOFECOM-250 - disable add to cart button with custom text message 22 string DisableAddToCartButton = product.ProductFields.Where(x => x.Key == "DisableAddToCartButton").FirstOrDefault().Value.Value.ToString(); 23 24 var _expectedDeliveryDate = product.ProductFields.Where(x => x.Key == "ExpectedDeliveryDate").FirstOrDefault().Value.Value; 25 DateTime expectedDeliveryDate = Convert.ToDateTime(_expectedDeliveryDate); 26 27 var bundleIncludedProducts = product.ProductFields.Single(x => x.Key == "BundleIncludedProducts"); 28 string bipValue = bundleIncludedProducts.Value.Value.ToString(); 29 bool bipViewProduct = string.IsNullOrWhiteSpace(bipValue) || bipValue == " " ? false : true; 30 31 var hideproductfieldValue = product.ProductFields.Single(x => x.Key == "HideProduct").Value.Value.ToString(); 32 bool productNotAvailable = Convert.ToBoolean(hideproductfieldValue); 33 34 string[] variantId = product.VariantId.Split('.'); 35 string disableAddToCart = string.IsNullOrEmpty(product.VariantId) && product.VariantInfo.VariantInfo != null ? "disabled" : ""; 36 string hideStockState = string.IsNullOrEmpty(product.VariantId) && product.VariantInfo.VariantInfo != null ? "d-none" : ""; 37 38 string url = "/Default.aspx?ID=" + (GetPageIdByNavigationTag("CartService")); 39 if (!url.Contains("LayoutTemplate")) 40 { 41 url += url.Contains("?") ? "&LayoutTemplate=Swift_MiniCart.cshtml" : "?LayoutTemplate=Swift_MiniCart.cshtml"; 42 } 43 44 IEnumerable<string> selectedDisplayGroups = Model.Item.GetList("MainFeatures").SelectedValues; 45 List<CategoryFieldViewModel> mainFeatures = new List<CategoryFieldViewModel>(); 46 47 foreach (var selection in selectedDisplayGroups) 48 { 49 50 foreach (CategoryFieldViewModel group in product.FieldDisplayGroups.Values) 51 { 52 53 if (selection == group.Id) 54 { 55 mainFeatures.Add(group); 56 } 57 } 58 } 59 60 if (DisableAddToCartButton == "True") 61 { 62 disableAddToCart = "disabled"; 63 } 64 65 66 string theme = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("Theme")) ? " theme " + Model.Item.GetRawValueString("Theme").Replace(" ", "").Trim().ToLower() : ""; 67 68 string titleFontSize = Model.Item.GetRawValueString("TitleFontSize", "display-6"); 69 70 string contentPadding = Model.Item.GetRawValueString("ContentPadding", ""); 71 contentPadding = contentPadding == "small" ? "p-2 p-md-3" : contentPadding; 72 contentPadding = contentPadding == "large" ? "p-4 p-md-5" : contentPadding; 73 74 string NoutovarastoTRE = product.ProductFields.Where(x => x.Key == "NoutovarastoTRE").FirstOrDefault().Value.Value.ToString(); 75 } 76 77 <div class="h-100 @(contentPadding) @(theme)"> 78 <div class="d-flex flex-column js-product"> 79 <div> 80 <h4 class="lato-h4" itemprop="name">@product.Name</h4> 81 @if (!Model.Item.GetBoolean("HideProductNumber")) 82 { 83 <div class="open-sans-caption text-color-medium">@product.Number</div> 84 } 85 </div> 86 87 @if (!string.IsNullOrEmpty(product.ShortDescription)) 88 { 89 <div class="mt-3 open-sans-body-one" itemprop="disambiguatingDescription"> 90 @product.ShortDescription 91 </div> 92 } 93 94 @{ 95 bool showWarehouseLocation = false; 96 97 if (Pageview.User != null) 98 { 99 if (Pageview.User.Groups != null) 100 { 101 showWarehouseLocation = Pageview.User.Groups.Any(g => 102 g?.CustomFieldValues?.Any(cfv => 103 cfv?.CustomField?.SystemName == "AccessUser_ShowWarehouseLocation" && cfv?.Value?.ToString().ToLower() == "true" 104 ) == true 105 ); 106 } 107 108 if (!showWarehouseLocation && Pageview.User.CustomFieldValues != null) 109 { 110 showWarehouseLocation = Pageview.User.CustomFieldValues.Any(cfv => 111 cfv?.CustomField?.SystemName == "AccessUser_ShowWarehouseLocation" && cfv?.Value?.ToString().ToLower() == "true" 112 ); 113 } 114 } 115 116 if (showWarehouseLocation) 117 { 118 <div class="lato-h5" itemprop="warehouseLocation"> 119 @NoutovarastoTRE 120 </div> 121 } 122 } 123 124 @if (userIsLoggedIn && !bipViewProduct && !Helpers.IsHiddedPrice()) 125 { 126 <div> 127 <span class="open-sans-caption text-color-medium">@Translate("Price")</span> 128 <div class="h4 mb-0" itemprop="offers" itemscope itemtype="https://schema.org/Offer"> 129 <span itemprop="priceCurrency" content="@product.Price.CurrencyCode" class="d-none"></span> 130 <span itemprop="price" content="@product.Price.Price" class="d-none"></span> 131 <span class="text-price lato-h5 text-color-primary">@product.Price.PriceFormatted</span> 132 </div> 133 @if (product.Price.Price != product.PriceBeforeDiscount.Price) 134 { 135 <div class="text-decoration-line-through opacity-85"> 136 @product.PriceBeforeDiscount.PriceFormatted 137 </div> 138 } 139 </div>} 140 141 @if (mainFeatures.Count > 0) 142 { 143 <div class="grid gap-0"> 144 @foreach (CategoryFieldViewModel mainFeatureGroup in mainFeatures) 145 { 146 foreach (var field in mainFeatureGroup.Fields) 147 { 148 @RenderField(field.Value) 149 } 150 } 151 </div> 152 } 153 154 @if (product.VariantInfo.VariantInfo != null) 155 { 156 int groupNumber = 1; 157 158 <div class="mb-3 js-variant-selector" data-combinations="@string.Join(",", product.VariantCombinations())"> 159 @foreach (var variantGroup in product.VariantGroups()) 160 { 161 VariantGroupViewModel group = variantGroup; 162 163 <h3 class="h6">@group.Name</h3> 164 <div class="mb-3 js-variant-group" data-group-id="@groupNumber"> 165 @foreach (var option in group.Options) 166 { 167 string active = variantId.Contains(option.Id) ? "active" : ""; 168 169 if (!string.IsNullOrEmpty(option.Color)) 170 { 171 <button type="button" class="btn colorbox rounded-circle me-1 mb-2 d-inline-block variant-option js-variant-option @active" style="background-color: @option.Color" onclick="swift.VariantSelector.OptionClick(event)" data-variant-id="@option.Id"></button> 172 } 173 else if (!string.IsNullOrEmpty(option.Color) && !string.IsNullOrEmpty(option.Image.Value)) 174 { 175 <button type="button" class="btn p-0 d-inline-block mb-2 variant-option js-variant-option @active" onclick="swift.VariantSelector.OptionClick(event)" data-variant-id="@option.Id"> 176 <img src="/Admin/Public/GetImage.ashx?image=@(option.Image.Value)&width=42&Format=WebP&Quality=70" /> 177 </button> 178 } 179 else 180 { 181 <button type="button" class="btn btn-secondary d-inline-block mb-2 variant-option js-variant-option @active" onclick="swift.VariantSelector.OptionClick(event)" data-variant-id="@option.Id"> 182 @option.Name 183 </button> 184 } 185 } 186 </div> 187 188 groupNumber++; 189 } 190 </div> 191 } 192 @if (DisableAddToCartButton == "True" && !bipViewProduct) 193 { 194 string DisableAddToCartText = Helpers.GetAreaItemValue("DisableAddToCart"); 195 <div class="mt-2 js-stock-state open-sans-body-one row"> 196 <div class="col-12 col-sm-auto d-flex align-items-center pr-0"> 197 <i class="fas fa-circle me-1 instock text-danger"></i> 198 <span class="fw-bold me-1 text-danger">Verkkokauppa:</span> 199 </div> 200 <div class="col-12 col-sm pl-xxl-0"> 201 <span>@DisableAddToCartText</span> 202 </div> 203 </div> 204 } 205 else if (!Model.Item.GetBoolean("HideStockState") && userIsLoggedIn && !bipViewProduct) 206 { 207 var ItemStatus = Helpers.ItemAvailabilityStatus(ItemAvailabilityIdentifier, customerServiceETA, expectedDeliveryDate, DisableAddToCartButton); 208 <div class="mt-2 js-stock-state open-sans-body-one @hideStockState"> 209 <i class="fas fa-circle me-1 instock @ItemStatus.Status"></i><span class="fw-bold me-1 @ItemStatus.Status">Verkkokauppa:</span><span>@Translate(ItemStatus.statusText)</span> 210 </div> 211 } 212 @if (userIsLoggedIn && !bipViewProduct) 213 { 214 if (!productNotAvailable) 215 { 216 <form method="post" action="@url" class="mt-3"> 217 <div class="d-flex flex-column"> 218 <input type="hidden" name="redirect" value="false" /> 219 <input type="hidden" name="ProductId" value="@product.Id" /> 220 <input type="hidden" name="cartcmd" value="add" /> 221 222 @if (!string.IsNullOrEmpty(product.VariantId)) 223 { 224 <input type="hidden" name="VariantId" value="@product.VariantId" /> 225 } 226 227 @if (!Model.Item.GetBoolean("QuantitySelector")) 228 { 229 <div class="flex-fill"> 230 <input id="Quantity_@product.Id" name="Quantity" value="1" type="hidden"> 231 <button type="button" onclick="swift.Cart.Update(event)" class="btn btn-primary js-add-to-cart-button w-100 @disableAddToCart" title="@Translate("Add to cart")" id="AddToCartButton@(product.Id)">@Translate("Add to cart")</button> 232 </div> 233 } 234 else 235 { 236 <div class="flex-fill input-primary-button-group d-flex flex-row mb-2"> 237 <span class="btn btn-primary me-1 @disableAddToCart" onclick="swift.ProductList.UpdateProductQuantity('minus', 'Quantity_@product.Id.Replace("/",@"\\/")', '@product.PurchaseQuantityStep')"><i class="fas fa-minus fa-sm"></i></span> 238 @if (product.PurchaseMinimumQuantity == 0) 239 { 240 <input id="Quantity_@product.Id" name="Quantity" value="1" class="form-control no-arrows mx-2 text-center" type="number" min="1"> 241 } 242 else 243 { 244 <input id="Quantity_@product.Id" name="Quantity" value="@product.PurchaseMinimumQuantity" class="form-control no-arrows mx-2 text-center" type="number" min="@product.PurchaseMinimumQuantity"> 245 246 } 247 <span class="btn btn-primary ms-1 @disableAddToCart" onclick="swift.ProductList.UpdateProductQuantity('plus', 'Quantity_@product.Id.Replace("/",@"\\/")', '@product.PurchaseQuantityStep')"><i class="fas fa-plus fa-sm"></i></span> 248 </div> 249 250 <div class="flex-fill input-group input-primary-button-group d-flex flex-row"> 251 <button type="button" onclick="swift.Cart.Update(event)" class="btn btn-primary flex-fill js-add-to-cart-button @disableAddToCart" title="@Translate("Add to cart")" id="AddToCartButton@(product.Id)">@Translate("Add to cart")</button> 252 </div> 253 } 254 </div> 255 </form> 256 } 257 } 258 </div> 259 </div> 260 261 @helper RenderField(FieldValueViewModel field) 262 { 263 string fieldValue = field?.Value != null ? field.Value.ToString() : ""; 264 bool noValues = false; 265 266 if (!string.IsNullOrEmpty(fieldValue)) 267 { 268 if (field.Value.GetType() == typeof(System.Collections.Generic.List<FieldOptionValueViewModel>)) 269 { 270 System.Collections.Generic.List<FieldOptionValueViewModel> values = field.Value as System.Collections.Generic.List<FieldOptionValueViewModel>; 271 noValues = values.Count > 0 ? false : true; 272 } 273 } 274 275 if (!string.IsNullOrEmpty(fieldValue) && noValues == false) 276 { 277 <dt class="g-col-12 g-col-sm-4 g-col-lg-12 fw-bold m-0">@field.Name</dt> 278 <dd class="g-col-12 g-col-sm-8 g-col-lg-12 mb-3"> 279 @RenderFieldValue(field) 280 </dd> 281 } 282 } 283 284 @helper RenderFieldValue(FieldValueViewModel field) 285 { 286 string fieldValue = field?.Value != null ? field.Value.ToString() : ""; 287 288 fieldValue = fieldValue == "False" ? Translate("No") : fieldValue; 289 fieldValue = fieldValue == "True" ? Translate("Yes") : fieldValue; 290 291 bool isColor = false; 292 293 if (field.Value.GetType() == typeof(System.Collections.Generic.List<Dynamicweb.Ecommerce.ProductCatalog.FieldOptionValueViewModel>)) 294 { 295 int valueCount = 0; 296 System.Collections.Generic.List<FieldOptionValueViewModel> values = field.Value as System.Collections.Generic.List<FieldOptionValueViewModel>; 297 int totalValues = values.Count; 298 299 foreach (FieldOptionValueViewModel option in values) 300 { 301 if (option.Value.Substring(0, 1) == "#") 302 { 303 isColor = true; 304 } 305 306 if (!isColor) 307 { 308 @option.Name 309 } 310 else 311 { 312 <span class="colorbox-sm" style="background-color: @option.Value" title="@option.Value"></span> 313 } 314 315 if (valueCount != totalValues && valueCount < (totalValues - 1)) 316 { 317 if (isColor) 318 { 319 <text> </text> 320 } 321 else 322 { 323 <text>, </text> 324 } 325 } 326 valueCount++; 327 } 328 } 329 else 330 { 331 if (fieldValue.Substring(0, 1) == "#") 332 { 333 isColor = true; 334 } 335 336 if (!isColor) 337 { 338 @fieldValue 339 } 340 else 341 { 342 <span class="colorbox-sm" style="background-color: @fieldValue" title="@fieldValue"></span> 343 } 344 } 345 } 346 347 @if (product.VariantInfo.VariantInfo != null) 348 { 349 <script> 350 //Initialize the variant selector 351 document.addEventListener('load', function (event) { 352 swift.VariantSelector.init(); 353 }); 354 </script> 355 } 356 357 <script> 358 window.addEventListener('keydown', function (e) { 359 if (e.keyIdentifier == 'U+000A' || e.keyIdentifier == 'Enter' || e.keyCode == 13) { 360 if (e.target.nodeName == 'INPUT' && e.target.getAttribute("type") != "search") { 361 e.preventDefault(); 362 return false; 363 } 364 } 365 }, true); 366 </script> 367
Error executing template "Designs/Swift/Paragraph/Solteq_ProductBundle.cshtml"
System.NullReferenceException: Object reference not set to an instance of an object.
   at CompiledRazorTemplates.Dynamic.RazorEngine_ddccc096745743ef8a454f5417369312.Execute() in D:\dynamicweb.net\Solutions\scanoffice.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Solteq_ProductBundle.cshtml:line 21
   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.Ecommerce.Products.FieldDisplayGroups 4 @using Dynamicweb.Frontend 5 @using ScanOffice.CustomModules 6 7 @{ 8 bool isVisualEditor = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString.Get("VisualEdit")) ? Convert.ToBoolean(Dynamicweb.Context.Current.Request.QueryString.Get("VisualEdit")) : false; 9 bool userIsLoggedIn = Pageview.User != null && Pageview.User.ID > 0 ? true : false; 10 string signInPage = "/Default.aspx?Id=" + GetPageIdByNavigationTag("SignInPage").ToString(); 11 12 string detailsPageLink = Dynamicweb.Context.Current.Items["DetailsPageLink"] != null ? Dynamicweb.Context.Current.Items["DetailsPageLink"].ToString() : ""; 13 ProductViewModel product = new ProductViewModel(); 14 15 string link = "/Default.aspx?ID=" + PageView.Current().ID; 16 17 if (Dynamicweb.Context.Current.Items.Contains("ProductDetails")) 18 { 19 product = (ProductViewModel)Dynamicweb.Context.Current.Items["ProductDetails"]; 20 } 21 string BundleIncludedProducts = !string.IsNullOrEmpty(product.ProductFields.Values.SingleOrDefault(x => x.SystemName == "BundleIncludedProducts").Value.ToString()) 22 ? product.ProductFields.Values.SingleOrDefault(x => x.SystemName == "BundleIncludedProducts").Value.ToString() : ""; 23 string BundleSelectableProducts = !string.IsNullOrEmpty(product.ProductFields.Values.SingleOrDefault(x => x.SystemName == "BundleSelectableProducts").Value.ToString()) 24 ? product.ProductFields.Values.SingleOrDefault(x => x.SystemName == "BundleSelectableProducts").Value.ToString() : ""; 25 26 string BundleSelectableProductsQty = !string.IsNullOrEmpty(product.ProductFields.Values.SingleOrDefault(x => x.SystemName == "BundleSelectableProductsQty").Value.ToString()) 27 ? product.ProductFields.Values.SingleOrDefault(x => x.SystemName == "BundleSelectableProductsQty").Value.ToString() : ""; 28 29 string BundleRecommendedProducts = !string.IsNullOrEmpty(product.ProductFields.Values.SingleOrDefault(x => x.SystemName == "BundleRecommendedProducts").Value.ToString()) 30 ? product.ProductFields.Values.SingleOrDefault(x => x.SystemName == "BundleRecommendedProducts").Value.ToString() : ""; 31 string BundleUsefulProducts = !string.IsNullOrEmpty(product.ProductFields.Values.SingleOrDefault(x => x.SystemName == "BundleUsefulProducts").Value.ToString()) 32 ? product.ProductFields.Values.SingleOrDefault(x => x.SystemName == "BundleUsefulProducts").Value.ToString() : ""; 33 string Title = Translate("Bundle Product"); 34 var guid = Guid.NewGuid().ToString("N").Substring(0,20); 35 //SQSCOFECOM-250 - disable add to cart button with custom text message 36 string DisableAddToCartButton = product.ProductFields.Where(x => x.Key == "DisableAddToCartButton").FirstOrDefault().Value.Value.ToString(); 37 string DisableAddToCartText = Helpers.GetAreaItemValue("DisableAddToCart"); 38 } 39 40 @if (!string.IsNullOrEmpty(BundleIncludedProducts)) { 41 <script id="mainproductdata" type="application/json"> 42 { 43 "ProductID": "@product.Id", 44 "ProductName": "@product.Name", 45 "ProductPrice": "@product.Price.PriceFormatted", 46 "Title" : "@Translate("Bundle Product")", 47 "IsUser": "@userIsLoggedIn", 48 "IsHiddedPrice" : "@Helpers.IsHiddedPrice()", 49 "SignInMessage" : "@Translate("Click here to Sign in")", 50 "AddToCartText": "@Translate("Add to cart")", 51 "CartId":"@GetPageIdByNavigationTag("CartService")", 52 "SignInButtonText": "@Translate("Sign in")", 53 "SignInLink": "@signInPage", 54 "ProductIdentifier": "@guid", 55 "DetailsPageLink": "@link", 56 "BundleIncludedProducts": "@BundleIncludedProducts", 57 "BundleSelectableProducts": "@BundleSelectableProducts", 58 "BundleSelectableProductsQty": "@BundleSelectableProductsQty", 59 "BundleRecommendedProducts": "@BundleRecommendedProducts", 60 "BundleUsefulProducts": "@BundleUsefulProducts", 61 "DisableAddToCartButton": "@DisableAddToCartButton", 62 "DisableAddToCartText": "@DisableAddToCartText" 63 } 64 </script> 65 66 <Product-Bundle></Product-Bundle> 67 } 68
Error executing template "Designs/Swift/Paragraph/Solteq_ProductDataTabs.cshtml"
System.ArgumentNullException: Value cannot be null.
Parameter name: source
   at System.Linq.Enumerable.Where[TSource](IEnumerable`1 source, Func`2 predicate)
   at CompiledRazorTemplates.Dynamic.RazorEngine_56400e719f974f7f8e27d4e130dc32fa.Execute() in D:\dynamicweb.net\Solutions\scanoffice.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Solteq_ProductDataTabs.cshtml:line 17
   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.Frontend 4 @using System.IO 5 @using System.Web 6 @using ScanOffice.CustomModules 7 @{ 8 9 ProductViewModel product = new ProductViewModel(); 10 11 if (Dynamicweb.Context.Current.Items.Contains("ProductDetails")) 12 { 13 product = (ProductViewModel)Dynamicweb.Context.Current.Items["ProductDetails"]; 14 } 15 16 int TabCounter = 1; 17 IEnumerable<MediaViewModel> Documents = product.AssetCategories.Where(x => x.Name == "Documents").SelectMany(x => x.Assets); 18 IEnumerable<MediaViewModel> Videos = product.AssetCategories.Where(x => x.Name == "Videos").SelectMany(x => x.Assets); 19 20 ListViewModel mainTabs = Model.Item.GetList("MainTabs"); 21 IEnumerable<string> selectedDisplayGroupIds = Model.Item.GetList("MainTabs").SelectedValues; 22 List<CategoryFieldViewModel> DataTabs = new List<CategoryFieldViewModel>(); 23 24 foreach (var selection in selectedDisplayGroupIds) 25 { 26 foreach (CategoryFieldViewModel group in product.FieldDisplayGroups.Values) 27 { 28 if (selection == group.Id) 29 { 30 31 bool hasvalue = group.Fields.Any(x => !string.IsNullOrEmpty(x.Value.Value.ToString())); 32 if (group.Name == "Documents") 33 { 34 hasvalue = Documents.Any(x => !string.IsNullOrEmpty(x.Value.ToString())) ? true : false; 35 } 36 else if (group.Name == "Video") 37 { 38 hasvalue = Videos.Any(x => !string.IsNullOrEmpty(x.Value.ToString())) ? true : false; 39 } 40 if (hasvalue) 41 { 42 DataTabs.Add(group); 43 } 44 45 } 46 } 47 } 48 } 49 50 @if (DataTabs.Count > 0) 51 { 52 <!-- Nav tabs --> 53 <ul class="nav nav-pills" id="datatabs" role="tablist"> 54 55 @foreach (var tab in DataTabs) 56 { 57 string tabId = tab.Id.ToLower(); 58 string tabTarget = "#" + tab.Id.ToLower() + "-content"; 59 string tabControl = tab.Id.ToLower(); 60 string tabActive = TabCounter == 1 ? "active" : ""; 61 62 <li class="nav-item" role="presentation"> 63 <button class="nav-link @tabActive lato-h6" id="@tabId" data-bs-toggle="tab" data-bs-target="@tabTarget" type="button" role="tab" aria-controls="@tabControl" aria-selected="true">@Translate(tab.Id.ToString(), tab.Name.ToString())</button> 64 </li> 65 66 if (TabCounter == DataTabs.Count) 67 { 68 TabCounter = 1; 69 } 70 else 71 { 72 TabCounter++; 73 } 74 75 } 76 77 </ul> 78 79 <!-- Tab panes --> 80 <div class="tab-content"> 81 @foreach (var tab in DataTabs) 82 { 83 string tabId = tab.Id.ToLower() + "-content"; 84 string tabTarget = tab.Id.ToLower(); 85 string tabActive = TabCounter == 1 ? "show active" : ""; 86 87 <div class="tab-pane fade @tabActive" id="@tabId" role="tabpanel" aria-labelledby="@tabTarget"> 88 @switch (tab.Name) 89 { 90 case "Description": 91 @renderDescription(product) 92 break; 93 case "Technical Data": 94 @renderTechnicalData(product) 95 break; 96 case "Documents": 97 @renderDocuments(Documents); 98 break; 99 case "Video": 100 @renderVideo(Videos); 101 break; 102 default: 103 break; 104 } 105 </div> 106 107 if (TabCounter == DataTabs.Count) 108 { 109 TabCounter = 1; 110 } 111 else 112 { 113 TabCounter++; 114 } 115 } 116 </div> 117 } 118 119 @helper renderDescription(ProductViewModel product) 120 { 121 <div class="description-tab"> 122 @product.LongDescription 123 </div> 124 } 125 126 @helper renderTechnicalData(ProductViewModel product) 127 { 128 var technical_data = Helpers.GetTechnicalData(product); 129 130 <table id="technical_data_table"> 131 @foreach (var group in technical_data) 132 { 133 var c = group.LongCount() + 1; 134 <tbody> 135 136 <th rowspan="@c">@Translate(group.Key)</th> 137 138 @foreach (var field in group) 139 { 140 <tr> 141 <td>@field.Name</td> 142 <td>@field.Unit</td> 143 <td>@field.Value</td> 144 </tr> 145 } 146 </tbody> 147 } 148 </table> 149 150 } 151 @helper renderDocuments(IEnumerable<MediaViewModel> Documents) 152 { 153 154 bool userIsLoggedIn = Pageview.User != null && Pageview.User.ID > 0 ? true : false; 155 <ul> 156 @foreach (var file in Documents) 157 { 158 string filePath = HttpContext.Current.Server.MapPath(file.Value); 159 if (File.Exists(filePath)) 160 { 161 FileInfo fileInfo = new FileInfo(file.Value); 162 if (userIsLoggedIn && file.DisplayName.ToLower() == "installer") 163 { 164 <li> 165 <a href="/Admin/Public/DWSDownload.aspx?File=@file.Value" alt="@fileInfo.Name"> 166 <i class="fas fa-file-pdf"></i> 167 @fileInfo.Name 168 </a> 169 </li> 170 } 171 else if (file.DisplayName.ToLower() != "installer") 172 { 173 <li> 174 <a href="/Admin/Public/DWSDownload.aspx?File=@file.Value" alt="@fileInfo.Name"> 175 <i class="fas fa-file-pdf"></i> 176 @fileInfo.Name 177 </a> 178 </li> 179 } 180 181 } 182 } 183 </ul> 184 } 185 186 @helper renderVideo(IEnumerable<MediaViewModel> Videos) 187 { 188 <div class="video_div"> 189 @foreach (var i in Videos) 190 { 191 192 if (i.Keywords == "youtube") 193 { 194 var yvsrc = "https://www.youtube.com/embed/" + i.Value.Replace("/Files/", ""); 195 <iframe class="iframe-youtube" src="@yvsrc" title="@i.Name" frameborder="0" allow="accelerometer; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe> 196 } 197 if (i.Keywords == "vimeo") 198 { 199 var vvsrc = "https://player.vimeo.com/video/" + i.Value.Replace("/Files/", ""); 200 <iframe class="iframe-vimeo" src="@vvsrc" frameborder="0" allow="accelerometer; clipboard-write; fullscreen; picture-in-picture" allowfullscreen></iframe> 201 } 202 203 } 204 </div> 205 } 206 207 <style> 208 @@media(max-width: 600px) { 209 #technical_data_table table, thead, tbody, th, td, tr { 210 display: block; 211 } 212 213 #technical_data_table tr { 214 border-bottom: 1px solid #ccc; 215 } 216 217 #technical_data_table td { 218 border: none; 219 border-bottom: 0px solid #eee; 220 position: relative; 221 padding-left: 50%; 222 font-size: small; 223 } 224 225 #technical_data_table td:before { 226 position: absolute; 227 top: 6px; 228 left: 6px; 229 width: 45%; 230 padding-right: 10px; 231 white-space: nowrap; 232 } 233 } 234 235 .iframe-youtube { 236 top: 0; 237 left: 0; 238 bottom: 0; 239 right: 0; 240 height: 230px; 241 margin: 1em; 242 min-width: 400px; 243 } 244 245 .iframe-vimeo { 246 top: 0; 247 left: 0; 248 bottom: 0; 249 right: 0; 250 height: 230px; 251 margin: 1em; 252 min-width: 400px; 253 } 254 255 .video_div { 256 width: 100%; 257 height: 100%; 258 align-items: center; 259 justify-content: center; 260 padding-left: 2em; 261 } 262 263 @@media(max-width: 600px) { 264 .iframe-youtube { 265 top: 0; 266 left: 0; 267 bottom: 0; 268 right: 0; 269 width: 100%; 270 height: 100%; 271 margin: 0em; 272 min-width: 0; 273 } 274 275 .iframe-vimeo { 276 top: 0; 277 left: 0; 278 bottom: 0; 279 right: 0; 280 width: 100%; 281 height: 100%; 282 margin: 0em; 283 min-width: 0; 284 } 285 286 .video_div { 287 width: 100%; 288 height: 100%; 289 align-items: center; 290 justify-content: center; 291 margin: 0; 292 padding-left: 0; 293 } 294 } 295 </style> 296
Error executing template "Designs/Swift/Paragraph/Swift_ProductDetailsGallery.cshtml"
System.ArgumentNullException: Value cannot be null.
Parameter name: source
   at System.Linq.Enumerable.Where[TSource](IEnumerable`1 source, Func`2 predicate)
   at CompiledRazorTemplates.Dynamic.RazorEngine_75582a8a54854b6d95452fdb31ee0095.Execute() in D:\dynamicweb.net\Solutions\scanoffice.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_ProductDetailsGallery.cshtml:line 18
   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.Frontend 4 5 @{ 6 ProductViewModel product = new ProductViewModel(); 7 8 if (Dynamicweb.Context.Current.Items.Contains("ProductDetails")) 9 { 10 product = (ProductViewModel)Dynamicweb.Context.Current.Items["ProductDetails"]; 11 } 12 13 @* Collect the images *@ 14 var selectedImageCategories = Model.Item.GetList("ImageAssets").SelectedValues; 15 bool includeImagePatternImages = Model.Item.GetBoolean("ImagePatternImages"); 16 17 @* Needed image data collection to support both DefaultImage, ImagePatterns and Image Assets *@ 18 IEnumerable<MediaViewModel> assetsImages = product.AssetCategories.Where(x => selectedImageCategories.Contains(x.SystemName)).SelectMany(x => x.Assets); 19 IEnumerable<MediaViewModel> images = new MediaViewModel[]{}; 20 images = includeImagePatternImages && assetsImages.Count() == 0 ? images.Append(product.DefaultImage) : images; 21 images = images.Union(assetsImages); 22 images = includeImagePatternImages ? images.Union(product.ImagePatternImages) : images; 23 24 bool defaultImageFallback = Model.Item.GetBoolean("DefaultImageFallback"); 25 26 int totalImages = 0; 27 foreach (MediaViewModel asset in images) { 28 var assetName = asset.Value.ToLower(); 29 if (assetName.Contains(".jpg") || assetName.Contains(".webp") || assetName.Contains(".png") || assetName.Contains(".gif")) { 30 totalImages++; 31 } 32 } 33 34 if (totalImages == 0) 35 { 36 if (defaultImageFallback) { 37 images = new List<MediaViewModel>(){ product.DefaultImage }; 38 totalImages = 1; 39 } else { 40 images = new List<MediaViewModel>(){ }; 41 totalImages = 0; 42 } 43 } 44 45 @* Layout settings *@ 46 string spacing = Model.Item.GetRawValueString("Spacing", "4"); 47 spacing = spacing == "none" ? "gap-0" : spacing; 48 spacing = spacing == "small" ? "gap-3" : spacing; 49 spacing = spacing == "large" ? "gap-4" : spacing; 50 51 string layout = Model.Item.GetRawValueString("Layout", "grid"); 52 } 53 54 @* Get images from selected categories or get all images *@ 55 @if (totalImages != 0 && images.Count() != 0) 56 { 57 string theme = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("Theme")) ? " theme " + Model.Item.GetRawValueString("Theme").Replace(" ", "").Trim().ToLower() : ""; 58 59 if (layout != "custom-slider") 60 { 61 62 @* Show the gallery on large screens *@ 63 <div class="d-none d-lg-block h-100 @theme"> 64 <div class="grid @spacing"> 65 @{ 66 int imageNumber = 0; 67 68 foreach (MediaViewModel asset in images) 69 { 70 var assetName = asset.Value.ToLower(); 71 72 if (assetName.Contains(".jpg") || assetName.Contains(".webp") || assetName.Contains(".png") || assetName.Contains(".gif")) 73 { 74 string colClass = totalImages > 1 ? "g-col-lg-6" : "g-col-12"; 75 colClass = layout == "full-first" && imageNumber == 0 ? "g-col-12" : colClass; 76 colClass = layout == "full-last" && imageNumber == (totalImages - 1) ? "g-col-12" : colClass; 77 colClass = layout == "advanced-grid" && imageNumber > 1 ? "g-col-4" : colClass; 78 79 colClass = layout == "advanced-grid" && totalImages == 1 ? "g-col-12" : colClass; 80 colClass = layout == "advanced-grid" && totalImages == 3 && imageNumber == 2 ? "g-col-12" : colClass; 81 colClass = layout == "advanced-grid" && totalImages == 4 && imageNumber == 2 ? "g-col-6" : colClass; 82 colClass = layout == "advanced-grid" && totalImages == 4 && imageNumber == 3 ? "g-col-6" : colClass; 83 colClass = layout == "advanced-grid" && totalImages == 6 && imageNumber == 5 ? "g-col-12" : colClass; 84 colClass = layout == "advanced-grid" && totalImages == 7 && imageNumber == 5 ? "g-col-6" : colClass; 85 colClass = layout == "advanced-grid" && totalImages == 7 && imageNumber == 6 ? "g-col-6" : colClass; 86 colClass = layout == "advanced-grid" && totalImages == 9 && imageNumber == 8 ? "g-col-12" : colClass; 87 88 <div class="@colClass"> 89 @RenderImage(asset, product, imageNumber) 90 </div> 91 92 imageNumber++; 93 } 94 } 95 } 96 </div> 97 </div> 98 99 } 100 101 @* Modal *@ 102 <div class="modal fade" id="modal_@Model.ID" tabindex="-1" aria-labelledby="productDetailsGalleryModalTitle" aria-hidden="true"> 103 <div class="modal-dialog modal-dialog-centered modal-xl"> 104 <div class="modal-content"> 105 <div class="modal-header visually-hidden"> 106 <h5 class="modal-title" id="productDetailsGalleryModalTitle">@Translate("Full image")</h5> 107 </div> 108 <div class="modal-body"> 109 <div id="FullImages_@Model.ID" class="d-flex align-items-center justify-content-center"> 110 @foreach (MediaViewModel asset in images) 111 { 112 var assetName = asset.Value.ToLower(); 113 if (assetName.Contains(".jpg") || assetName.Contains(".webp") || assetName.Contains(".png") || assetName.Contains(".gif")) 114 { 115 string imagePath = !string.IsNullOrEmpty(asset.Value) ? asset.Value : product.DefaultImage.Value; 116 var parms = new Dictionary<string, object>(); 117 parms.Add("columns", Model.GridRowColumnCount); 118 parms.Add("cssClass", "mw-100 mh-100"); 119 <span class="d-flex align-items-center justify-content-center overflow-hidden h-100"> 120 @RenderPartial("Components/Image.cshtml", new FileViewModel { Path = imagePath }, parms) 121 </span> 122 } 123 } 124 </div> 125 <script type="module"> 126 var sliderFull_@(Model.ID) = tns({ 127 container: '#FullImages_@Model.ID', 128 items: 1, 129 gutter: 16, 130 mouseDrag: true, 131 touch: true, 132 arrowKeys: true, 133 nav: false, 134 loop: false, 135 speed: 10, 136 controls: false, 137 swipeAngle: 30, 138 preventScrollOnTouch: 'auto' 139 }); 140 141 if (document.getElementById('modal_@Model.ID')) { 142 document.getElementById('modal_@Model.ID').addEventListener('show.bs.modal', function (event) { 143 var slideNumber = event.relatedTarget.getAttribute("data-image-number"); 144 sliderFull_@(Model.ID).goTo(slideNumber); 145 }); 146 } 147 </script> 148 </div> 149 </div> 150 </div> 151 </div> 152 153 154 155 @* Show the thumbs on small screens *@ 156 string defaultSliderClass = "d-block d-lg-none mini-product-image-slider mx-lg-0" + theme; 157 string customSliderClass = "d-block d-lg-flex flex-lg-row mini-product-image-slider mx-lg-0" + theme; 158 string sliderClass = layout == "custom-slider" ? @customSliderClass : @defaultSliderClass; 159 <div class="@sliderClass"> 160 <div class="custom-slider d-lg-flex flex-lg-column flex-lg-fill border me-lg-2"> 161 <div id="SmallScreenImages_@Model.ID"> 162 @{ 163 var smallImageNumber = 0; 164 165 foreach (MediaViewModel asset in images) 166 { 167 var assetName = asset.Value.ToLower(); 168 169 if (assetName.Contains(".jpg") || assetName.Contains(".webp") || assetName.Contains(".png") || assetName.Contains(".gif")) 170 { 171 @RenderImage(asset, product, smallImageNumber, "small") 172 smallImageNumber++; 173 } 174 } 175 } 176 </div> 177 </div> 178 179 180 @{ 181 if (images.Count() > 1) 182 { 183 <div id="SmallScreenImagesThumbnails_@Model.ID" class="custom-thumbnails tns-nav-thumbnails grid gap-2 my-3 m-lg-0 d-lg-flex flex-lg-column h-100"> 184 @{ 185 foreach (MediaViewModel asset in images) { 186 var assetName = asset.Value.ToLower(); 187 if (assetName.Contains(".jpg") || assetName.Contains(".webp") || assetName.Contains(".png") || assetName.Contains(".gif")) { 188 189 string imagePath = Dynamicweb.Context.Current.Server.UrlEncode(assetName); 190 string imagePathThumb = $"/Admin/Public/GetImage.ashx?image={imagePath}&width=160&format=webp"; 191 192 <div class="tns-nav-thumbnail-item ratio ratio-4x3 border outline-none" style="width:80px;"><img src="@imagePathThumb" class="p-2" style="object-fit: cover;"></div> 193 } 194 } 195 } 196 </div> 197 } 198 } 199 200 @* Tiny slider *@ 201 <script type="module"> 202 var slider_@Model.ID = tns({ 203 container: '#SmallScreenImages_@Model.ID', 204 items: 1, 205 gutter: 16, 206 mouseDrag: true, 207 touch: true, 208 arrowKeys: true, 209 nav: true, 210 navContainer: "#SmallScreenImagesThumbnails_@Model.ID", 211 navAsThumbnails: true, 212 loop: false, 213 controls: false, 214 swipeAngle: 30, 215 preventScrollOnTouch: 'auto', 216 autoHeight: false, 217 }); 218 </script> 219 </div> 220 } 221 222 @helper RenderImage(MediaViewModel asset, ProductViewModel product, int number, string screenSize = "large") { 223 string layout = Model.Item.GetRawValueString("Layout", "grid"); 224 string padding = ""; 225 string theme = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("ImageTheme")) ? " theme " + Model.Item.GetRawValueString("ImageTheme").Replace(" ", "").Trim().ToLower() : ""; 226 227 if (theme != "") 228 { 229 padding = "p-3"; 230 } 231 232 string ratio = Model.Item.GetRawValueString("ImageAspectRatio", ""); 233 ratio = ratio != "0" ? ratio : ""; 234 string ratioCssClass = ratio != "" && ratio != "fill" ? " ratio" : ""; 235 string ratioVariable = ratio != "" && ratio != "fill" ? "--bs-aspect-ratio: " + ratio : ""; 236 ratioCssClass = ratio != "" && ratio == "fill" && screenSize == "small" ? " ratio" : ratioCssClass; 237 ratioVariable = ratio != "" && ratio == "fill" && screenSize == "small" ? "--bs-aspect-ratio: 66%" : ratioVariable; 238 string fillClass = ratio == "fill" ? " h-100" : ""; 239 240 string imagePath = !string.IsNullOrEmpty(asset.Value) ? asset.Value : product.DefaultImage.Value; 241 string imageLinkPath = Dynamicweb.Context.Current.Server.UrlEncode(imagePath); 242 string productName = product.Name; 243 244 var parms = new Dictionary<string, object>(); 245 parms.Add("alt", product.Name); 246 parms.Add("itemprop", "image"); 247 parms.Add("columns", Model.GridRowColumnCount); 248 249 if (ratio == "fill" && layout != "grid") { 250 parms.Add("cssClass", "w-100 h-100 image-zoom-lg"); 251 } 252 else 253 { 254 parms.Add("cssClass", "mw-100 mh-100"); 255 } 256 257 258 <div class="h-100 @(padding)@(theme)"> 259 <a href="@imageLinkPath" class="d-block h-100 @(ratioCssClass)@(fillClass)" data-bs-toggle="modal" data-bs-target="#modal_@Model.ID" data-image-number="@number"> 260 <span class="d-flex align-items-center justify-content-center overflow-hidden h-100"> 261 @RenderPartial("Components/Image.cshtml", new FileViewModel { Path = imagePath }, parms) 262 </span> 263 </a> 264 </div> 265 } 266
Error executing template "Designs/Swift/Paragraph/Swift_RelatedProducts.cshtml"
System.ArgumentNullException: Value cannot be null.
Parameter name: source
   at System.Linq.Enumerable.SelectMany[TSource,TResult](IEnumerable`1 source, Func`2 selector)
   at Dynamicweb.Ecommerce.ProductCatalog.ProductViewModelExtensions.GetRelatedProducts(ProductViewModel product)
   at CompiledRazorTemplates.Dynamic.RazorEngine_e2713ebadb07487ba286d35b71912741.Execute() in D:\dynamicweb.net\Solutions\scanoffice.cloud.dynamicweb-cms.com\Files\Templates\Designs\Swift\Paragraph\Swift_RelatedProducts.cshtml:line 87
   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 4 @{ 5 bool isVisualEditor = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString.Get("VisualEdit")) ? Convert.ToBoolean(Dynamicweb.Context.Current.Request.QueryString.Get("VisualEdit")) : false; 6 7 bool productViewModelFound = false; 8 ProductViewModel product = new ProductViewModel(); 9 10 if (Dynamicweb.Context.Current.Items.Contains("ProductDetails")) 11 { 12 productViewModelFound = true; 13 product = (ProductViewModel)Dynamicweb.Context.Current.Items["ProductDetails"]; 14 } 15 16 string titleFontSize = Model.Item.GetRawValueString("TitleFontSize", "h3"); 17 string subtitleFontSize = Model.Item.GetRawValueString("SubtitleFontSize", "fs-5"); 18 19 string buttonStyle = Model.Item.GetRawValueString("ButtonStyle", ""); 20 buttonStyle = buttonStyle == "primary" ? " btn-primary" : buttonStyle; 21 buttonStyle = buttonStyle == "secondary" ? " btn-secondary" : buttonStyle; 22 23 string generalTheme = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("GeneralTheme")) ? " theme " + Model.Item.GetRawValueString("GeneralTheme").Replace(" ", "").Trim().ToLower() : ""; 24 string theme = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("Theme")) ? " theme " + Model.Item.GetRawValueString("Theme").Replace(" ", "").Trim().ToLower() : ""; 25 string imageTheme = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("ImageTheme")) ? " theme " + Model.Item.GetRawValueString("ImageTheme").Replace(" ", "").Trim().ToLower() : ""; 26 27 string detailPageId = Model.Item.GetLink("ProductDetailsPage") != null ? Model.Item.GetLink("ProductDetailsPage").PageId.ToString() : ""; 28 string productPageByNavigationTag = GetPageIdByNavigationTag("ProductDetailPage") != 0 ? GetPageIdByNavigationTag("ProductDetailPage").ToString() : ""; 29 detailPageId = detailPageId == "" ? productPageByNavigationTag : detailPageId; 30 31 string pageId = Model.Item.GetLink("ProductSliderServicePage") != null ? Model.Item.GetLink("ProductSliderServicePage").PageId.ToString() : ""; 32 string servicePageByNavigationTag = GetPageIdByNavigationTag("ProductSliderService") != 0 ? GetPageIdByNavigationTag("ProductSliderService").ToString() : ""; 33 pageId = pageId == "" ? servicePageByNavigationTag : pageId; 34 35 string url = "/Default.aspx?ID=" + pageId; 36 if (!url.Contains("LayoutTemplate")) { 37 url += url.Contains("?") ? "&LayoutTemplate=Designs/Swift/Swift_PageClean.cshtml" : "?LayoutTemplate=Designs/Swift/Swift_PageClean.cshtml"; 38 } 39 if (isVisualEditor) { 40 url += "&VisualEdit=True"; 41 } 42 43 string relationType = Model.Item.GetRawValueString("RelationType", "trending"); 44 45 //If products is added through the trending groups selector 46 IList<ProductGroupViewModel> groupsToRelateToTrending = Model.Item.GetValue<IList<ProductGroupViewModel>>("GroupsToRelateToTrending"); 47 IList<ProductGroupViewModel> groupsToRelateToMostSold = Model.Item.GetValue<IList<ProductGroupViewModel>>("GroupsToRelateToMostSold"); 48 IList<string> relateFromGroupIds = new List<string>{}; 49 50 if (groupsToRelateToTrending != null && relationType == "trending") { 51 foreach (var fromGroup in groupsToRelateToTrending) 52 { 53 relateFromGroupIds.Add(fromGroup.Id); 54 } 55 } 56 57 if (groupsToRelateToMostSold != null && relationType == "most-sold") { 58 foreach (var fromGroup in groupsToRelateToMostSold) 59 { 60 relateFromGroupIds.Add(fromGroup.Id); 61 } 62 } 63 64 //If products is added through the selector 65 ProductListViewModel productsToRelateTo = Model.Item.GetValue<ProductListViewModel>("ProductsToRelateTo"); 66 IList<string> relateFromProductIds = new List<string>{}; 67 68 if (productsToRelateTo != null) { 69 foreach (var fromProduct in productsToRelateTo.Products) 70 { 71 relateFromProductIds.Add(fromProduct.Id); 72 } 73 } 74 75 ProductListViewModel products = Model.Item.GetValue<ProductListViewModel>("Products"); 76 IList<string> selectedProductIds = new List<string>{}; 77 78 if (products != null) { 79 foreach (var productSelection in products.Products) 80 { 81 selectedProductIds.Add(productSelection.Id); 82 } 83 } 84 85 if (relationType == "selected" && products == null) 86 { 87 foreach(var pro in product.GetRelatedProducts()) 88 { 89 selectedProductIds.Add(pro.Id); 90 } 91 } 92 93 string groupIds = productViewModelFound ? product.PrimaryOrDefaultGroup.Id : string.Join(",", relateFromGroupIds); 94 string productIds = productViewModelFound ? product.Id : string.Join(",", relateFromProductIds); 95 string title = Model?.Item?.GetString("Title") != null ? Model.Item.GetString("Title") : Translate("Products"); 96 97 string linkParameters = ""; 98 linkParameters += "&GroupId=" + groupIds; 99 linkParameters += !string.IsNullOrEmpty(productIds) ? "&MainProductId=" + productIds : ""; 100 linkParameters += selectedProductIds.Count > 0 ? "&MainProductId=" + string.Join(",", selectedProductIds) : ""; 101 string productListPageId = Model.Item.GetLink("ProductListPage") != null ? Model.Item.GetLink("ProductListPage").PageId.ToString() : ""; 102 string productListPageByNavigationTag = GetPageIdByNavigationTag("Shop") != 0 ? GetPageIdByNavigationTag("Shop").ToString() : ""; 103 productListPageId = productListPageId == "" ? productListPageByNavigationTag : productListPageId; 104 string link = "/Default.aspx?ID=" + productListPageId + linkParameters; 105 } 106 107 <form method="post" action="@url" data-response-target-element="RelatedProducts_@Model.ID" data-preloader="inline" data-update-url="false" class="w-100 h-100 js-product-list"> 108 <input type="hidden" name="HideTitle" value="@Model.Item.GetString("HideTitle")" /> 109 @if (Model.Item.GetInt32("ProductsCount") != 0) 110 { 111 <input type="hidden" name="PageSize" value="@Model.Item.GetInt32("ProductsCount")" /> 112 } 113 @if (detailPageId != "") 114 { 115 <input type="hidden" name="ProductDetailsPage" value="@detailPageId" /> 116 } 117 @if (!Model.Item.GetBoolean("HideTitle")) 118 { 119 <input type="hidden" name="HeadingTitle" value="@title" /> 120 } 121 @if (!string.IsNullOrEmpty(Model.Item.GetString("Subtitle"))) 122 { 123 <input type="hidden" name="Subtitle" value="@Model.Item.GetString("Subtitle")" /> 124 } 125 126 <input type="hidden" name="Link" value="@link" /> 127 128 @if (!string.IsNullOrEmpty(Model.Item.GetString("LinkText"))) 129 { 130 <input type="hidden" name="LinkText" value="@Model.Item.GetString("LinkText")" /> 131 } 132 @if (!string.IsNullOrEmpty(Model.Item.GetString("ImageAspectRatio"))) 133 { 134 string ratio = Model.Item.GetRawValueString("ImageAspectRatio", ""); 135 ratio = ratio != "0" ? ratio : ""; 136 <input type="hidden" name="ImageAspectRatio" value="@ratio" /> 137 } 138 @if (!string.IsNullOrEmpty(Model.Item.GetString("Layout"))) 139 { 140 <input type="hidden" name="Layout" value="@Model.Item.GetRawValueString("Layout")" /> 141 } 142 @if (titleFontSize != "") 143 { 144 <input type="hidden" name="TitleFontSize" value="@titleFontSize" /> 145 } 146 @if (subtitleFontSize != "") 147 { 148 <input type="hidden" name="SubtitleFontSize" value="@subtitleFontSize" /> 149 } 150 @if (buttonStyle != "") 151 { 152 <input type="hidden" name="ButtonStyle" value="@buttonStyle" /> 153 } 154 @if (generalTheme != "") 155 { 156 <input type="hidden" name="GeneralTheme" value="@generalTheme" /> 157 } 158 @if (theme != "") 159 { 160 <input type="hidden" name="Theme" value="@theme" /> 161 } 162 @if (imageTheme != "") 163 { 164 <input type="hidden" name="ImageTheme" value="@imageTheme" /> 165 } 166 @if (!string.IsNullOrEmpty(Model.Item.GetString("ContentPadding"))) 167 { 168 string contentPadding = Model.Item.GetRawValueString("ContentPadding"); 169 <input type="hidden" name="ContentPadding" value="@contentPadding" /> 170 } 171 <input type="hidden" name="HideNavigationBar" value="@Model.Item.GetString("HideNavigationBar").ToLower()" /> 172 173 @* Types *@ 174 @if (relationType == "trending" || relationType == "most-sold" || 175 (relationType == "selected" && products == null && !product.GetRelatedProducts().Any())) 176 { 177 if (!string.IsNullOrEmpty(groupIds)) 178 { 179 <input type="hidden" name="GroupId" value="@groupIds" /> 180 <input type="hidden" name="SortBy" value="OrderCountGrowth" /> 181 } 182 } 183 @if (relationType == "most-sold") 184 { 185 <input type="hidden" name="SortBy" value="OrderCount" /> 186 } 187 @if (relationType == "frequently") 188 { 189 <input type="hidden" name="BoughtWithProductIds" value="[@productIds]" /> 190 } 191 @if (relationType == "selected") 192 { 193 productIds = string.Join(",", selectedProductIds); 194 <input type="hidden" name="MainProductID" value="@productIds" /> 195 } 196 197 <div id="RelatedProducts_@Model.ID" class="h-100"></div> 198 </form> 199 200 <script type="module"> 201 swift.ProductList.init(); 202 </script> 203