An error occurred while attaching module (Dynamicweb.Frontend.Content)

System.Data.SqlClient.SqlException (0x80131904): A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: Named Pipes Provider, error: 40 - Could not open a connection to SQL Server) ---> System.ComponentModel.Win32Exception (0x80004005): The system cannot find the file specified
   at System.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, UInt32 waitForMultipleObjectsTimeout, Boolean allowCreate, Boolean onlyOneCheckConnection, DbConnectionOptions userOptions, DbConnectionInternal& connection)
   at System.Data.ProviderBase.DbConnectionPool.TryGetConnection(DbConnection owningObject, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal& connection)
   at System.Data.ProviderBase.DbConnectionFactory.TryGetConnection(DbConnection owningConnection, TaskCompletionSource`1 retry, DbConnectionOptions userOptions, DbConnectionInternal oldConnection, DbConnectionInternal& connection)
   at System.Data.ProviderBase.DbConnectionInternal.TryOpenConnectionInternal(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource`1 retry, DbConnectionOptions userOptions)
   at System.Data.SqlClient.SqlConnection.TryOpenInner(TaskCompletionSource`1 retry)
   at System.Data.SqlClient.SqlConnection.TryOpen(TaskCompletionSource`1 retry)
   at System.Data.SqlClient.SqlConnection.Open()
   at Dynamicweb.Data.DatabaseConnectionProvider.CreateConnection(Boolean open)
   at Dynamicweb.Data.Database.CreateConnection()
   at Dynamicweb.Data.Database.CreateDataReader(String sql, IDbConnection connection, IDbTransaction transaction, Int32 commandTimeout, Dictionary`2 sqlParams)
   at Dynamicweb.Ecommerce.Prices.PriceDataBaseDependecy.GetPricesBySql(String sql)
   at Dynamicweb.Ecommerce.Prices.PriceDependencies.GetPriceCollection(String sql)
   at Dynamicweb.Ecommerce.Prices.PriceDependencies.GetPrices(String productId)
   at Dynamicweb.Ecommerce.ProductCatalog.ViewEngine.GetPrices(PriceViewModelSettings settings, IList`1 products, Boolean& pricesHasBeenPrepared, Object lock, Product product)
   at Dynamicweb.Ecommerce.ProductCatalog.ViewEngine.<>c__DisplayClass3_1.b__47()
   at Dynamicweb.Ecommerce.ProductCatalog.ViewModelPropertyFiller`1.Fill[S](T model, String propertyName, Func`1 source)
   at Dynamicweb.Ecommerce.ProductCatalog.ViewEngine.BulkCreateView(ProductViewModelSettings settings, Boolean isRecursive, IList`1 products)
   at Dynamicweb.Ecommerce.ProductCatalog.ViewEngine.CreateView(ProductViewModelSettings settings, Product product)
   at Dynamicweb.Ecommerce.ProductCatalog.ProductCatalogFrontend.RenderProduct(String productId, String variantId, String groupId, ProductCatalogSettings settings)
   at Dynamicweb.Ecommerce.ProductCatalog.ProductCatalogFrontend.GetContent()
   at Dynamicweb.Frontend.Content.GetModuleOutput(Paragraph paragraph, PageView pageview)
ClientConnectionId:00000000-0000-0000-0000-000000000000
Error Number:2,State:0,Class:20

Error executing template "/Designs/Swift/Paragraph/DS_ProductDetailsImage.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_e215ec1bceb149f18c8154a7a0248f27.Execute() in C:\inetpub\wwwroot\DWShop2023\Solutions\Swift_v1.21.0\Files\Templates\Designs\Swift\Paragraph\DS_ProductDetailsImage.cshtml:line 78
   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 6 @functions { 7 public ProductViewModel product { get; set; } = new ProductViewModel(); 8 public string galleryLayout { get; set; } 9 public string[] supportedImageFormats { get; set; } 10 public string[] supportedVideoFormats { get; set; } 11 public string[] supportedDocumentFormats { get; set; } 12 public string[] allSupportedFormats { get; set; } 13 14 public class RatioSettings { 15 public string Ratio { get; set; } 16 public string CssClass { get; set; } 17 public string CssVariable { get; set; } 18 public string Fill { get; set; } 19 } 20 21 public RatioSettings GetRatioSettings(string size = "desktop") { 22 var ratioSettings = new RatioSettings(); 23 24 string ratio = Model.Item.GetRawValueString("ImageAspectRatio", ""); 25 ratio = ratio != "0" ? ratio : ""; 26 string cssClass = ratio != "" && ratio != "fill" ? " ratio" : ""; 27 string cssVariable = ratio != "" && ratio != "fill" ? "--bs-aspect-ratio: " + ratio : ""; 28 cssClass = ratio == "fill" && size == "mobile" ? " ratio" : cssClass; 29 cssVariable = ratio == "fill" && size == "mobile" ? "--bs-aspect-ratio: 66%" : cssVariable; 30 31 ratioSettings.Ratio = ratio; 32 ratioSettings.CssClass = cssClass; 33 ratioSettings.CssVariable = cssVariable; 34 ratioSettings.Fill = ratio == "fill" ? " h-100" : ""; 35 36 return ratioSettings; 37 } 38 39 public string GetArrowsColor() 40 { 41 var invertColor = Model.Item.GetBoolean("InvertModalArrowsColor"); 42 var arrowsColor = invertColor ? " carousel-dark" : string.Empty; 43 return arrowsColor; 44 } 45 } 46 47 @{ 48 ProductViewModel product = null; 49 if (Dynamicweb.Context.Current.Items.Contains("ProductDetails")) 50 { 51 product = (ProductViewModel)Dynamicweb.Context.Current.Items["ProductDetails"]; 52 } 53 else if (Pageview.Item["DummyProduct"] != null) 54 { 55 var pageViewModel = Dynamicweb.Frontend.ContentViewModelFactory.CreatePageInfoViewModel(Pageview.Page); 56 ProductListViewModel productList = pageViewModel.Item.GetValue("DummyProduct") != null ? pageViewModel.Item.GetValue("DummyProduct") as ProductListViewModel : new ProductListViewModel(); 57 58 if (productList?.Products is object) 59 { 60 product = productList.Products[0]; 61 } 62 } 63 } 64 65 @if (product is object) { 66 @* Supported formats *@ 67 supportedImageFormats = new string[] { ".jpg", ".jpeg", ".webp", ".png", ".gif", ".bmp", ".tiff" }; 68 supportedVideoFormats = new string[] { "youtu.be", "youtube", "vimeo", ".mp4", ".webm" }; 69 supportedDocumentFormats = new string[] { ".pdf", ".docx", ".xlsx", ".ppt", "pptx" }; 70 allSupportedFormats = supportedImageFormats.Concat(supportedVideoFormats).Concat(supportedDocumentFormats).ToArray(); 71 72 @* Collect the assets *@ 73 var selectedAssetCategories = Model.Item.GetRawValueString("ImageAssets").Split(',').ToList(); 74 bool includeImagePatternImages = Model.Item.GetBoolean("ImagePatternImages"); 75 76 @* Needed image data collection to support both DefaultImage, ImagePatterns and Image Assets *@ 77 string defaultImage = product.DefaultImage != null ? product.DefaultImage.Value : ""; 78 IEnumerable<MediaViewModel> assetsImages = product.AssetCategories.Where(x => selectedAssetCategories.Contains(x.SystemName)).SelectMany(x => x.Assets); 79 assetsImages = assetsImages.OrderByDescending(x => x.Value.Equals(defaultImage)); 80 IEnumerable<MediaViewModel> assetsList = new MediaViewModel[]{}; 81 assetsList = assetsList.Union(assetsImages); 82 assetsList = includeImagePatternImages ? assetsList.Union(product.ImagePatternImages) : assetsList; 83 assetsList = includeImagePatternImages && assetsList.Count() == 0 ? assetsList.Append(product.DefaultImage) : assetsList; 84 85 bool defaultImageFallback = Model.Item.GetBoolean("DefaultImageFallback"); 86 bool showOnlyPrimaryImage = Model.Item.GetBoolean("ShowOnlyPrimaryImage"); 87 88 int totalAssets = 0; 89 if (showOnlyPrimaryImage == false) { 90 foreach (MediaViewModel asset in assetsList) { 91 var assetValue = asset.Value.ToLower(); 92 foreach (string format in allSupportedFormats) { 93 if (assetValue.Contains(format) ) { 94 totalAssets++; 95 } 96 } 97 } 98 } 99 100 if((totalAssets == 0 && product.DefaultImage != null && selectedAssetCategories.Count() == 0) || (showOnlyPrimaryImage == true && product.DefaultImage != null) || totalAssets == 0 && defaultImageFallback) 101 { 102 assetsList = new List<MediaViewModel>(){ product.DefaultImage }; 103 totalAssets = 1; 104 } 105 106 107 @* Theme settings *@ 108 string theme = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("Theme")) ? " theme " + Model.Item.GetRawValueString("Theme").Replace(" ", "").Trim().ToLower() : ""; 109 110 var badgeParms = new Dictionary<string, object>(); 111 badgeParms.Add("size", "h5"); 112 badgeParms.Add("saleBadgeType", Model.Item.GetRawValue("SaleBadgeType")); 113 badgeParms.Add("saleBadgeCssClassName", Model.Item.GetRawValue("SaleBadgeDesign")); 114 badgeParms.Add("newBadgeCssClassName", Model.Item.GetRawValue("NewBadgeDesign")); 115 badgeParms.Add("newPublicationDays", Model.Item.GetInt32("NewPublicationDays")); 116 badgeParms.Add("campaignBadgesValues", Model.Item.GetRawValueString("CampaignBadges")); 117 118 bool saleBadgeEnabled = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("SaleBadgeDesign")) && Model.Item.GetRawValueString("SaleBadgeDesign") != "none" ? true : false; 119 bool newBadgeEnabled = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("NewBadgeDesign")) && Model.Item.GetRawValueString("NewBadgeDesign") != "none" ? true : false; 120 DateTime createdDate = product.Created.Value; 121 bool showBadges = saleBadgeEnabled && product.Discount.Price != 0 ? true : false; 122 showBadges = (newBadgeEnabled && Model.Item.GetInt32("NewPublicationDays") == 0) || (newBadgeEnabled && (createdDate.AddDays(Model.Item.GetInt32("NewPublicationDays")) > DateTime.Now)) ? true : showBadges; 123 showBadges = !string.IsNullOrEmpty(Model.Item.GetRawValueString("CampaignBadges")) ? true : showBadges; 124 125 @* Get assets from selected categories or get all assets *@ 126 if (totalAssets != 0) { 127 int assetNumber = 0; 128 int thumbnailNumber = 0; 129 int modalAssetNumber = 0; 130 131 <div class="h-100@(theme) position-relative item_@Model.Item.SystemName.ToLower() Product_ImageAll"> 132 <div id="SmallScreenImages_@Model.ID" class="carousel@(GetArrowsColor()) Product_ImageLarge" data-bs-ride="carousel"> 133 <div class="carousel-inner h-100"> 134 @foreach (MediaViewModel asset in assetsList) { 135 var assetValue = asset.Value.ToLower(); 136 foreach (string format in allSupportedFormats) { 137 if (assetValue.Contains(format)) { 138 string activeSlide = assetNumber == 0 ? "active" : ""; 139 140 <div class="carousel-item @activeSlide" data-bs-interval="99999"> 141 @{@RenderAsset(asset, assetNumber, "mobile")} 142 </div> 143 assetNumber++; 144 } 145 } 146 } 147 </div> 148 </div> 149 150 @if (totalAssets > 1) { 151 <div id="SmallScreenImagesThumbnails_@Model.ID" class="grid grid-10 gap-2 overflow-x-auto my-3 Product_ImageThumbs"> 152 @foreach (MediaViewModel asset in assetsList) { 153 var assetValue = asset.Value; 154 foreach (string format in allSupportedFormats) { 155 if (assetValue.Contains(format)) { 156 string imagePath = Dynamicweb.Context.Current.Server.UrlEncode(assetValue); 157 imagePath = assetValue.Contains("youtu.be") || assetValue.Contains("youtube") ? "https://img.youtube.com/vi/" + assetValue.Substring(assetValue.LastIndexOf('/') + 1) + "/mqdefault.jpg" : imagePath; 158 string imagePathThumb = !imagePath.Contains("youtube") && !imagePath.Contains(".mp4") ? $"/Admin/Public/GetImage.ashx?image={imagePath}&width=180&format=webp" : imagePath; 159 string iconPath = "/Files/Templates/Designs/Swift/Assets/icons/"; 160 161 string videoId = assetValue.Substring(assetValue.LastIndexOf('/') + 1); 162 string vimeoJsClass = assetValue.Contains("vimeo") ? "js-vimeo-video-thumbnail" : ""; 163 164 bool isDocument = false; 165 foreach (string documentFormat in supportedDocumentFormats) { 166 if (assetValue.Contains(documentFormat)) { 167 isDocument = true; 168 } 169 } 170 171 string assetName = asset.Name; 172 assetName += !string.IsNullOrEmpty(asset.Keywords) ? " " + asset.Keywords : ""; 173 string assetTitle = !string.IsNullOrEmpty(asset.DisplayName) ? "title=\"" + asset.DisplayName + "\"" : ""; 174 175 if (!isDocument) { 176 RatioSettings ratioSettings = GetRatioSettings("desktop"); 177 178 <div class="outline-none @(ratioSettings.CssClass)" style="@(ratioSettings.CssVariable); cursor: pointer" data-bs-target="#SmallScreenImages_@Model.ID" data-bs-slide-to="@thumbnailNumber"> 179 <div class="d-flex align-items-center justify-content-center overflow-hidden position-absolute h-100"> 180 @foreach (string videoFormat in supportedVideoFormats) { //Videos 181 if (assetValue.Contains(videoFormat)) { 182 <div class="icon-3 position-absolute text-light" style="z-index: 1">@ReadFile(iconPath + "play-circle.svg")</div> 183 } 184 } 185 </div> 186 @if (!imagePathThumb.Contains(".mp4")) { 187 <img src="@imagePathThumb" alt="@assetName" @assetTitle class="p-0 p-lg-1 @vimeoJsClass w-100 h-100" style="object-fit: contain" data-video-id="@videoId"> 188 } else { 189 string videoType = Path.GetExtension(asset.Value).ToLower(); 190 191 <video preload="auto" class="h-100 w-100" style="object-fit: contain;"> 192 <source src="@imagePathThumb" type="video/@videoType.Replace(".", "")"> 193 </video> 194 } 195 </div> 196 } else { 197 <a href="@assetValue" class="ratio ratio-4x3 border outline-none" style="cursor: pointer" download title="@asset.Value"> 198 @if (asset.Value.Contains(".pdf")) { 199 <div class="d-flex align-items-center justify-content-center overflow-hidden h-100"> 200 <div class="icon-3 position-absolute text-light" style="z-index: 1">@ReadFile(iconPath + "download.svg")</div> 201 </div> 202 <img src="@imagePathThumb" alt="@assetName" @assetTitle class="p-0 p-lg-1 mw-100 mh-100" style="object-fit: cover;"> 203 } else { 204 <div class="d-flex align-items-center justify-content-center overflow-hidden h-100"> 205 <div class="icon-3 position-absolute" style="z-index: 1">@ReadFile(iconPath + "file-text.svg")</div> 206 </div> 207 } 208 </a> 209 } 210 211 thumbnailNumber++; 212 } 213 } 214 } 215 </div> 216 } 217 218 @if (showBadges) { 219 <div class="position-absolute top-0 left-0 p-2 p-lg-3"> 220 @RenderPartial("Components/EcommerceBadge.cshtml", product, badgeParms) 221 </div> 222 } 223 </div> 224 225 @* Modal with slides *@ 226 <div class="modal fade swift_products-details-images-modal" id="modal_@Model.ID" tabindex="-1" aria-labelledby="productDetailsGalleryModalTitle_@Model.ID" aria-hidden="true"> 227 <div class="modal-dialog modal-dialog-centered modal-xl"> 228 <div class="modal-content"> 229 <div class="modal-header visually-hidden"> 230 <h5 class="modal-title" id="productDetailsGalleryModalTitle_@Model.ID">@product.Title</h5> 231 <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> 232 </div> 233 <div class="modal-body p-2 p-lg-3 h-100"> 234 <div id="ModalCarousel_@Model.ID" class="carousel@(GetArrowsColor()) h-100" data-bs-ride="carousel"> 235 <div class="carousel-inner h-100"> 236 @foreach (MediaViewModel asset in assetsList) { 237 var assetValue = !string.IsNullOrEmpty(asset.Value) ? asset.Value : product.DefaultImage.Value; 238 foreach (string format in supportedImageFormats.Concat(supportedVideoFormats).ToArray()) { 239 if (assetValue.Contains(format) ) { 240 string imagePath = assetValue; 241 string activeSlide = modalAssetNumber == 0 ? "active" : ""; 242 243 var parms = new Dictionary<string, object>(); 244 parms.Add("cssClass", "d-block mw-100 mh-100 m-auto"); 245 parms.Add("fullwidth", true); 246 parms.Add("columns", Model.GridRowColumnCount); 247 248 <div class="carousel-item @activeSlide h-100" data-bs-interval="99999"> 249 @foreach (string imageFormat in supportedImageFormats) { //Images 250 if (assetValue.Contains(imageFormat)) { 251 @RenderPartial("Components/Prod_Image.cshtml", new FileViewModel { Path = imagePath }, parms) 252 } 253 } 254 255 @foreach (string videoFormat in supportedVideoFormats) { //Videos 256 if (assetValue.Contains(videoFormat)) { 257 {@RenderVideoPlayer(asset, "modal")} 258 } 259 } 260 </div> 261 262 modalAssetNumber++; 263 } 264 } 265 } 266 <button class="carousel-control-prev" type="button" data-bs-target="#ModalCarousel_@Model.ID" data-bs-slide="prev"> 267 <span class="carousel-control-prev-icon" aria-hidden="true"></span> 268 <span class="visually-hidden">@Translate("Previous")</span> 269 </button> 270 <button class="carousel-control-next" type="button" data-bs-target="#ModalCarousel_@Model.ID" data-bs-slide="next"> 271 <span class="carousel-control-next-icon" aria-hidden="true"></span> 272 <span class="visually-hidden">@Translate("Next")</span> 273 </button> 274 </div> 275 </div> 276 </div> 277 </div> 278 </div> 279 </div> 280 } else if (Pageview.IsVisualEditorMode) { 281 RatioSettings ratioSettings = GetRatioSettings("desktop"); 282 283 <div class="h-100 @theme"> 284 <div class="d-block @(ratioSettings.CssClass)@(ratioSettings.Fill)" style="@(ratioSettings.CssVariable)"> 285 <img src="/Files/Images/missing_image.jpg" loading="lazy" decoding="async" class="mh-100 mw-100 ProductImgMain" style="object-fit: cover;"> 286 </div> 287 </div> 288 } 289 } else if (Pageview.IsVisualEditorMode) { 290 <div class="alert alert-dark m-0">@Translate("No products available")</div> 291 } 292 293 @helper RenderAsset(MediaViewModel asset, int assetNumber, string size = "desktop") { 294 string theme = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("ImageTheme")) ? " theme " + Model.Item.GetRawValueString("ImageTheme").Replace(" ", "").Trim().ToLower() : ""; 295 string assetValue = asset.Value; 296 297 <div class="h-100 @(theme)"> 298 @foreach (string format in supportedImageFormats) { //Images 299 if (assetValue.Contains(format)) { 300 {@RenderImage(asset, assetNumber, size)} 301 } 302 } 303 @foreach (string format in supportedVideoFormats) { //Videos 304 if (assetValue.Contains(format)) { 305 if (Model.Item.GetString("OpenVideoInModal") == "true") { 306 {@RenderVideoScreendump(asset, assetNumber, size)} 307 } else { 308 {@RenderVideoPlayer(asset, size)} 309 } 310 } 311 } 312 @foreach (string format in supportedDocumentFormats) { //Documents 313 if (assetValue.Contains(format)) { 314 {@RenderDocument(asset, assetNumber, size)} 315 } 316 } 317 </div> 318 } 319 320 @helper RenderImage(MediaViewModel asset, int number, string size = "desktop") { 321 if (product is object) 322 { 323 string productName = product.Name; 324 string imagePath = !string.IsNullOrEmpty(asset.Value) ? asset.Value : product.DefaultImage.Value; 325 string imageLinkPath = Dynamicweb.Context.Current.Server.UrlEncode(imagePath); 326 327 RatioSettings ratioSettings = GetRatioSettings(size); 328 329 var parms = new Dictionary<string, object>(); 330 parms.Add("alt", productName + asset.Keywords); 331 parms.Add("itemprop", "image"); 332 parms.Add("fullwidth", true); 333 parms.Add("columns", Model.GridRowColumnCount); 334 if (!string.IsNullOrEmpty(asset.DisplayName)) { 335 parms.Add("title", asset.DisplayName); 336 } 337 338 if (ratioSettings.Ratio == "fill" && galleryLayout != "grid") { 339 parms.Add("cssClass", "w-100 h-100 image-zoom-lg-l-hover"); 340 } else { 341 parms.Add("cssClass", "mw-100 mh-100 ProductImgMain"); 342 } 343 344 <a href="@imageLinkPath" class="d-block @(ratioSettings.CssClass)@(ratioSettings.Fill)" style="@(ratioSettings.CssVariable)" data-bs-toggle="modal" data-bs-target="#modal_@Model.ID"> 345 <div class="d-flex align-items-center justify-content-center overflow-hidden h-100" data-bs-target="#ModalCarousel_@Model.ID" data-bs-slide-to="@number"> 346 @RenderPartial("Components/Prod_Image.cshtml", new FileViewModel { Path = imagePath }, parms) 347 </div> 348 </a> 349 } 350 } 351 352 @helper RenderVideoScreendump(MediaViewModel asset, int number, string size = "desktop") { 353 if (product is object) 354 { 355 string iconPath = "/Files/Templates/Designs/Swift/Assets/icons/"; 356 357 string videoScreendumpPath = !string.IsNullOrEmpty(asset.Value) ? asset.Value : ""; 358 string videoId = videoScreendumpPath.Substring(videoScreendumpPath.LastIndexOf('/') + 1); 359 videoScreendumpPath = videoScreendumpPath.Contains("youtu.be") || videoScreendumpPath.Contains("youtube") ? "https://img.youtube.com/vi/" + videoId + "/maxresdefault.jpg" : videoScreendumpPath; 360 361 string vimeoJsClass = videoScreendumpPath.Contains("vimeo") ? "js-vimeo-video-thumbnail" : ""; 362 videoScreendumpPath = videoScreendumpPath.Contains("vimeo") ? "" : videoScreendumpPath; 363 364 string productName = product.Name; 365 productName += !string.IsNullOrEmpty(asset.Keywords) ? " " + asset.Keywords : ""; 366 string assetTitle = !string.IsNullOrEmpty(asset.DisplayName) ? "title=\"" + asset.DisplayName + "\"" : ""; 367 368 RatioSettings ratioSettings = GetRatioSettings(size); 369 370 <div class="d-block @(ratioSettings.CssClass)@(ratioSettings.Fill)" style="@(ratioSettings.CssVariable); cursor: pointer" data-bs-toggle="modal" data-bs-target="#modal_@Model.ID"> 371 <div class="d-flex align-items-center justify-content-center overflow-hidden h-100" data-bs-target="#ModalCarousel_@Model.ID" data-bs-slide-to="@number"> 372 <div class="icon-5 position-absolute" style="z-index: 1">@ReadFile(iconPath + "play-circle.svg")</div> 373 @if (!videoScreendumpPath.Contains(".mp4")) 374 { 375 <img src="@videoScreendumpPath" loading="lazy" decoding="async" alt="@productName" @assetTitle class="@vimeoJsClass mw-100 mh-100" data-video-id="@videoId" style="object-fit: cover;" onload="CheckIfVideoThumbnailExist(this)"> 376 } 377 else 378 { 379 string videoType = Path.GetExtension(asset.Value).ToLower(); 380 381 <video preload="auto" class="h-100 w-100" style="object-fit: contain;"> 382 <source src="@asset.Value" type="video/@videoType.Replace(".", "")"> 383 </video> 384 } 385 </div> 386 </div> 387 388 <script> 389 function CheckIfVideoThumbnailExist(image) { 390 if (image.width == 120) { 391 const lowQualityImage = "https://img.youtube.com/vi/@(videoId)/hqdefault.jpg" 392 image.src = lowQualityImage; 393 } 394 } 395 </script> 396 } 397 } 398 399 @helper RenderVideoPlayer(MediaViewModel asset, string size = "desktop") { 400 if (product is object) 401 { 402 string assetName = !string.IsNullOrEmpty(asset.DisplayName) ? asset.DisplayName : asset.Name; 403 string assetValue = asset.Value; 404 string videoId = asset.Value.Substring(asset.Value.LastIndexOf('/') + 1); 405 string type = assetValue.Contains("youtu.be") || assetValue.Contains("youtube") ? "youtube" : ""; 406 type = assetValue.Contains("vimeo") ? "vimeo" : type; 407 type = assetValue.Contains(".mp4") || assetValue.Contains(".webm") ? "selfhosted" : type; 408 409 string openInModal = Model.Item.GetString("OpenVideoInModal"); 410 bool autoPlay = Model.Item.GetBoolean("VideoAutoPlay"); 411 412 <div class="h-100" itemscope itemtype="https://schema.org/VideoObject"> 413 <span class="visually-hidden" itemprop="name">@assetName</span> 414 <span class="visually-hidden" itemprop="contentUrl">@asset.Value</span> 415 <span class="visually-hidden" itemprop="thumbnailUrl">@asset.Value</span> 416 417 @if (type != "selfhosted") 418 { 419 <div 420 id="player_@(Pageview.CurrentParagraph.ID)_@(videoId)_@size" 421 class="plyr__video-embed" 422 data-plyr-provider="@(type)" 423 data-plyr-embed-id="@videoId" 424 style="--plyr-color-main: var(--swift-foreground-color); height: 100%"> 425 </div> 426 427 <script type="module" src="/Files/Templates/Designs/Swift/Assets/js/plyr.js"></script> 428 429 <script type="module"> 430 var player = new Plyr('#player_@(Pageview.CurrentParagraph.ID)_@(videoId)_@size', { 431 type: 'video', 432 youtube: { 433 noCookie: true, 434 showinfo: 0 435 }, 436 fullscreen: { 437 enabled: true, 438 iosNative: true, 439 } 440 }); 441 442 @if (autoPlay && openInModal == "false") 443 { 444 <text> 445 player.config.autoplay = true; 446 player.config.muted = true; 447 player.config.volume = 0; 448 player.media.loop = true; 449 450 player.on('ready', function() { 451 if (player.config.autoplay === true) { 452 player.media.play(); 453 } 454 }); 455 </text> 456 } 457 458 @if (openInModal == "true") 459 { 460 <text> 461 var productDetailsGalleryModal = document.querySelector('#modal_@Model.ID') 462 productDetailsGalleryModal.addEventListener('hidden.bs.modal', function (event) { 463 player.media.pause(); 464 }) 465 </text> 466 } 467 </script> 468 } 469 else 470 { 471 string autoPlayAttributes = (autoPlay && openInModal == "false") ? "loop autoplay muted playsinline" : ""; 472 string videoType = Path.GetExtension(assetValue).ToLower(); 473 474 <video preload="auto" @autoPlayAttributes class="h-100 w-100" style="object-fit: cover;" controls> 475 <source src="@assetValue" type="video/@videoType.Replace(".", "")"> 476 </video> 477 } 478 </div> 479 } 480 } 481 482 @helper RenderDocument(MediaViewModel asset, int number, string size = "desktop") { 483 if (product is object) 484 { 485 string iconPath = "/Files/Templates/Designs/Swift/Assets/icons/"; 486 487 string productName = product.Name; 488 string imagePath = !string.IsNullOrEmpty(asset.Value) ? asset.Value : product.DefaultImage.Value; 489 string imageLinkPath = imagePath; 490 491 RatioSettings ratioSettings = GetRatioSettings(size); 492 493 var parms = new Dictionary<string, object>(); 494 parms.Add("alt", productName + asset.Keywords); 495 parms.Add("itemprop", "image"); 496 parms.Add("fullwidth", true); 497 parms.Add("columns", Model.GridRowColumnCount); 498 if (!string.IsNullOrEmpty(asset.DisplayName)) { 499 parms.Add("title", asset.DisplayName); 500 } 501 502 if (ratioSettings.Ratio == "fill" && galleryLayout != "grid") { 503 parms.Add("cssClass", "w-100 h-100 image-zoom-lg-l-hover"); 504 } else { 505 parms.Add("cssClass", "mw-100 mh-100"); 506 } 507 508 <a href="@imageLinkPath" class="d-block @(ratioSettings.CssClass)@(ratioSettings.Fill)" style="@(ratioSettings.CssVariable)" download alt="@Translate("Download")"> 509 <div class="d-flex align-items-center justify-content-center overflow-hidden h-100"> 510 <div class="icon-5 position-absolute" style="z-index: 1">@ReadFile(iconPath + "download.svg")</div> 511 @if (asset.Value.Contains(".pdf")) { 512 @RenderPartial("Components/Image.cshtml", new FileViewModel { Path = imagePath }, parms) 513 } 514 </div> 515 </a> 516 } 517 } 518

Error executing template "/Designs/Swift/Paragraph/DS_ProductPrice.cshtml"
System.NullReferenceException: Object reference not set to an instance of an object.
   at CompiledRazorTemplates.Dynamic.RazorEngine_b61d38ce11aa4b24b1e3dfe19b4c502b.Execute() in C:\inetpub\wwwroot\DWShop2023\Solutions\Swift_v1.21.0\Files\Templates\Designs\Swift\Paragraph\DS_ProductPrice.cshtml:line 82
   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 ProductViewModel product = null; 6 if (Dynamicweb.Context.Current.Items.Contains("ProductDetails")) 7 { 8 product = (ProductViewModel)Dynamicweb.Context.Current.Items["ProductDetails"]; 9 } 10 else if (Pageview.Item["DummyProduct"] != null) 11 { 12 var pageViewModel = Dynamicweb.Frontend.ContentViewModelFactory.CreatePageInfoViewModel(Pageview.Page); 13 ProductListViewModel productList = pageViewModel.Item.GetValue("DummyProduct") != null ? pageViewModel.Item.GetValue("DummyProduct") as ProductListViewModel : new ProductListViewModel(); 14 15 if (productList?.Products is object) 16 { 17 product = productList.Products[0]; 18 } 19 } 20 21 string anonymousUsersLimitations = Pageview.AreaSettings.GetRawValueString("AnonymousUsers", ""); 22 bool anonymousUser = Pageview.User == null; 23 bool isErpConnectionDown = !Dynamicweb.Core.Converter.ToBoolean(Dynamicweb.Context.Current.Items["IsWebServiceConnectionAvailable"]); 24 bool hidePrice = anonymousUsersLimitations.Contains("price") && anonymousUser || Pageview.AreaSettings.GetBoolean("ErpDownHidePrices") && isErpConnectionDown; 25 } 26 27 @if (product is object && !hidePrice) { 28 bool showInformativePrice = Model.Item.GetBoolean("ShowInformativePrice"); 29 string unitId = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form.Get("UnitId")) ? Dynamicweb.Context.Current.Request.Form.Get("UnitId") : string.Empty; 30 31 string priceFontSize = Model.Item.GetRawValueString("PriceSize", "fs-2"); 32 string horizontalAlign = Model.Item.GetRawValueString("HorizontalAlignment", ""); 33 string layout = Model.Item.GetRawValueString("Layout", "horizontal"); 34 string textAlign = horizontalAlign == "center" ? "text-center" : string.Empty; 35 textAlign = horizontalAlign == "end" ? "text-end" : textAlign; 36 37 horizontalAlign = horizontalAlign == "center" && layout == "horizontal" ? "justify-content-center" : horizontalAlign; 38 horizontalAlign = horizontalAlign == "end" && layout == "horizontal" ? "justify-content-end" : horizontalAlign; 39 horizontalAlign = horizontalAlign == "center" && layout == "vertical" ? "align-items-center" : horizontalAlign; 40 horizontalAlign = horizontalAlign == "end" && layout == "vertical" ? "align-items-end" : horizontalAlign; 41 42 string flexDirection = layout == "horizontal" ? string.Empty : "flex-column"; 43 string flexGap = layout == "horizontal" ? "gap-3" : string.Empty; 44 string order = layout == "horizontal" ? string.Empty : "order-2"; 45 string theme = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("Theme")) ? "theme " + Model.Item.GetRawValueString("Theme").Replace(" ", "").Trim().ToLower() : ""; 46 theme = GetViewParameter("theme") != null ? GetViewParameterString("theme") : theme; 47 48 string contentPadding = Model.Item.GetRawValueString("ContentPadding", ""); 49 contentPadding = contentPadding == "none" ? "p-0" : contentPadding; 50 contentPadding = contentPadding == "small" ? "p-1 px-md-2 py-md-1" : contentPadding; 51 contentPadding = contentPadding == "large" ? "p-2 px-md-3 py-md-2" : contentPadding; 52 53 string showPricesWithVat = Pageview.Area.EcomPricesWithVat.ToLower(); 54 bool neverShowVat = string.IsNullOrEmpty(showPricesWithVat); 55 56 string priceMin = ""; 57 string priceMax = ""; 58 59 string liveInfoClass = ""; 60 string productInfoFeed = ""; 61 bool isLazyLoadingForProductInfoEnabled = Dynamicweb.Core.Converter.ToBoolean(Dynamicweb.Context.Current.Items["IsLazyLoadingForProductInfoEnabled"]); 62 if (isLazyLoadingForProductInfoEnabled) 63 { 64 if (Dynamicweb.Context.Current.Items.Contains("ProductInfoFeed")) 65 { 66 productInfoFeed = Dynamicweb.Context.Current.Items["ProductInfoFeed"]?.ToString(); 67 if (!string.IsNullOrEmpty(productInfoFeed)) 68 { 69 productInfoFeed = $"data-product-info-feed=\"{productInfoFeed}\""; 70 } 71 } 72 liveInfoClass = "js-live-info"; 73 } 74 75 <div class="@textAlign @liveInfoClass item_@Model.Item.SystemName.ToLower()" data-product-id="@product.Id" data-variant-id="@product.VariantId" @productInfoFeed> 76 @if (showInformativePrice && product.PriceInformative.Price != 0) 77 { 78 <div class="opacity-50"> 79 <span>@Translate("RRP") </span> 80 <span class="text-decoration-line-through text-price">@product.PriceInformative.PriceFormatted</span> 81 </div> 82 } 83 <div class="@priceFontSize m-0 d-flex @flexDirection @flexGap @horizontalAlign" itemprop="offers" itemscope itemtype="https://schema.org/Offer"> 84 <span itemprop="priceCurrency" content="@product.Price.CurrencyCode" class="d-none"></span> 85 86 87 @if (showPricesWithVat == "false" && !neverShowVat) 88 { 89 if (isLazyLoadingForProductInfoEnabled && !Pageview.IsVisualEditorMode) 90 { 91 <span itemprop="price" content="" class="d-none"></span> 92 <span class="text-decoration-line-through js-text-decoration-line-through opacity-75 me-3 text-price js-text-price d-none" data-show-if="LiveProductInfo.product.Price.Price != LiveProductInfo.product.PriceBeforeDiscount.Price"></span> 93 } 94 else 95 { 96 string beforePrice = !string.IsNullOrEmpty(unitId) ? product.GetPrice(unitId).PriceBeforeDiscount.PriceWithoutVatFormatted : product.PriceBeforeDiscount.PriceWithoutVatFormatted; 97 98 <span itemprop="price" content="@product.Price.PriceWithoutVat" class="d-none"></span> 99 if (product.Price.Price != product.PriceBeforeDiscount.Price) 100 { 101 <span class="text-decoration-line-through opacity-75 @order">@beforePrice</span> 102 } 103 } 104 } 105 else 106 { 107 if (isLazyLoadingForProductInfoEnabled && !Pageview.IsVisualEditorMode) 108 { 109 <span itemprop="price" content="" class="d-none"></span> 110 <span class="text-decoration-line-through js-text-decoration-line-through opacity-75 me-3 text-price js-text-price d-none" data-show-if="LiveProductInfo.product.Price.Price != LiveProductInfo.product.PriceBeforeDiscount.Price"></span> 111 } 112 else 113 { 114 string beforePrice = !string.IsNullOrEmpty(unitId) ? product.GetPrice(unitId).PriceBeforeDiscount.PriceFormatted : product.PriceBeforeDiscount.PriceFormatted; 115 116 <span itemprop="price" content="@product.Price.Price" class="d-none"></span> 117 118 if (product.Price.Price != product.PriceBeforeDiscount.Price) 119 { 120 <span class="text-decoration-line-through opacity-75 @order"> 121 <span class="text-price">@beforePrice</span> 122 </span> 123 } 124 } 125 } 126 127 @if (showPricesWithVat == "false" && !neverShowVat) 128 { 129 if (isLazyLoadingForProductInfoEnabled && !Pageview.IsVisualEditorMode) 130 { 131 <span class="text-price js-text-price"> 132 <span class="spinner-border" role="status"></span> 133 </span> 134 } 135 else 136 { 137 string price = !string.IsNullOrEmpty(unitId) ? product.GetPrice(unitId).Price.PriceWithoutVatFormatted : product.Price.PriceWithoutVatFormatted; 138 139 if (product?.VariantInfo?.VariantInfo != null) 140 { 141 priceMin = product?.VariantInfo?.PriceMin?.PriceWithoutVatFormatted != null ? product.VariantInfo.PriceMin.PriceWithoutVatFormatted : ""; 142 priceMax = product?.VariantInfo?.PriceMax?.PriceWithoutVatFormatted != null ? product.VariantInfo.PriceMax.PriceWithoutVatFormatted : ""; 143 } 144 if (priceMin != priceMax) 145 { 146 price = priceMin + " - " + priceMax; 147 } 148 <span class="@theme @contentPadding"> 149 <span class="text-price">@price</span> 150 </span> 151 } 152 } 153 else 154 { 155 if (isLazyLoadingForProductInfoEnabled && !Pageview.IsVisualEditorMode) 156 { 157 <span class="text-price js-text-price"> 158 <span class="spinner-border" role="status"></span> 159 </span> 160 } 161 else 162 { 163 string price = !string.IsNullOrEmpty(unitId) ? product.GetPrice(unitId).Price.PriceFormatted : product.Price.PriceFormatted; 164 var priceinKN = product.Price.Price * 7.53450; 165 166 if (product?.VariantInfo?.VariantInfo != null) 167 { 168 priceMin = product?.VariantInfo?.PriceMin?.PriceFormatted != null ? product.VariantInfo.PriceMin.PriceFormatted : ""; 169 priceMax = product?.VariantInfo?.PriceMax?.PriceFormatted != null ? product.VariantInfo.PriceMax.PriceFormatted : ""; 170 } 171 if (priceMin != priceMax) 172 { 173 price = priceMin + " - " + priceMax; 174 } 175 <span class="@theme @contentPadding"> 176 <span class="text-price">@price</span> 177 @* @if(Pageview.Area.Culture.ToString() == "hr-HR") {<span class="priceinKN">(@priceinKN.ToString("N2") kn)</span> }*@ 178 </span> 179 } 180 } 181 182 @* Stock state for Schema.org, start *@ 183 @{ 184 Uri url = Dynamicweb.Context.Current.Request.Url; 185 } 186 187 <link itemprop="url" href="@url"> 188 189 @{ 190 bool IsNeverOutOfStock = product.NeverOutOfstock; 191 } 192 193 @if (IsNeverOutOfStock) 194 { 195 <span itemprop="availability" class="d-none">@Translate("Available in stock")</span> 196 } 197 else 198 { 199 if (product.StockLevel > 0) 200 { 201 <span itemprop="availability" class="d-none">InStock</span> 202 } 203 else 204 { 205 <span itemprop="availability" class="d-none">OutOfStock</span> 206 } 207 } 208 @* Stock state for Schema.org, stop *@ 209 210 </div> 211 212 @if (showPricesWithVat == "false" && !neverShowVat) 213 { 214 if (isLazyLoadingForProductInfoEnabled && !Pageview.IsVisualEditorMode) 215 { 216 <small class="opacity-85 fst-normal js-text-price-with-vat d-none" data-suffix="@Translate("Incl. VAT")"></small> 217 } 218 else 219 { 220 string price = !string.IsNullOrEmpty(unitId) ? product.GetPrice(unitId).Price.PriceWithVatFormatted : product.Price.PriceWithVatFormatted; 221 222 if (product?.VariantInfo?.VariantInfo != null) 223 { 224 priceMin = product?.VariantInfo?.PriceMin?.PriceWithVatFormatted != null ? product.VariantInfo.PriceMin.PriceWithVatFormatted : ""; 225 priceMax = product?.VariantInfo?.PriceMax?.PriceWithVatFormatted != null ? product.VariantInfo.PriceMax.PriceWithVatFormatted : ""; 226 } 227 if (priceMin != priceMax) 228 { 229 price = priceMin + " - " + priceMax; 230 } 231 <small class="opacity-85 fst-normal">@price @Translate("Incl. VAT")</small> 232 } 233 } 234 </div> 235 } 236 else if (Pageview.IsVisualEditorMode) 237 { 238 <div class="alert alert-dark m-0" role="alert"> 239 <span>@Translate("No products available")</span> 240 </div> 241 } 242
Error executing template "Designs/Swift/Paragraph/Swift_ProductVariantSelector.cshtml"
System.NullReferenceException: Object reference not set to an instance of an object.
   at Dynamicweb.Ecommerce.ProductCatalog.ProductViewModelExtensionMethods.VariantGroups(ProductViewModel productViewModel)
   at CompiledRazorTemplates.Dynamic.RazorEngine_126ace56929241ea958cab3d251de002.Execute() in C:\inetpub\wwwroot\DWShop2023\Solutions\Swift_v1.21.0\Files\Templates\Designs\Swift\Paragraph\Swift_ProductVariantSelector.cshtml:line 105
   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 System.Collections.Generic 3 @using System.Linq 4 @using Dynamicweb.Ecommerce.ProductCatalog 5 @using Dynamicweb.Ecommerce.Variants 6 7 @functions { 8 //Find contrast color (white, black) 9 public static string GetContrastColor(string hexString) 10 { 11 System.Drawing.Color bg = System.Drawing.ColorTranslator.FromHtml(hexString); 12 13 int nThreshold = 105; 14 int bgDelta = Convert.ToInt32((bg.R * 0.299) + (bg.G * 0.587) + 15 (bg.B * 0.114)); 16 17 string foreColor = (255 - bgDelta < nThreshold) ? "#333" : "#fff"; 18 return foreColor; 19 } 20 21 public string GetLayoutForVariantGroup(string variantGroupId) 22 { 23 string showVariantGroups = !string.IsNullOrEmpty(Model.Item.GetString("ShowVariantGroupOptions")) ? Model.Item.GetString("ShowVariantGroupOptions") : "all"; 24 string defaultVariantGroupLayout = Model.Item.GetRawValueString("DefaultVariantGroupLayout", "button"); 25 var selectedVariantGroupsList = !string.IsNullOrEmpty(Model.Item.GetRawValueString("VariantGroups")) ? Model.Item.GetItems("VariantGroups") : new List<Dynamicweb.Frontend.ItemViewModel>(); 26 27 if (showVariantGroups == "all" || selectedVariantGroupsList == null || !selectedVariantGroupsList.Any()) return defaultVariantGroupLayout; 28 29 foreach (var selectedVariantGroupListItem in selectedVariantGroupsList) 30 { 31 var variantGroups = selectedVariantGroupListItem.GetRawValueString("VariantGroups").Split(','); 32 if (variantGroups.Any(s => s.Equals(variantGroupId))) return selectedVariantGroupListItem.GetRawValueString("VariantGroupLayout"); 33 } 34 35 return defaultVariantGroupLayout; 36 } 37 38 //Collect all variant images 39 public static Dictionary<string, string> GetVariantImages(List<VariantInfoViewModel> variantInfo, Dictionary<string, string> list) 40 { 41 foreach (var variantGroup in variantInfo) 42 { 43 if (variantGroup.Image?.Value != null && !list.ContainsKey(variantGroup.OptionID)) 44 { 45 list.Add(variantGroup.OptionID, variantGroup.Image.Value); 46 } 47 48 if (variantGroup.VariantInfo != null) 49 { 50 GetVariantImages(variantGroup.VariantInfo, list); 51 } 52 } 53 54 return list; 55 } 56 57 private string GetDefaultOrVariantGroupValue(string variantGroupId, string itemField, string itemFieldDefaultValue, Dictionary<string, string> fieldValueMapping) 58 { 59 string horizontalTextAlign = Model.Item.GetRawValueString(itemField, itemFieldDefaultValue); 60 horizontalTextAlign = fieldValueMapping.ContainsKey(horizontalTextAlign) ? fieldValueMapping[horizontalTextAlign] : horizontalTextAlign; 61 62 // If no variantGroup (i.e. Visual Editor), return default value 63 if (string.IsNullOrEmpty(variantGroupId)) return horizontalTextAlign; 64 65 string showVariantGroups = Model.Item.GetString("ShowVariantGroupOptions", "all"); 66 var selectedVariantGroupsList = !string.IsNullOrEmpty(Model.Item.GetRawValueString("VariantGroups")) ? Model.Item.GetItems("VariantGroups") : new List<Dynamicweb.Frontend.ItemViewModel>(); 67 // If no exceptions or settings are all the same, return default value 68 if (showVariantGroups == "all" || selectedVariantGroupsList == null || !selectedVariantGroupsList.Any()) return horizontalTextAlign; 69 70 // Get specific value for variant group 71 foreach (var selectedVariantGroupListItem in selectedVariantGroupsList) 72 { 73 var variantGroups = selectedVariantGroupListItem.GetRawValueString("VariantGroups").Split(','); 74 if (!variantGroups.Any(s => s.Equals(variantGroupId))) continue; 75 76 horizontalTextAlign = selectedVariantGroupListItem.GetRawValueString(itemField, itemFieldDefaultValue); 77 horizontalTextAlign = fieldValueMapping.ContainsKey(horizontalTextAlign) ? fieldValueMapping[horizontalTextAlign] : horizontalTextAlign; 78 } 79 80 return horizontalTextAlign; 81 } 82 } 83 84 @{ 85 ProductViewModel product = null; 86 if (Dynamicweb.Context.Current.Items.Contains("ProductDetails")) 87 { 88 product = (ProductViewModel)Dynamicweb.Context.Current.Items["ProductDetails"]; 89 } 90 else if (Pageview.Item["DummyProduct"] != null) 91 { 92 var pageViewModel = Dynamicweb.Frontend.ContentViewModelFactory.CreatePageInfoViewModel(Pageview.Page); 93 ProductListViewModel productList = pageViewModel.Item.GetValue("DummyProduct") != null ? pageViewModel.Item.GetValue("DummyProduct") as ProductListViewModel : new ProductListViewModel(); 94 95 if (productList?.Products is object) 96 { 97 product = productList.Products[0]; 98 } 99 } 100 } 101 102 @if ((product is object)) 103 { 104 bool hideGroupHeaders = Model.Item.GetBoolean("HideGroupHeaders"); 105 var productVariantGroups = product.VariantGroups(); 106 107 if (productVariantGroups.Any()) 108 { 109 string[] variantId = product.VariantId.Split('.'); 110 int groupNumber = 1; 111 112 string baseUrl = $"Default.aspx?ID={GetPageIdByNavigationTag("Shop")}&GroupID={product.PrimaryOrDefaultGroup.Id}&ProductID={product.Id}"; 113 string variantUrl = ""; 114 if (!string.IsNullOrEmpty(product.VariantId)) 115 { 116 variantUrl = Dynamicweb.Frontend.SearchEngineFriendlyURLs.GetFriendlyUrl($"Default.aspx?ID={GetPageIdByNavigationTag("Shop")}&GroupID={product.PrimaryOrDefaultGroup.Id}&ProductID={product.Id}&VariantID={product.VariantId}"); 117 } 118 119 Dictionary<string, string> variantImages = new Dictionary<string, string>(); 120 variantImages = GetVariantImages(product.VariantInfo.VariantInfo, variantImages); 121 122 <form class="d-flex flex-column gap-2 js-variant-selector item_@Model.Item.SystemName.ToLower()" data-combinations="@string.Join(",", product.VariantCombinations())" data-base-url="@baseUrl" data-friendly-url="@variantUrl"> 123 @foreach (var variantGroup in productVariantGroups) 124 { 125 VariantGroupViewModel group = variantGroup; 126 string variantGroupLayout = GetLayoutForVariantGroup(variantGroup.Id); 127 string horizontalAlign = GetDefaultOrVariantGroupValue(variantGroup.Id, "HorizontalAlignment", "", new Dictionary<string, string> { { "center", "justify-content-center" }, { "end", "justify-content-end" } }); 128 string horizontalTextAlign = GetDefaultOrVariantGroupValue(variantGroup.Id, "HorizontalAlignment", "", new Dictionary<string, string> { { "center", "text-center" }, { "end", "text-end" } }); 129 130 <div> 131 @if (!hideGroupHeaders) 132 { 133 <h3 class="h6 @horizontalTextAlign">@group.Name</h3> 134 } 135 <div class="d-flex gap-2 @horizontalAlign flex-wrap js-variant-group" data-group-id="@groupNumber"> 136 @if (variantGroupLayout == "button") 137 { 138 foreach (var option in group.Options) 139 { 140 string active = variantId != null && variantId.Contains(option.Id) ? "active" : ""; 141 string buttonId = $"{product.Id}_{option.Id}_{Pageview.CurrentParagraph.ID}"; 142 string contrastColor = string.Empty; 143 string optionLayout = optionLayout = GetDefaultOrVariantGroupValue(variantGroup.Id, "ButtonLayout", "rounded-circle", new Dictionary<string, string> { { "round", "rounded-circle" }, { "square", "" } }); 144 var displayType = group.DisplayType; 145 146 switch (displayType) 147 { 148 case VariantGroupDisplayType.VariantColor: 149 contrastColor = GetContrastColor(option.Color); 150 <button type="button" class="btn colorbox @optionLayout d-inline-block variant-option border js-variant-option @active" style="background-color: @option.Color; --variantoption-check-color: @contrastColor" onclick="swift.VariantSelector.OptionClick(event)" data-variant-id="@option.Id" id="@buttonId"> 151 <span class="visually-hidden">@option.Color</span> 152 </button> 153 break; 154 case VariantGroupDisplayType.VariantImage: 155 string variantImage = string.Empty; 156 if (variantImages.TryGetValue(option.Id, out variantImage)) 157 { 158 <button type="button" class="btn p-0 d-inline-block @optionLayout variant-option js-variant-option @active" onclick="swift.VariantSelector.OptionClick(event)" data-variant-id="@option.Id" id="@(product.Id)_@(option.Id)_@Pageview.CurrentParagraph.ID"> 159 <img class="@optionLayout" src="/Admin/Public/GetImage.ashx?image=@(variantImage)&width=42&Format=WebP&Quality=70"> 160 </button> 161 } 162 else 163 { 164 <button type="button" class="btn btn-secondary d-inline-block variant-option js-variant-option @active" onclick="swift.VariantSelector.OptionClick(event)" data-variant-id="@option.Id" id="@(product.Id)_@(option.Id)_@Pageview.CurrentParagraph.ID"> 165 @option.Name 166 </button> 167 } 168 169 break; 170 case VariantGroupDisplayType.VariantName: 171 <button type="button" class="btn btn-secondary d-inline-block variant-option js-variant-option @active" onclick="swift.VariantSelector.OptionClick(event)" data-variant-id="@option.Id" id="@buttonId"> 172 @option.Name 173 </button> 174 break; 175 case VariantGroupDisplayType.VariantOptionImage: 176 <button type="button" class="btn p-0 d-inline-block @optionLayout variant-option js-variant-option @active" onclick="swift.VariantSelector.OptionClick(event)" data-variant-id="@option.Id" id="@(product.Id)_@(option.Id)_@Pageview.CurrentParagraph.ID"> 177 <img class="@optionLayout" src="/Admin/Public/GetImage.ashx?image=@(option.OptionImage.Value)&width=42&Format=WebP&Quality=70"> 178 </button> 179 break; 180 default: 181 if (!string.IsNullOrEmpty(option.Color)) 182 { 183 contrastColor = GetContrastColor(option.Color); 184 <button type="button" class="btn colorbox @optionLayout d-inline-block variant-option border js-variant-option @active" style="background-color: @option.Color; --variantoption-check-color: @contrastColor" onclick="swift.VariantSelector.OptionClick(event)" data-variant-id="@option.Id" id="@buttonId"> 185 <span class="visually-hidden">@option.Color</span> 186 </button> 187 } 188 else if (!string.IsNullOrEmpty(option.Color) && !string.IsNullOrEmpty(option.Image.Value)) 189 { 190 <button type="button" class="btn p-0 d-inline-block @optionLayout variant-option js-variant-option @active" onclick="swift.VariantSelector.OptionClick(event)" data-variant-id="@option.Id" id="@buttonId"> 191 <img src="/Admin/Public/GetImage.ashx?image=@(option.Image.Value)&width=42&Format=WebP&Quality=70"> 192 </button> 193 } 194 else 195 { 196 <button type="button" class="btn btn-secondary d-inline-block variant-option js-variant-option @active" onclick="swift.VariantSelector.OptionClick(event)" data-variant-id="@option.Id" id="@buttonId"> 197 @option.Name 198 </button> 199 } 200 break; 201 } 202 } 203 } 204 else 205 { 206 <select class="form-select" id="VariantDropdown_@variantGroup.Id" aria-label="@variantGroup.Name" onchange="swift.VariantSelector.OptionClick(event)"> 207 @if (string.IsNullOrEmpty(product.VariantId)) 208 { 209 <option value="" class="variant-option js-variant-option" data-variant-id="">@Translate("Nothing selected")</option> 210 } 211 212 @foreach (var option in variantGroup.Options) 213 { 214 string active = variantId != null && variantId.Contains(option.Id) ? "active" : ""; 215 var selected = variantId != null && variantId.Contains(option.Id) ? "selected" : ""; 216 var value = $"{product.Id}_{option.Id}"; 217 218 <option value="@(value)" class="variant-option js-variant-option @active" data-variant-id="@option.Id" id="@(value)_@(Pageview.CurrentParagraph.ID)" @selected>@option.Name</option> 219 } 220 </select> 221 } 222 </div> 223 </div> 224 225 226 groupNumber++; 227 } 228 </form> 229 230 <script type="module"> 231 swift.VariantSelector.init(); 232 </script> 233 } 234 else if (Pageview.IsVisualEditorMode) 235 { 236 string horizontalAlign = GetDefaultOrVariantGroupValue("", "HorizontalAlignment", "", new Dictionary<string, string> { { "center", "justify-content-center" }, { "end", "justify-content-end" } }); 237 string horizontalTextAlign = GetDefaultOrVariantGroupValue("", "HorizontalAlignment", "", new Dictionary<string, string> { { "center", "text-center" }, { "end", "text-end" } }); 238 239 <form class="d-flex flex-column js-variant-selector item_@Model.Item.SystemName.ToLower()" data-combinations="VO1,VO2,VO3,VO4"> 240 <div> 241 @if (!hideGroupHeaders) 242 { 243 <h3 class="h6 @horizontalTextAlign">@Translate("Sizes")</h3> 244 } 245 <div class="mb-3 @horizontalAlign js-variant-group" data-group-id="0"> 246 <button type="button" class="btn btn-secondary d-inline-block mb-2 variant-option js-variant-option" onclick="swift.VariantSelector.OptionClick(event)" data-variant-id="VO1" id="@(product.Id)_VO1_@Pageview.CurrentParagraph.ID">S</button> 247 <button type="button" class="btn btn-secondary d-inline-block mb-2 variant-option js-variant-option" onclick="swift.VariantSelector.OptionClick(event)" data-variant-id="VO2" id="@(product.Id)_VO2_@Pageview.CurrentParagraph.ID">M</button> 248 <button type="button" class="btn btn-secondary d-inline-block mb-2 variant-option js-variant-option" onclick="swift.VariantSelector.OptionClick(event)" data-variant-id="VO3" id="@(product.Id)_VO3_@Pageview.CurrentParagraph.ID">L</button> 249 <button type="button" class="btn btn-secondary d-inline-block mb-2 variant-option js-variant-option" onclick="swift.VariantSelector.OptionClick(event)" data-variant-id="VO4" id="@(product.Id)_VO4_@Pageview.CurrentParagraph.ID">XL</button> 250 </div> 251 </div> 252 </form> 253 254 <script type="module"> 255 swift.VariantSelector.init(); 256 </script> 257 } 258 } 259 else if (Pageview.IsVisualEditorMode) 260 { 261 <div class="alert alert-dark m-0" role="alert"> 262 <span>@Translate("No products available")</span> 263 </div> 264 } 265
Error executing template "/Designs/Swift/Paragraph/DS_ProductAddToCart.cshtml"
System.NullReferenceException: Object reference not set to an instance of an object.
   at CompiledRazorTemplates.Dynamic.RazorEngine_ccd6a229b5cf4e9698a8e5562bbe4c85.Execute() in C:\inetpub\wwwroot\DWShop2023\Solutions\Swift_v1.21.0\Files\Templates\Designs\Swift\Paragraph\DS_ProductAddToCart.cshtml:line 94
   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.CustomerExperienceCenter.Favorites 4 5 6 @{ 7 ProductViewModel product = null; 8 if (Dynamicweb.Context.Current.Items.Contains("ProductDetails")) 9 { 10 product = (ProductViewModel)Dynamicweb.Context.Current.Items["ProductDetails"]; 11 } 12 else if (Pageview.Item["DummyProduct"] != null) 13 { 14 var pageViewModel = Dynamicweb.Frontend.ContentViewModelFactory.CreatePageInfoViewModel(Pageview.Page); 15 ProductListViewModel productList = pageViewModel.Item.GetValue("DummyProduct") != null ? pageViewModel.Item.GetValue("DummyProduct") as ProductListViewModel : new ProductListViewModel(); 16 17 if (productList?.Products is object) 18 { 19 product = productList.Products[0]; 20 } 21 } 22 23 string anonymousUsersLimitations = Pageview.AreaSettings.GetRawValueString("AnonymousUsers", ""); 24 bool anonymousUser = Pageview.User == null; 25 bool isErpConnectionDown = !Dynamicweb.Core.Converter.ToBoolean(Dynamicweb.Context.Current.Items["IsWebServiceConnectionAvailable"]); 26 bool hideAddToCart = anonymousUsersLimitations.Contains("cart") && anonymousUser || Pageview.AreaSettings.GetBoolean("ErpDownHideAddToCart") && isErpConnectionDown; 27 hideAddToCart = Pageview.IsVisualEditorMode ? false : hideAddToCart; 28 } 29 30 @if (product is object && !hideAddToCart) { 31 string horizontalAlign = Model.Item.GetRawValueString("HorizontalAlignment", ""); 32 horizontalAlign = horizontalAlign == "center" ? "justify-content-center" : horizontalAlign; 33 horizontalAlign = horizontalAlign == "end" ? "justify-content-end" : horizontalAlign; 34 horizontalAlign = horizontalAlign == "full" ? "" : horizontalAlign; 35 36 bool favoritesSelector = !string.IsNullOrEmpty(Model.Item.GetString("ShowAddToFavorites")) ? Model.Item.GetBoolean("ShowAddToFavorites") : false; 37 bool quantitySelector = !string.IsNullOrEmpty(Model.Item.GetString("ShowQuantitySelector")) ? Model.Item.GetBoolean("ShowQuantitySelector") : false; 38 bool unitsSelector = !string.IsNullOrEmpty(Model.Item.GetString("ShowUnitsSelector")) ? Model.Item.GetBoolean("ShowUnitsSelector") : false; 39 bool hideInventory = !string.IsNullOrEmpty(Model.Item.GetString("HideInventory")) ? Model.Item.GetBoolean("HideInventory") : false; 40 bool hideStockState = !string.IsNullOrEmpty(Model.Item.GetString("HideStockState")) ? Model.Item.GetBoolean("HideStockState") : false; 41 42 string buttonSize = Model.Item.GetRawValueString("ButtonSize", "regular"); 43 string inputSize = string.Empty; 44 45 switch (buttonSize) 46 { 47 case "small": 48 inputSize = " input-group-sm"; 49 buttonSize = " btn-sm"; 50 break; 51 case "regular": 52 buttonSize = string.Empty; 53 break; 54 case "large": 55 inputSize = " input-group-lg"; 56 buttonSize = " btn-lg"; 57 break; 58 } 59 60 string iconPath = "/Files/icons/"; 61 string url = "/Default.aspx?ID=" + (GetPageIdByNavigationTag("CartService")); 62 if (!url.Contains("LayoutTemplate")) 63 { 64 url += url.Contains("?") ? "&LayoutTemplate=Swift_MiniCart.cshtml" : "?LayoutTemplate=Swift_MiniCart.cshtml"; 65 } 66 67 string disableAddToCart = (product.StockLevel <= 0) ? "disabled" : ""; 68 bool isNeverOutOfStock = product.NeverOutOfstock; 69 disableAddToCart = isNeverOutOfStock ? "" : disableAddToCart; 70 71 string whenVariantsExist = Model.Item.GetRawValueString("WhenVariantsExist", "hide"); 72 73 string flexFill = Model.Item.GetRawValueString("HorizontalAlignment", "") == "full" ? "flex-fill" : ""; 74 string fullWidth = Model.Item.GetRawValueString("HorizontalAlignment", "") == "full" ? "w-100" : ""; 75 string addToCartIcon = Model.Item.GetRawValueString("Icon", iconPath + "shopping-cart.svg"); 76 string addToCartLabel = !addToCartIcon.Contains("_none") ? "<span class=\"icon-2\">" + ReadFile(addToCartIcon) + "</span>" : ""; 77 addToCartLabel += !addToCartIcon.Contains("_none") && !Model.Item.GetBoolean("HideButtonText") ? " " : ""; 78 addToCartLabel += !Model.Item.GetBoolean("HideButtonText") ? Translate("Add to cart") : ""; 79 string imagePath = product?.DefaultImage?.Value ?? ""; 80 imagePath = Dynamicweb.Context.Current.Server.UrlEncode(imagePath); 81 string ratio = Model.Item.GetRawValueString("ImageAspectRatio", ""); 82 ratio = ratio != "0" ? ratio : ""; 83 string ratioCssClass = ratio != "" ? " ratio" : ""; 84 string ratioVariable = ratio != "" ? "--bs-aspect-ratio: " + ratio : ""; 85 86 string width = Model.Item.GetRawValueString("Width", "auto"); 87 int smallImageSize = 640; 88 int largeImageSize = width == "auto" ? 1280 : Convert.ToInt32(width); 89 string imagePathXs = "/Admin/Public/GetImage.ashx?width=" + smallImageSize + "&image=" + imagePath + "&format=webp"; 90 string imagePathS = "/Admin/Public/GetImage.ashx?width=" + largeImageSize + "&image=" + imagePath + "&format=webp"; 91 string imagePathFallBack = "/Admin/Public/GetImage.ashx?width=" + largeImageSize + "&image=" + imagePath + "&format=webp"; 92 93 94 if (product.VariantInfo.VariantInfo == null || whenVariantsExist == "disable") { 95 string unitId = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form.Get("UnitId")) ? Dynamicweb.Context.Current.Request.Form.Get("UnitId") : product.DefaultUnitId; 96 if (string.IsNullOrEmpty(unitId) && product?.UnitOptions != null) { 97 if (product.UnitOptions.FirstOrDefault<UnitOptionViewModel>() != null) { 98 unitId = product.UnitOptions.FirstOrDefault<UnitOptionViewModel>().Id; 99 } 100 } 101 102 string minQty = product.PurchaseMinimumQuantity != 1 ? "min=\"" + product.PurchaseMinimumQuantity.ToString() + "\"" : "min=\"1\""; 103 string stepQty = product.PurchaseQuantityStep > 1 ? product.PurchaseQuantityStep.ToString() : "1"; 104 string valueQty = product.PurchaseMinimumQuantity > product.PurchaseQuantityStep ? product.PurchaseMinimumQuantity.ToString() : stepQty; 105 disableAddToCart = product.VariantInfo.VariantInfo != null && string.IsNullOrEmpty(product.VariantId) ? "disabled" : disableAddToCart; 106 107 var reserveMode = Dynamicweb.Ecommerce.Frontend.Cart.ProductReserve.Mode; 108 109 if (unitsSelector && product.UnitOptions.Count > 0) { 110 <form method="post" action="/Default.aspx?ID=@(Pageview.Page.ID)&ProductId=@product.Id" id="UnitSelectorForm_@(product.Id)_@(product.VariantId)_@Model.ID"> 111 <input type="hidden" name="redirect" value="false"> 112 <input type="hidden" name="VariantID" value="@product.VariantId"> 113 <input type="hidden" name="UnitID" class="js-unit-id" value="@unitId"> 114 </form> 115 } 116 117 <div class="d-flex @horizontalAlign @fullWidth js-input-group item_@Model.Item.SystemName.ToLower()"> 118 <form method="post" action="@url" class="@fullWidth" style="z-index: 1"> 119 <input type="hidden" name="redirect" value="false"> 120 <input type="hidden" name="ProductId" value="@product.Id"> 121 <input type="hidden" name="ProductName" value="@product.Name"> 122 <input type="hidden" name="ProductVariantName" value="@product.VariantName"> 123 <input type="hidden" name="ProductCurrency" value="@Dynamicweb.Ecommerce.Common.Context.Currency.Code"> 124 <input type="hidden" name="ProductPrice" value="@PriceViewModelExtensions.ToStringInvariant(product.Price)"> 125 <input type="hidden" name="ProductReferer" value="component_ProductAddToCart"> 126 <input type="hidden" name="cartcmd" value="add"> 127 128 @if (reserveMode == Dynamicweb.Ecommerce.Frontend.Cart.ProductReserveMode.AddToCart) 129 { 130 <input type="hidden" name="GetReservedAmount" value="true"> 131 } 132 133 @if (!string.IsNullOrEmpty(product.VariantId)) 134 { 135 <input type="hidden" name="VariantId" value="@product.VariantId"> 136 } 137 138 @if (!product.NeverOutOfstock) 139 { 140 <input type="hidden" name="Stock" value="@product.StockLevel"> 141 142 <template class="js-out-of-stock-notice"> 143 <div class="modal-header"> 144 <h1 class="modal-title fs-5">@Translate("Stock limit")</h1> 145 <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> 146 </div> 147 <div class="modal-body"> 148 @Translate("There are not enough products in stock. The product might be sold out or discontinued. Please adjust the quantity.") 149 </div> 150 </template> 151 } 152 153 @if (stepQty != "1") 154 { 155 <template class="js-step-quantity-warning"> 156 <div class="modal-header"> 157 <h1 class="modal-title fs-5">@Translate("The quantity is not valid")</h1> 158 </div> 159 <div class="modal-body"> 160 @Translate("Please select a quantity that is dividable by") @stepQty 161 </div> 162 </template> 163 } 164 @if (product.PurchaseMinimumQuantity != 1) 165 { 166 <template class="js-min-quantity-warning"> 167 <div class="modal-header"> 168 <h1 class="modal-title fs-5">@Translate("The product could not be added to the cart")</h1> 169 </div> 170 <div class="modal-body"> 171 @Translate("The quantity is not valid. You must buy at least") @product.PurchaseMinimumQuantity 172 </div> 173 </template> 174 } 175 176 @if (quantitySelector || (!anonymousUser && product.VariantInfo.VariantInfo != null) || (!anonymousUser && favoritesSelector)) 177 { 178 <input type="hidden" id="Unit_@(product.Id)_@product.VariantId" name="UnitID" value="@unitId" /> 179 } 180 181 <div class="d-flex flex-row w-100"> 182 @if (!anonymousUser && favoritesSelector) 183 { 184 @RenderPartial("Components/ToggleFavorite.cshtml", product) 185 } 186 187 @if (!quantitySelector) 188 { 189 <input id="Quantity_@(product.Id)_@product.VariantId" name="Quantity" value="@valueQty" type="hidden" @disableAddToCart> 190 } 191 192 <div class="input-group input-primary-button-group flex-nowrap@(inputSize)"> 193 @if(product.StockLevel>0){ 194 if (quantitySelector) 195 { 196 <input id="Quantity_@(product.Id)_@product.VariantId" name="Quantity" value="@valueQty" step="@stepQty" @minQty class="form-control swift_quantity-field AddToCardButton" style="min-width: 60px; max-width: 100px; z-index: 1" type="number" onchange="swift.Cart.UpdateOnEnterKey(event)" onkeyup="swift.Cart.UpdateOnEnterKey(event)" @disableAddToCart> 197 } 198 199 if (unitsSelector && product.UnitOptions.Count > 0) 200 { 201 string selectedUnitName = !string.IsNullOrEmpty(unitId) && product?.UnitOptions != null ? unitId : product.UnitOptions.FirstOrDefault<UnitOptionViewModel>().Name; 202 203 foreach (var unitOption in product.UnitOptions) 204 { 205 if (unitOption.Id == unitId) 206 { 207 selectedUnitName = unitOption.Name; 208 } 209 } 210 211 <button class="btn btn-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false"> 212 @selectedUnitName 213 </button> 214 <ul class="dropdown-menu swift_unit-field"> 215 @foreach (var unitOption in product.UnitOptions) 216 { 217 var selectedUnit = unitOption.Id == unitId ? "selected" : ""; 218 219 <li> 220 <button type="button" class="btn dropdown-item" data-value="@unitOption.Id" onclick="document.querySelector('#UnitSelectorForm_@(product.Id)_@(product.VariantId)_@Model.ID').querySelector('.js-unit-id').value = this.getAttribute('data-value'); 221 document.querySelector('#Unit_@(product.Id)_@product.VariantId').value = this.getAttribute('data-value'); 222 swift.PageUpdater.Update(document.querySelector('#UnitSelectorForm_@(product.Id)_@(product.VariantId)_@Model.ID'))"> 223 <span>@unitOption.Name</span> 224 <span> 225 @if (unitOption.StockLevel > 0) 226 { 227 if (!Model.Item.GetBoolean("HideInventory")) 228 { 229 <span class="small text-success">@unitOption.StockLevel @Translate("In stock")</span> 230 } 231 else 232 { 233 <span class="small text-success">@Translate("In stock")</span> 234 } 235 } 236 else 237 { 238 <span class="small text-danger">@Translate("Out of Stock")</span> 239 } 240 </span> 241 </button> 242 </li> 243 } 244 </ul> 245 } 246 247 <button type="button" onclick="swift.Cart.Update(event); AddToCartInfo()" class="btn btn-secondary @(buttonSize) @flexFill js-add-to-cart-button" style="white-space: nowrap" @disableAddToCart title="@Translate("Add to cart")" id="AddToCartButton@(product.Id)_@Pageview.CurrentParagraph.ID"> 248 @if (!Model.Item.GetBoolean("HideButtonText")) 249 { 250 <span class="text-nowrap d-flex align-items-center justify-content-center gap-2"> 251 @addToCartLabel 252 </span> 253 } 254 else 255 { 256 @addToCartLabel 257 } 258 </button> 259 <div aria-live="polite" aria-atomic="true"> 260 <div class="position-fixed bottom-0 end-0 p-3" style="z-index: 11"> 261 <div id="AddToCartInfo" class="toast hide" role="alert" aria-live="assertive" aria-atomic="true" autohide="true"> 262 <div class="toast-header"> 263 <strong class="me-auto">@Translate("Product is added to the cart")</strong> 264 <button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button> 265 </div> 266 <div class="toast-body d-flex gap-3"> 267 <div id="AddToCartInfoNotificationToast_Image"><img src="@imagePathXs" style="width:100px;"></div> 268 <div id="AddToCartInfoNotificationToast_Text" >@(product.Name)<br> 269 @(product.Id)</div> 270 </div> 271 </div> 272 </div> 273 </div> 274 <script> 275 function AddToCartInfo() { 276 document.getElementById("AddToCartInfo").classList.add("show"); 277 setTimeout(function() { 278 document.getElementById("AddToCartInfo").classList.remove("show"); 279 }, 3000); 280 } 281 </script> 282 283 284 285 286 287 } else { 288 289 <div class="productNotAvailable text-nowrap d-flex align-items-center justify-content-center gap-2">@Translate("This product is currently not available.")</div> 290 291 } 292 </div> 293 </div> 294 </form> 295 </div> 296 } else if (whenVariantsExist == "modal") { 297 string buttonText = Translate("Select"); 298 299 string variantSelectorServicePageId = !string.IsNullOrEmpty(Model.Item.GetString("VariantSelectorServicePageId")) ? Model.Item.GetLink("VariantSelectorServicePageId").PageId.ToString() : ""; 300 variantSelectorServicePageId = variantSelectorServicePageId != "" ? variantSelectorServicePageId : GetPageIdByNavigationTag("VariantSelectorService").ToString(); 301 302 <div class="d-flex @horizontalAlign w-100 item_@Model.Item.SystemName.ToLower()"> 303 @if (!anonymousUser && favoritesSelector) 304 { 305 @RenderPartial("Components/ToggleFavorite.cshtml", product) 306 } 307 <form action="/Default.aspx?ID=@variantSelectorServicePageId" data-response-target-element="DynamicModalContent" data-preloader="inline" style="z-index: 1" class="@fullWidth"> 308 <input type="hidden" name="ProductID" value="@product.Id"> 309 <input type="hidden" name="QuantitySelector" value="@quantitySelector.ToString()"> 310 <input type="hidden" name="HideInventory" value="@hideInventory.ToString()"> 311 <input type="hidden" name="HideStockState" value="@hideStockState.ToString()"> 312 <input type="hidden" name="VariantSelectorServicePage" value="@variantSelectorServicePageId"> 313 <input type="hidden" name="ViewType" value="ModalContent"> 314 <button type="button" onclick="swift.PageUpdater.Update(event)" class="btn btn-primary@(buttonSize) @fullWidth" title="@Translate("Select")" data-bs-toggle="modal" data-bs-target="#DynamicModal" id="OpenVariantSelectorModal@(product.Id)_@Pageview.CurrentParagraph.ID">@buttonText</button> 315 </form> 316 </div> 317 } 318 } else if (Pageview.IsVisualEditorMode) { 319 <div class="alert alert-dark m-0">@Translate("No products available")</div> 320 } 321
Error executing template "/Designs/Swift/Paragraph/DS_ProductSpecification.cshtml"
System.NullReferenceException: Object reference not set to an instance of an object.
   at CompiledRazorTemplates.Dynamic.RazorEngine_83dcbf164a8b48999478918a02a70a99.Execute() in C:\inetpub\wwwroot\DWShop2023\Solutions\Swift_v1.21.0\Files\Templates\Designs\Swift\Paragraph\DS_ProductSpecification.cshtml:line 28
   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 ProductViewModel product = null; 6 if (Dynamicweb.Context.Current.Items.Contains("ProductDetails")) 7 { 8 product = (ProductViewModel)Dynamicweb.Context.Current.Items["ProductDetails"]; 9 } 10 else if (Pageview.Item["DummyProduct"] != null) 11 { 12 var pageViewModel = Dynamicweb.Frontend.ContentViewModelFactory.CreatePageInfoViewModel(Pageview.Page); 13 ProductListViewModel productList = pageViewModel.Item.GetValue("DummyProduct") != null ? pageViewModel.Item.GetValue("DummyProduct") as ProductListViewModel : new ProductListViewModel(); 14 15 if (productList?.Products is object) 16 { 17 product = productList.Products[0]; 18 } 19 } 20 } 21 22 @if (product is object) { 23 IEnumerable<string> selectedDisplayGroupIds = Model.Item.GetRawValueString("DisplayGroups").Split(',').ToList(); 24 List<CategoryFieldViewModel> displayGroups = new List<CategoryFieldViewModel>(); 25 26 foreach (var selection in selectedDisplayGroupIds) 27 { 28 foreach (CategoryFieldViewModel group in product.FieldDisplayGroups.Values) 29 { 30 if (selection == group.Id) 31 { 32 int fieldsWithNoValueOrZero = 0; 33 34 foreach (var field in group.Fields) 35 { 36 if (string.IsNullOrEmpty(field.Value.Value.ToString())) 37 { 38 fieldsWithNoValueOrZero++; 39 } 40 } 41 42 if (fieldsWithNoValueOrZero != group.Fields.Count) 43 { 44 displayGroups.Add(group); 45 } 46 } 47 } 48 } 49 50 bool showProductFields = Model.Item.GetBoolean("ProductFields"); 51 52 bool hideTitle = Model.Item.GetBoolean("HideTitle"); 53 54 string theme = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("Theme")) ? " theme " + Model.Item.GetRawValueString("Theme").Replace(" ", "").Trim().ToLower() : ""; 55 56 string titleFontSize = Model.Item.GetRawValueString("TitleFontSize", "display-4"); 57 58 string contentPadding = Model.Item.GetRawValueString("ContentPadding", ""); 59 contentPadding = contentPadding == "none" ? string.Empty : contentPadding; 60 contentPadding = contentPadding == "small" ? " p-2 p-md-3" : contentPadding; 61 contentPadding = contentPadding == "large" ? " p-4 p-md-5" : contentPadding; 62 63 string layout = Model.Item.GetRawValueString("Layout", "list"); 64 string size = Model.Item.GetRawValueString("Size", "full"); 65 string gaps = size == "full" ? " gap-4" : " gap-2"; 66 67 68 if (Pageview.IsVisualEditorMode && displayGroups.Count() == 0) 69 { 70 product.ProductFields.Clear(); 71 product.ProductFields.Add(Translate("Width"), new FieldValueViewModel { Name = Translate("Width"), Value = "99cm" }); 72 product.ProductFields.Add(Translate("Height"), new FieldValueViewModel { Name = Translate("Height"), Value = "195cm" }); 73 showProductFields = true; 74 } 75 76 if (layout == "commas") 77 { 78 gaps = size == "full" ? " gap-4" : " gap-2"; 79 80 } 81 82 <div class="h-100@(gaps)@(theme)@(contentPadding) item_@Model.Item.SystemName.ToLower()"> 83 <div> 84 @if ((product.ProductFields != null && Model.Item.GetBoolean("ProductFields")) || (product.ProductCategories != null && Model.Item.GetBoolean("CategoryFields")) || (displayGroups.Count != 0)) { 85 if (!hideTitle) 86 { 87 <h2 class="g-col-12 @titleFontSize">@Model.Item.GetString("Title")</h2> 88 } 89 } 90 91 @if (displayGroups.Count != 0) 92 { 93 int br = 0; 94 string show = " none"; 95 if (layout != "accordion") 96 { 97 foreach (var group in displayGroups) 98 { 99 bool hideHeader = Model.Item.GetBoolean("HideGroupHeaders"); 100 101 if (!hideHeader) { 102 show = " none"; 103 if (br == 0) 104 { 105 show = " ShowList"; 106 br++; 107 } 108 <h4 class="g-col-12 h4 mb-0 productdetailAtributesHeading" onclick="document.getElementsByClassName('@group.Name')[0].classList.toggle('ShowList');">+ @Translate(group.Name) </h4> 109 } 110 111 { <div class="@group.Name @show">@RenderFieldsFromList(group.Fields, layout)</div> } 112 113 114 115 } 116 <div class="g-col-12"> 117 <a href="/Default.aspx?Id=@GetPageIdByNavigationTag("TermsAndConditions") ?1" class=" productdetailAtributesHeading">+ @Translate("DOSTAVA")</a> <br> 118 <a href="/Default.aspx?Id=@GetPageIdByNavigationTag("TermsAndConditions") ?3" class=" productdetailAtributesHeading">+ @Translate("PLAĆANJE")</a> <br> 119 <a href="/Default.aspx?Id=@GetPageIdByNavigationTag("TermsAndConditions") ?2" class=" productdetailAtributesHeading">+ @Translate("POVRATI I ZAMJENE")</a> 120 </div> 121 } 122 else 123 { 124 <div class="g-col-12"> 125 <div class="accordion accordion-flush w-100" id="Specifications_@Model.ID"> 126 @foreach (var group in displayGroups) 127 { 128 <div class="accordion-item"> 129 <h2 class="accordion-header" id="SpecificationHeading_@group.Id"> 130 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#SpecificationItem_@group.Id" aria-expanded="false" aria-controls="SpecificationItem_@group.Id"> 131 @group.Name 132 </button> 133 </h2> 134 <div id="SpecificationItem_@group.Id" class="accordion-collapse collapse" aria-labelledby="SpecificationHeading_@group.Id" data-bs-parent="#Specifications_@Model.ID"> 135 <div class="accordion-body"> 136 @{ @RenderFieldsFromList(group.Fields, "list") } 137 </div> 138 </div> 139 </div> 140 } 141 </div> 142 </div> 143 } 144 } 145 146 @if (product.ProductFields != null && showProductFields) 147 { 148 if (product.ProductFields.Count > 0) 149 { 150 if (layout != "accordion") 151 { 152 {@RenderFieldsFromList(product.ProductFields, layout) } 153 } 154 else 155 { 156 <div class="g-col-12"> 157 <div class="accordion accordion-flush w-100" id="Specifications_@Model.ID"> 158 <div class="accordion-item"> 159 <h2 class="accordion-header" id="SpecificationHeading_@Model.ID"> 160 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#SpecificationItem_@Model.ID" aria-expanded="false" aria-controls="SpecificationItem_@Model.ID"> 161 @Translate("Specifications") 162 </button> 163 </h2> 164 <div id="SpecificationItem_@Model.ID" class="accordion-collapse" aria-labelledby="SpecificationHeading_@Model.ID" data-bs-parent="#Specifications_@Model.ID"> 165 <div class="accordion-body"> 166 @{ @RenderFieldsFromList(product.ProductFields, "List") } 167 </div> 168 </div> 169 </div> 170 </div> 171 </div> 172 } 173 } 174 } 175 176 @if (product.ProductCategories != null && Model.Item.GetBoolean("CategoryFields")) 177 { 178 if (product.ProductCategories.Count > 0) 179 { 180 if (layout != "accordion") 181 { 182 foreach (var group in product.ProductCategories) 183 { 184 CategoryFieldViewModel category = group.Value; 185 bool hideHeader = Model.Item.GetBoolean("HideGroupHeaders"); 186 187 if (!hideHeader) { 188 <h4 class="g-col-12 h4 mb-0">@group.Value.Name</h4> 189 } 190 191 { @RenderFieldsFromList(category.Fields, layout) } 192 } 193 } 194 else 195 { 196 <div class="g-col-12"> 197 <div class="accordion accordion-flush w-100" id="Specifications_@Model.ID"> 198 @foreach (var group in product.ProductCategories) 199 { 200 CategoryFieldViewModel category = group.Value; 201 202 <div class="accordion-item"> 203 <h2 class="accordion-header" id="SpecificationHeading_@group.Value.Id"> 204 <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#SpecificationItem_@group.Value.Id" aria-expanded="false" aria-controls="SpecificationItem_@group.Value.Id"> 205 @group.Value.Name 206 </button> 207 </h2> 208 <div id="SpecificationItem_@group.Value.Id" class="accordion-collapse" aria-labelledby="SpecificationHeading_@group.Value.Id" data-bs-parent="#Specifications_@Model.ID"> 209 <div class="accordion-body"> 210 @{ @RenderFieldsFromList(category.Fields, "list") } 211 </div> 212 </div> 213 </div> 214 } 215 </div> 216 </div> 217 } 218 } 219 } 220 </div> 221 </div> 222 } 223 else if (Pageview.IsVisualEditorMode) 224 { 225 <div class="alert alert-warning m-0">@Translate("No products available")</div> 226 } 227 228 @helper RenderFieldsFromList(Dictionary<string, FieldValueViewModel> fields, string layout) 229 { 230 string size = Model.Item.GetRawValueString("Size", "full"); 231 string gaps = size != "full" ? " gap-1" : string.Empty; 232 bool hideFieldLabels = Model.Item.GetBoolean("HideFieldLabels"); 233 bool hideFieldsWithZeroValue = Model.Item.GetBoolean("HideFieldsWithZeroValue"); 234 235 if (layout == "columns") { 236 <div class="g-col-12"> 237 <div class="grid@(gaps)"> 238 @foreach (var field in fields) 239 { 240 {@RenderField(field.Value, layout)} 241 } 242 </div> 243 </div> 244 } 245 if (layout == "list") { 246 <div class="g-col-12"> 247 <dl class="Popis"> 248 @foreach (var field in fields) 249 { 250 {@RenderField(field.Value, layout)} 251 } 252 </dl> 253 </div> 254 } 255 if (layout == "table") 256 { 257 string tableSize = size == "full" ? "" : " table-sm"; 258 <div class="g-col-12"> 259 <table class="table table-striped@(tableSize)"> 260 @foreach (var field in fields) 261 { 262 {@RenderField(field.Value, layout)} 263 } 264 </table> 265 </div> 266 } 267 if (layout == "bullets") 268 { 269 string listSize = size == "full" ? "" : "m-0 p-0 lh-1 fs-7 opacity-75"; 270 string listStyle = size == "full" ? "" : "style=\"list-style-position: inside\""; 271 <div class="g-col-12"> 272 <ul class="@listSize" @listStyle> 273 @foreach (var field in fields) 274 { 275 {@RenderField(field.Value, layout)} 276 } 277 </ul> 278 </div> 279 } 280 if (layout == "commas") 281 { 282 List<string> featuresList = new List<string>(); 283 284 foreach (var field in fields) 285 { 286 string firstListItemValue = string.Empty; //Hack to support field type providers with a single value 287 288 if (field.Value?.Value != null) 289 { 290 if (field.Value.Value.GetType() == typeof(System.Collections.Generic.List<FieldOptionValueViewModel>)) 291 { 292 System.Collections.Generic.List<FieldOptionValueViewModel> values = field.Value.Value as System.Collections.Generic.List<FieldOptionValueViewModel>; 293 294 //Hack to support field type providers with a single value 295 if (values.FirstOrDefault() != null) 296 { 297 firstListItemValue = values.FirstOrDefault().Value; 298 } 299 } 300 } 301 302 if (!hideFieldsWithZeroValue || (firstListItemValue != "0" && firstListItemValue != "0.0" && field.Value.Value.ToString() != "0" && field.Value.Value.ToString() != "0.0")) 303 { 304 if (field.Value.Value is object && !string.IsNullOrEmpty(field.Value.Value.ToString())) 305 { 306 if (field.Value.Value.GetType() == typeof(System.Collections.Generic.List<FieldOptionValueViewModel>)) 307 { 308 List<string> options = new List<string>(); 309 foreach (FieldOptionValueViewModel option in field.Value.Value as System.Collections.Generic.List<FieldOptionValueViewModel>) 310 { 311 if (!string.IsNullOrWhiteSpace(option.Value)) 312 { 313 if (option.Value.ToString().Contains("#") && (Translate(field.Value.Name) == Translate("Color") || Translate(field.Value.Name) == Translate("Colour"))) 314 { 315 string colorSpan = "<span class=\"colorbox-sm\" style=\"background-color: " + option.Value + "\"></span>"; 316 options.Add(colorSpan); 317 } 318 else if (!string.IsNullOrEmpty(option.Value)) 319 { 320 options.Add(option.Name); 321 } 322 } 323 } 324 string optionsString = (string.Join(", ", options.Select(x => x.ToString()).ToArray())); 325 if ((Translate(field.Value.Name) == Translate("Color") || Translate(field.Value.Name) == Translate("Colour"))) 326 { 327 optionsString = (string.Join(" ", options.Select(x => x.ToString()).ToArray())); 328 } 329 330 if (!string.IsNullOrEmpty(optionsString)) 331 { 332 if (!hideFieldLabels) 333 { 334 featuresList.Add(field.Value.Name + ": " + optionsString); 335 } 336 else 337 { 338 featuresList.Add(optionsString); 339 } 340 } 341 } 342 else 343 { 344 if (!string.IsNullOrWhiteSpace(field.Value.Value.ToString())) 345 { 346 if (field.Value.Value.ToString().Contains("#") && (Translate(field.Value.Name) == Translate("Color") || Translate(field.Value.Name) == Translate("Colour"))) 347 { 348 string colorSpan = "<span class=\"colorbox-sm\" style=\"background-color: " + field.Value.Value + "\"></span>"; 349 350 if (!hideFieldLabels) 351 { 352 featuresList.Add(field.Value.Name + ": " + colorSpan); 353 } 354 else 355 { 356 featuresList.Add(colorSpan); 357 } 358 } 359 else 360 { 361 if (!hideFieldLabels) 362 { 363 featuresList.Add(field.Value.Name + ": " + field.Value.Value.ToString()); 364 } 365 else 366 { 367 featuresList.Add(field.Value.Value.ToString()); 368 } 369 } 370 } 371 } 372 } 373 } 374 } 375 376 string featuresString = (string.Join(", ", featuresList.Select(x => x.ToString()).ToArray())); 377 378 <div class="g-col-12 opacity-75 fs-7">@featuresString</div> 379 } 380 } 381 382 @helper RenderField(FieldValueViewModel field, string layout) 383 { 384 string size = Model.Item.GetRawValueString("Size", "full"); 385 string fieldValue = field?.Value != null ? field.Value.ToString() : ""; 386 bool hideFieldLabels = Model.Item.GetBoolean("HideFieldLabels"); 387 bool noValues = false; 388 string firstListItemValue = string.Empty; //Hack to support field type providers with a single value 389 bool hideFieldsWithZeroValue = Model.Item.GetBoolean("HideFieldsWithZeroValue"); 390 391 if (!string.IsNullOrEmpty(fieldValue)) 392 { 393 if (field.Value.GetType() == typeof(System.Collections.Generic.List<FieldOptionValueViewModel>)) 394 { 395 System.Collections.Generic.List<FieldOptionValueViewModel> values = field.Value as System.Collections.Generic.List<FieldOptionValueViewModel>; 396 noValues = values.Count > 0 ? false : true; 397 398 //Hack to support field type providers with a single value 399 if (values.FirstOrDefault() != null) 400 { 401 firstListItemValue = values.FirstOrDefault().Value; 402 } 403 } 404 } 405 406 if (!string.IsNullOrEmpty(fieldValue) && noValues == false) 407 { 408 if (!hideFieldsWithZeroValue || (firstListItemValue != "0" && firstListItemValue != "0.0" && field.Value.ToString() != "0" && field.Value.ToString() != "0.0")) 409 { 410 if (layout == "columns") 411 { 412 413 <div class="grid g-col-6 g-col-lg-4 gap-1"> 414 @if (!hideFieldLabels) 415 { 416 <dt class="g-col-12 g-col-lg-4">@field.Name</dt> 417 } 418 <dd class="g-col-12 g-col-lg-8 mb-0 text-break"> 419 @{ @RenderFieldValue(field) } 420 </dd> 421 </div> 422 } 423 if (layout == "list") 424 { 425 if (!hideFieldLabels) 426 { 427 <div class="g-col-4 productField">@field.Name: @{ @RenderFieldValue(field) }</div> 428 } 429 } 430 if (layout == "table") 431 { 432 <tr> 433 @if (!hideFieldLabels) 434 { 435 <th class="w-25 w-lg-50" scope="row">@field.Name</th> 436 } 437 <td class="text-break"> 438 @{ @RenderFieldValue(field) } 439 </td> 440 </tr> 441 } 442 if (layout == "bullets") 443 { 444 <li> 445 @if (!hideFieldLabels) 446 { 447 <strong>@field.Name</strong> 448 } 449 <span> 450 @{ @RenderFieldValue(field) } 451 </span> 452 </li> 453 } 454 } 455 } 456 } 457 458 @helper RenderFieldValue(FieldValueViewModel field) 459 { 460 string fieldValue = field?.Value != null ? field.Value.ToString() : ""; 461 462 bool isLink = field?.Type == "Link"; 463 bool isColor = false; 464 bool isBrandName = field?.SystemName == "Brand_name"; 465 466 fieldValue = fieldValue == "False" ? Translate("No") : fieldValue; 467 fieldValue = fieldValue == "True" ? Translate("Yes") : fieldValue; 468 469 470 if (field.Value.GetType() == typeof(System.Collections.Generic.List<Dynamicweb.Ecommerce.ProductCatalog.FieldOptionValueViewModel>)) 471 { 472 int valueCount = 0; 473 System.Collections.Generic.List<FieldOptionValueViewModel> values = field.Value as System.Collections.Generic.List<FieldOptionValueViewModel>; 474 int totalValues = values.Count; 475 476 foreach (FieldOptionValueViewModel option in values) 477 { 478 if (!string.IsNullOrEmpty(option.Value)) 479 { 480 if (option.Value.Substring(0, 1) == "#") 481 { 482 isColor = true; 483 } 484 } 485 486 if (!isColor) 487 { 488 @option.Name 489 } 490 else 491 { 492 <span class="colorbox-sm" style="background-color: @option.Value" title="@option.Name"></span> 493 } 494 495 if (valueCount != totalValues && valueCount < (totalValues - 1)) 496 { 497 if (isColor) 498 { 499 <text> </text> 500 } 501 else 502 { 503 <text>, </text> 504 } 505 } 506 valueCount++; 507 } 508 } 509 else 510 { 511 if (fieldValue.Substring(0, 1) == "#") 512 { 513 isColor = true; 514 } 515 516 if (!isColor) 517 { 518 if (isLink) 519 { 520 string linktTitle = !fieldValue.Contains("aspx") ? fieldValue : Translate("Go to link"); 521 string target = Pageview.AreaSettings.GetBoolean("OpenLinksInNewTab") && fieldValue.Contains("http") ? "target=\"_blank\"" : string.Empty; 522 string rel = Pageview.AreaSettings.GetBoolean("OpenLinksInNewTab") && fieldValue.Contains("http") ? "rel=\"noopener\"" : string.Empty; 523 524 <a href="@field.Value" title="@field.Name" @target @rel>@linktTitle</a> 525 } 526 else if (isBrandName) 527 { 528 <span itemprop="brand" itemtype="https://schema.org/Brand" itemscope> 529 <span itemprop="name">@fieldValue</span> 530 </span> 531 } 532 else 533 { 534 @fieldValue 535 } 536 537 } 538 else 539 { 540 <span class="colorbox-sm" style="background-color: @fieldValue" title="@fieldValue"></span> 541 } 542 } 543 } 544
Error executing template "/Designs/Swift/Paragraph/DS_RelatedProducts.cshtml"
System.NullReferenceException: Object reference not set to an instance of an object.
   at CompiledRazorTemplates.Dynamic.RazorEngine_5540b5b3e5664a0dba9536a107b81d39.Execute() in C:\inetpub\wwwroot\DWShop2023\Solutions\Swift_v1.21.0\Files\Templates\Designs\Swift\Paragraph\Swift_RelatedProducts.cshtml:line 171
   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.Core 3 @using Dynamicweb.Ecommerce.ProductCatalog 4 5 @{ 6 ProductViewModel product = null; 7 if (Dynamicweb.Context.Current.Items.Contains("ProductDetails")) 8 { 9 product = (ProductViewModel)Dynamicweb.Context.Current.Items["ProductDetails"]; 10 } 11 if (Pageview.Item["DummyProduct"] != null && Pageview.IsVisualEditorMode) 12 { 13 ProductListViewModel productList = Pageview.GetPageviewModel().Item.GetValue<ProductListViewModel>("DummyProduct"); 14 if (productList?.Products is object) 15 { 16 product = productList.Products[0]; 17 } 18 } 19 20 string title = Model?.Item?.GetString("Title") != null ? Model.Item.GetString("Title") : Translate("Products"); 21 string campaignValues = Model.Item.GetRawValueString("CampaignBadges", string.Empty); 22 23 //Styling 24 string titleFontSize = Model.Item.GetRawValueString("TitleFontSize", "h3"); 25 string subtitleFontSize = Model.Item.GetRawValueString("SubtitleFontSize", "fs-5"); 26 string buttonStyle = Model.Item.GetRawValueString("ButtonStyle", ""); 27 buttonStyle = buttonStyle == "primary" ? " btn-primary" : buttonStyle; 28 buttonStyle = buttonStyle == "secondary" ? " btn-secondary" : buttonStyle; 29 buttonStyle = buttonStyle == "link" ? " btn-link" : buttonStyle; 30 string maxWidth = Model.Item.GetRawValueString("TextReadability", ""); 31 maxWidth = maxWidth == "max-width-on" ? " mw-75ch" : maxWidth; 32 maxWidth = maxWidth == "max-width-off" ? "" : maxWidth; 33 34 string generalTheme = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("GeneralTheme")) ? " theme " + Model.Item.GetRawValueString("GeneralTheme").Replace(" ", "").Trim().ToLower() : ""; 35 string theme = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("Theme")) ? " theme " + Model.Item.GetRawValueString("Theme").Replace(" ", "").Trim().ToLower() : ""; 36 string imageTheme = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("ImageTheme")) ? " theme " + Model.Item.GetRawValueString("ImageTheme").Replace(" ", "").Trim().ToLower() : ""; 37 38 //Link generation 39 string pageId = Model.Item.GetLink("ProductSliderServicePage") != null ? Model.Item.GetLink("ProductSliderServicePage").PageId.ToString() : ""; 40 string servicePageByNavigationTag = GetPageIdByNavigationTag("ProductSliderService") != 0 ? GetPageIdByNavigationTag("ProductSliderService").ToString() : ""; 41 pageId = pageId == "" ? servicePageByNavigationTag : pageId; 42 43 string url = "/Default.aspx?ID=" + pageId; 44 if (!url.Contains("LayoutTemplate")) 45 { 46 url += url.Contains("?") ? "&LayoutTemplate=Designs/Swift/Swift_PageClean.cshtml" : "?LayoutTemplate=Designs/Swift/Swift_PageClean.cshtml"; 47 } 48 if (Pageview.IsVisualEditorMode) 49 { 50 url += "&VisualEdit=True"; 51 } 52 53 bool isLazyLoadingForProductInfoEnabled = Dynamicweb.Core.Converter.ToBoolean(Dynamicweb.Context.Current.Items["IsLazyLoadingForProductInfoEnabled"]); 54 if (isLazyLoadingForProductInfoEnabled) 55 { 56 url += "&getproductinfo=true"; 57 } 58 59 //Source type 60 string sourceType = Model.Item.GetRawValueString("RelationType", "trending"); 61 IList<string> relateFromGroupIds = new List<string> { }; 62 IList<string> relateFromProductVariantIds = new List<string> { }; 63 IList<string> relateFromProductIds = new List<string> { }; 64 bool hasVariants = false; 65 66 //--- VARIANTS --- 67 ProductListViewModel productsToRelateToVariants = Model.Item.GetValue<ProductListViewModel>("ProductsToRelateToVariants"); 68 if (productsToRelateToVariants != null && sourceType == "variants") 69 { 70 foreach (var productSelection in productsToRelateToVariants.Products) 71 { 72 relateFromProductIds.Add(productSelection.Id); 73 } 74 } 75 76 //--- MOST SOLD --- 77 IList<ProductGroupViewModel> groupsToRelateToMostSold = Model.Item.GetValue<IList<ProductGroupViewModel>>("GroupsToRelateToMostSold"); 78 if (groupsToRelateToMostSold != null && sourceType == "most-sold") 79 { 80 foreach (var fromGroup in groupsToRelateToMostSold) 81 { 82 relateFromGroupIds.Add(fromGroup.Id); 83 } 84 } 85 86 //--- TRENDING --- 87 IList<ProductGroupViewModel> groupsToRelateToTrending = Model.Item.GetValue<IList<ProductGroupViewModel>>("GroupsToRelateToTrending"); 88 if (groupsToRelateToTrending != null && sourceType == "trending") 89 { 90 foreach (var fromGroup in groupsToRelateToTrending) 91 { 92 relateFromGroupIds.Add(fromGroup.Id); 93 } 94 } 95 96 //--- LATEST --- 97 IList<ProductGroupViewModel> groupsToRelateToLatest = Model.Item.GetValue<IList<ProductGroupViewModel>>("GroupsToRelateToLatest"); 98 if (groupsToRelateToLatest != null && sourceType == "latest") 99 { 100 foreach (var fromGroup in groupsToRelateToLatest) 101 { 102 relateFromGroupIds.Add(fromGroup.Id); 103 } 104 } 105 106 //--- FREQUENTLY BOUGHT --- 107 ProductListViewModel productsToRelateTo = Model.Item.GetValue<ProductListViewModel>("ProductsToRelateTo"); 108 if (productsToRelateTo != null && sourceType == "frequently") 109 { 110 foreach (var fromProduct in productsToRelateTo.Products) 111 { 112 relateFromProductIds.Add(fromProduct.Id); 113 } 114 } 115 116 //--- SELECTED PRODUCTS --- 117 ProductListViewModel products = Model.Item.GetValue<ProductListViewModel>("Products"); 118 if (products != null && sourceType == "selected") 119 { 120 hasVariants = products.Products.Any(p => !string.IsNullOrEmpty(p.VariantId)); 121 foreach (var productSelection in products.Products) 122 { 123 if (hasVariants) 124 { 125 if (!string.IsNullOrEmpty(productSelection.VariantId)) 126 { 127 relateFromProductVariantIds.Add($"{productSelection.Id} {productSelection.VariantId}"); 128 } 129 else 130 { 131 relateFromProductVariantIds.Add($"{productSelection.Id}"); 132 } 133 } 134 relateFromProductIds.Add($"{productSelection.Id}"); 135 } 136 } 137 138 //--- RELATED PRODUCTS --- 139 if (sourceType == "related-products") 140 { 141 ProductListViewModel selectedRelationProduct = Model.Item.GetValue<ProductListViewModel>("ProductsToRelateTo2"); 142 if (selectedRelationProduct?.Products != null) 143 { 144 if (selectedRelationProduct.Products.Count > 0) 145 { 146 int productCount = 0; 147 foreach (var selectedProduct in selectedRelationProduct.Products) 148 { 149 if (productCount == 0) 150 { 151 product = selectedProduct; 152 productCount++; 153 } 154 } 155 } 156 } 157 158 if (product?.RelatedGroups != null) 159 { 160 foreach (var group in product.RelatedGroups) 161 { 162 foreach (var relatedProduct in group.Products) 163 { 164 relateFromProductIds.Add(relatedProduct.ProductId); 165 } 166 } 167 } 168 } 169 170 //Create group id collection and products id collection strings 171 string groupIds = product is object ? product.PrimaryOrDefaultGroup.Id : string.Join(",", relateFromGroupIds); 172 string productVariantIds = relateFromProductVariantIds.Count > 0 ? string.Join(",", relateFromProductVariantIds) : ""; 173 string productIds = product is object && relateFromProductIds.Count == 0 ? product.Id : string.Join(",", relateFromProductIds); 174 175 //Set the parameters to the url 176 string linkParameters = ""; 177 linkParameters += sourceType != "related-products" && sourceType != "frequently" && sourceType != "selected" ? "&GroupId=" + groupIds : ""; 178 linkParameters += !string.IsNullOrEmpty(productIds) && sourceType != "most-sold" && sourceType != "trending" && sourceType != "latest" && sourceType != "frequently" ? "&MainProductId=" + productIds : ""; 179 linkParameters += sourceType == "variants" ? "&IsVariant=true" : ""; 180 linkParameters += sourceType == "latest" ? "&SortBy=Created" : ""; 181 linkParameters += sourceType == "most-sold" ? "&SortBy=OrderCount" : ""; 182 linkParameters += sourceType == "trending" ? "&SortBy=OrderCountGrowth" : ""; 183 linkParameters += !string.IsNullOrEmpty(productIds) && sourceType == "frequently" ? $"&BoughtWithProductIds=[{productIds}]" : ""; 184 var productListPageId = GetPageIdByNavigationTag("Shop"); 185 string link = "/Default.aspx?ID=" + productListPageId + linkParameters; 186 187 // Slider settings (documentation: swiffyslider.com/configuration) 188 string navigationStyle = $"{Model.Item.GetRawValueString("NavigationStyle", "slider-nav-round")}"; 189 string navigationPlacement = $"{Model.Item.GetRawValueString("NavigationPlacement", "slider-nav-on-slides")}"; 190 string indicatorStyle = $"{Model.Item.GetRawValueString("IndicatorStyle", "slider-indicators-hidden")}"; 191 string revealSlides = Model.Item.GetRawValueString("RevealSlides", "no-reveal") == "reveal" ? "slider-item-reveal" : string.Empty; 192 string navigationAlwaysVisible = (Model.Item.GetBoolean("NavigationAlwaysVisible")) ? "slider-nav-visible" : string.Empty; 193 string navigationVisibleOnTouch = (Model.Item.GetBoolean("NavigationVisibleOnTouch")) ? "slider-nav-touch" : string.Empty; 194 string navigationShowScrollbar = (Model.Item.GetBoolean("NavigationShowScrollbar")) ? "slider-nav-scrollbar" : string.Empty; 195 string navigationSmall = (Model.Item.GetBoolean("NavigationSmall")) ? "slider-nav-sm" : string.Empty; 196 string navigationInvertColors = (Model.Item.GetBoolean("NavigationInvertColors")) ? "slider-nav-dark" : string.Empty; 197 string navigationSlideEntirePage = (Model.Item.GetBoolean("NavigationSlideEntirePage")) ? "slider-nav-page" : string.Empty; 198 string navigationNoLoop = (Model.Item.GetBoolean("NavigationNoLoop")) ? "slider-nav-noloop" : string.Empty; 199 string indicatorsOutsideSlider = (Model.Item.GetBoolean("IndicatorsOutsideSlider") && indicatorStyle != string.Empty) ? "slider-indicators-outside" : string.Empty; 200 string indicatorsHighlightActive = (Model.Item.GetBoolean("IndicatorsHighlightActive")) ? "slider-indicators-highlight" : string.Empty; 201 string indicatorsInvertColors = (Model.Item.GetBoolean("IndicatorsInvertedColors")) ? "slider-indicators-dark" : string.Empty; 202 string indicatorsVisibleOnSmallDevices = (Model.Item.GetBoolean("IndicatorsVisibleOnSmallDevices")) ? "slider-indicators-sm" : string.Empty; 203 204 bool productsFound = true; 205 if (string.IsNullOrEmpty(groupIds) && string.IsNullOrEmpty(productIds)) 206 { 207 if (Pageview.IsVisualEditorMode) 208 { 209 productIds = product.Id; 210 sourceType = "selected"; 211 } 212 else 213 { 214 productsFound = false; 215 } 216 } 217 } 218 219 @*Container element for the request*@ 220 @if (productsFound) 221 { 222 <form method="post" action="@url" id="RelatedProductsForm_@Model.ID" data-response-target-element="RelatedProducts_@Model.ID" data-preloader="inline" data-update-url="false" class="item_@Model.Item.SystemName.ToLower()"> 223 <input type="hidden" name="ModelID" value="@Model.ID"> 224 <input type="hidden" name="SourceType" value="@sourceType"> 225 226 @*--- SLIDER SETTINGS ---*@ 227 <input type="hidden" name="NavigationStyle" value="@navigationStyle"> 228 <input type="hidden" name="NavigationPlacement" value="@navigationPlacement"> 229 <input type="hidden" name="IndicatorStyle" value="@indicatorStyle"> 230 <input type="hidden" name="RevealSlides" value="@revealSlides"> 231 <input type="hidden" name="NavigationAlwaysVisible" value="@(navigationAlwaysVisible)"> 232 <input type="hidden" name="NavigationVisibleOnTouch" value="@(navigationVisibleOnTouch)"> 233 <input type="hidden" name="NavigationShowScrollbar" value="@(navigationShowScrollbar)"> 234 <input type="hidden" name="NavigationSmall" value="@(navigationSmall)"> 235 <input type="hidden" name="NavigationInvertColors" value="@(navigationInvertColors)"> 236 <input type="hidden" name="NavigationNoLoop" value="@(navigationNoLoop)"> 237 <input type="hidden" name="NavigationSlideEntirePage" value="@(navigationSlideEntirePage)"> 238 <input type="hidden" name="IndicatorsOutsideSlider" value="@(indicatorsOutsideSlider)"> 239 <input type="hidden" name="IndicatorsHighlightActive" value="@(indicatorsHighlightActive)"> 240 <input type="hidden" name="IndicatorsInvertColors" value="@(indicatorsInvertColors)"> 241 <input type="hidden" name="IndicatorsVisibleOnSmallDevices" value="@(indicatorsVisibleOnSmallDevices)"> 242 243 @*--- VARIANTS ---*@ 244 @if (sourceType == "variants") 245 { 246 <input type="hidden" name="isVariant" value="true"> 247 <input type="hidden" name="MainProductID" id="MainProductID_@Model.ID" value="@productIds"> 248 } 249 250 @*--- MOST SOLD ---*@ 251 @if (sourceType == "most-sold") 252 { 253 <input type="hidden" name="SortBy" value="OrderCount"> 254 if (groupIds != "") 255 { 256 <input type="hidden" name="GroupId" value="@groupIds"> 257 } 258 } 259 260 @*--- TRENDING ---*@ 261 @if (sourceType == "trending") 262 { 263 <input type="hidden" name="SortBy" value="OrderCountGrowth"> 264 if (groupIds != "") 265 { 266 <input type="hidden" name="GroupId" value="@groupIds"> 267 } 268 } 269 270 @*--- FREQUENTLY BOUGHT ---*@ 271 @if (sourceType == "frequently" && !string.IsNullOrEmpty(productIds)) 272 { 273 <input type="hidden" name="BoughtWithProductIds" value="[@productIds]"> 274 } 275 276 @*--- LATEST ---*@ 277 @if (sourceType == "latest") 278 { 279 <input type="hidden" name="SortBy" value="Created"> 280 <input type="hidden" name="GroupId" value="@groupIds"> 281 } 282 283 @*--- SELECTED PRODUCTS ---*@ 284 @if (sourceType == "selected" && !string.IsNullOrEmpty(productIds) && !hasVariants) 285 { 286 <input type="hidden" name="MainProductId" id="MainProductID_@Model.ID" value="@productIds" /> 287 } 288 @if (sourceType == "selected" && hasVariants) 289 { 290 <input type="hidden" name="ProductVariantId" value="@productVariantIds" /> 291 } 292 293 @*--- RELATED PRODUCTS ---*@ 294 @if (sourceType == "related-products") 295 { 296 <input type="hidden" name="MainProductID" id="MainProductID_@Model.ID" value="@productIds"> 297 } 298 299 @* General parameters *@ 300 <input type="hidden" name="Link" value="@link" /> 301 <input type="hidden" name="HideTitle" value="@Model.Item.GetString("HideTitle")" /> 302 303 @if (Model.Item.GetInt32("ProductsCount") != 0) 304 { 305 <input type="hidden" name="PageSize" value="@Model.Item.GetInt32("ProductsCount")"> 306 } 307 <input type="hidden" name="HeadingTitle" id="RelatedProductsTitle_@Model.ID" value="@title"> 308 @if (!string.IsNullOrEmpty(Model.Item.GetString("Subtitle"))) 309 { 310 <input type="hidden" name="Subtitle" value="@Model.Item.GetString("Subtitle")"> 311 } 312 @if (!string.IsNullOrEmpty(Model.Item.GetString("LinkText"))) 313 { 314 <input type="hidden" name="LinkText" value="@Model.Item.GetString("LinkText")"> 315 } 316 @if (!string.IsNullOrEmpty(Model.Item.GetString("ImageAspectRatio"))) 317 { 318 string ratio = Model.Item.GetRawValueString("ImageAspectRatio", ""); 319 ratio = ratio != "0" ? ratio : ""; 320 <input type="hidden" name="ImageAspectRatio" value="@ratio"> 321 } 322 @if (!string.IsNullOrEmpty(Model.Item.GetString("Layout"))) 323 { 324 <input type="hidden" name="Layout" value="@Model.Item.GetRawValueString("Layout")"> 325 } 326 @if (titleFontSize != "") 327 { 328 <input type="hidden" name="TitleFontSize" value="@titleFontSize"> 329 } 330 @if (subtitleFontSize != "") 331 { 332 <input type="hidden" name="SubtitleFontSize" value="@subtitleFontSize"> 333 } 334 @if (buttonStyle != "") 335 { 336 <input type="hidden" name="ButtonStyle" value="@buttonStyle"> 337 } 338 @if (generalTheme != "") 339 { 340 <input type="hidden" name="GeneralTheme" value="@generalTheme"> 341 } 342 @if (theme != "") 343 { 344 <input type="hidden" name="Theme" value="@theme"> 345 } 346 @if (imageTheme != "") 347 { 348 <input type="hidden" name="ImageTheme" value="@imageTheme"> 349 } 350 @if (!string.IsNullOrEmpty(Model.Item.GetString("ContentPadding"))) 351 { 352 string contentPadding = Model.Item.GetRawValueString("ContentPadding"); 353 <input type="hidden" name="ContentPadding" value="@contentPadding"> 354 } 355 <input type="hidden" name="TextReadability" value="@maxWidth"> 356 <input type="hidden" name="ParentColumnSize" id="ParentColumnSize_@Model.ID" value="12"> 357 358 <input type="hidden" name="SaleBadgeType" value="@Model.Item.GetRawValue("SaleBadgeType")"> 359 <input type="hidden" name="SaleBadgeCssClassName" value="@Model.Item.GetRawValue("SaleBadgeDesign")"> 360 <input type="hidden" name="NewBadgeCssClassName" value="@Model.Item.GetRawValue("NewBadgeDesign")"> 361 <input type="hidden" name="NewPublicationDays" value="@Model.Item.GetInt32("NewPublicationDays")"> 362 363 @if (campaignValues != "") 364 { 365 <input type="hidden" name="CampaignBadgesValues" value="@campaignValues"> 366 } 367 </form> 368 369 <script type="module" src="~/Files/Templates/Designs/Swift/Assets/js/swiffy-slider.js"></script> 370 <script type="module"> 371 swift.AssetLoader.Load('/Files/Templates/Designs/Swift/Assets/css/swiffy-slider.min.css', 'css'); 372 </script> 373 374 if (Pageview.IsVisualEditorMode) 375 { 376 <div class="alert alert-info" role="alert"> 377 <span>@Translate("Product slider: Edit this column to configure")</span> 378 </div> 379 } 380 381 if (sourceType != "related-products") 382 { 383 <div class="w-100 h-100"> 384 <a id="@Model.ID" class="user-select-none" style="scroll-margin-top:var(--header-height,150px)"></a> 385 <div id="RelatedProducts_@Model.ID" class="h-100 swift_product_slider_container"></div> 386 </div> 387 } 388 else if (product?.RelatedGroups != null) 389 { 390 @* Create multiple slider containers, if type is Product relation *@ 391 <div class="grid w-100 h-100@(generalTheme)" style="grid-row-gap: 4rem"> 392 <a id="@Model.ID" class="user-select-none" style="scroll-margin-top:var(--header-height,150px)"></a> 393 @foreach (var group in product.RelatedGroups) 394 { 395 <div id="RelatedProducts_@(Model.ID)_@group.Id" class="g-col-12 h-100 swift_product_slider_container"></div> 396 } 397 </div> 398 } 399 400 @* Initialize *@ 401 if (sourceType != "related-products") 402 { 403 <script type="module"> 404 if (document.querySelector("#RelatedProducts_@Model.ID").closest("[data-col-size]")) { 405 document.querySelector("#ParentColumnSize_@Model.ID").value = document.querySelector("#RelatedProducts_@Model.ID").closest("[data-col-size]").getAttribute("data-col-size"); 406 } 407 swift.PageUpdater.Update(document.querySelector("#RelatedProductsForm_@Model.ID")).then(function () { 408 setTimeout(function() { 409 const isVisualEditor = @(Converter.ToString(Pageview.IsVisualEditorMode).ToLowerInvariant()); 410 const productSliderContainer = document.querySelector(".swift_product_slider_container"); 411 412 if (productSliderContainer && productSliderContainer.innerHTML !== "") { 413 productSliderContainer.classList.remove("d-none"); 414 } 415 else if (!isVisualEditor) { 416 productSliderContainer.closest("[class*=column]").classList.add("d-none"); 417 } 418 }, 150); 419 }); 420 </script> 421 } 422 else if (product?.RelatedGroups != null) 423 { 424 @* Create multiple sliders, if type is Product relation *@ 425 foreach (var group in product.RelatedGroups) 426 { 427 IList<string> fromProductIds = new List<string> { }; 428 429 foreach (var relatedProduct in group.Products) 430 { 431 fromProductIds.Add(relatedProduct.ProductId); 432 } 433 <script type="module"> 434 document.querySelector("#ParentColumnSize_@Model.ID").value = document.querySelector("#RelatedProducts_@(Model.ID)_@group.Id").closest("[data-col-size]").getAttribute("data-col-size"); 435 document.querySelector("#MainProductID_@Model.ID").value = "@string.Join(",", fromProductIds)"; 436 document.querySelector("#RelatedProductsTitle_@Model.ID").value = "@group.Name"; 437 document.querySelector("#RelatedProductsForm_@Model.ID").setAttribute("data-response-target-element", "RelatedProducts_@(Model.ID)_@group.Id"); 438 439 swift.PageUpdater.Update(document.querySelector("#RelatedProductsForm_@Model.ID")); 440 </script> 441 } 442 } 443 } 444
By clicking 'Accept All' you consent that we may collect information about you for various purposes, including: Functionality, Statistics and Marketing