huge
6.599,00 kr.
OutOfStock
Error executing template "Designs/Swift/Components/VariantSelector_Custom.cshtml" System.NullReferenceException: Object reference not set to an instance of an object. at Dynamicweb.Ecommerce.Products.ProductExtentions.GetIsVariantMaster(Product product) at CompiledRazorTemplates.Dynamic.RazorEngine_f495584c1b034519a1279cb0bf0e05a8.ExecuteAsync() at RazorEngine.Templating.TemplateBase.Run(ExecuteContext context, TextWriter reader) at RazorEngine.Templating.RazorEngineCore.RunTemplate(ICompiledTemplate template, TextWriter writer, Object model, DynamicViewBag viewBag) at RazorEngine.Templating.RazorEngineService.Run(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag) at RazorEngine.Templating.DynamicWrapperService.Run(ITemplateKey key, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag) at RazorEngine.Templating.RazorEngineServiceExtensions.Run(IRazorEngineService service, String name, TextWriter writer, Type modelType, Object model, DynamicViewBag viewBag) at RazorEngine.Templating.RazorEngineServiceExtensions.<>c__DisplayClass23_0.<Run>b__0(TextWriter writer) at RazorEngine.Templating.RazorEngineServiceExtensions.WithWriter(Action`1 withWriter) at RazorEngine.Templating.RazorEngineServiceExtensions.Run(IRazorEngineService service, String name, Type modelType, Object model, DynamicViewBag viewBag) 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 @using Dynamicweb.Frontend 7 @using Dynamicweb.Ecommerce.Products 8 9 @functions { 10 //Find contrast color (white, black) 11 public static string GetContrastColor(string hexString) 12 { 13 System.Drawing.Color bg = System.Drawing.ColorTranslator.FromHtml(hexString); 14 15 int nThreshold = 105; 16 int bgDelta = Convert.ToInt32((bg.R * 0.299) + (bg.G * 0.587) + 17 (bg.B * 0.114)); 18 19 string foreColor = (255 - bgDelta < nThreshold) ? "#333" : "#fff"; 20 return foreColor; 21 } 22 23 public string GetLayoutForVariantGroup(string variantGroupId) 24 { 25 string showVariantGroups = Model.Item?.GetRawValueString("ShowVariantGroupOptions"); 26 var selectedVariantGroupsList = Model.Item?.GetItems("VariantGroups") ?? new List<ItemViewModel>(); 27 bool showAllVariantGroupsDefault = string.IsNullOrEmpty(showVariantGroups) || selectedVariantGroupsList == null || !selectedVariantGroupsList.Any(); 28 string defaultVariantGroupLayout = Model.Item?.GetRawValueString("DefaultVariantGroupLayout"); 29 defaultVariantGroupLayout = !string.IsNullOrEmpty(defaultVariantGroupLayout) ? defaultVariantGroupLayout : "button"; 30 31 if (showAllVariantGroupsDefault) return defaultVariantGroupLayout; 32 33 foreach (var selectedVariantGroupListItem in selectedVariantGroupsList) 34 { 35 var variantGroups = selectedVariantGroupListItem.GetList("VariantGroups").GetRawValue().OfType<string>().ToList(); 36 if (variantGroups.Any(s => s.Equals(variantGroupId))) return selectedVariantGroupListItem.GetRawValueString("VariantGroupLayout"); 37 } 38 39 return defaultVariantGroupLayout; 40 } 41 42 //Collect all variant images 43 public static Dictionary<string, string> GetVariantImages(List<VariantInfoViewModel> variantInfo, Dictionary<string, string> list) 44 { 45 foreach (var variantGroup in variantInfo) 46 { 47 if (variantGroup.Image?.Value != null && !list.ContainsKey(variantGroup.OptionID)) 48 { 49 list.Add(variantGroup.OptionID, variantGroup.Image.Value); 50 } 51 52 if (variantGroup.VariantInfo != null) 53 { 54 GetVariantImages(variantGroup.VariantInfo, list); 55 } 56 } 57 58 return list; 59 } 60 61 private string GetDefaultOrVariantGroupValue(string variantGroupId, string itemField, string itemFieldDefaultValue, Dictionary<string, string> fieldValueMapping) 62 { 63 if (!string.IsNullOrEmpty(variantGroupId)) 64 { 65 string itemFieldValue = Model.Item?.GetRawValueString(itemField, itemFieldDefaultValue); 66 string itemFieldParameter = GetViewParameterString(itemField); 67 itemFieldValue = string.IsNullOrEmpty(itemFieldValue) && !string.IsNullOrEmpty(itemFieldParameter) ? itemFieldParameter : itemFieldValue; 68 69 if (fieldValueMapping != null && !string.IsNullOrEmpty(itemFieldValue) && fieldValueMapping.Any()) 70 { 71 itemFieldValue = fieldValueMapping.ContainsKey(itemFieldValue) ? fieldValueMapping[itemFieldValue] : itemFieldValue; 72 } 73 74 // If no variantGroup (i.e. Visual Editor), return default value 75 if (string.IsNullOrEmpty(variantGroupId)) return itemFieldValue; 76 77 string showVariantGroups = Model.Item?.GetString("ShowVariantGroupOptions", "all"); 78 var selectedVariantGroupsList = Model.Item?.GetItems("VariantGroups") ?? new List<ItemViewModel>(); 79 // If no exceptions or settings are all the same, return default value 80 if (showVariantGroups == "all" || selectedVariantGroupsList == null || !selectedVariantGroupsList.Any()) return itemFieldValue; 81 82 // Get specific value for variant group 83 foreach (var selectedVariantGroupListItem in selectedVariantGroupsList) 84 { 85 var variantGroups = selectedVariantGroupListItem.GetList("VariantGroups").GetRawValue().OfType<string>().ToList(); 86 if (!variantGroups.Any(s => s.Equals(variantGroupId))) continue; 87 88 itemFieldValue = selectedVariantGroupListItem.GetRawValueString(itemField, itemFieldDefaultValue); 89 itemFieldValue = fieldValueMapping.ContainsKey(itemFieldValue) ? fieldValueMapping[itemFieldValue] : itemFieldValue; 90 } 91 92 return itemFieldValue; 93 } 94 else 95 { 96 return string.Empty; 97 } 98 } 99 100 private bool GetDefaultOrVariantGroupValue(string variantGroupId, string itemField) 101 { 102 if (!string.IsNullOrEmpty(variantGroupId)) 103 { 104 bool itemFieldValue = Model.Item?.GetBoolean(itemField) ?? false; 105 106 // If no variantGroup (i.e. Visual Editor), return default value 107 if (string.IsNullOrEmpty(variantGroupId)) return itemFieldValue; 108 109 string showVariantGroups = Model.Item?.GetString("ShowVariantGroupOptions", "all"); 110 var selectedVariantGroupsList = Model.Item?.GetItems("VariantGroups") ?? new List<ItemViewModel>(); 111 // If no exceptions or settings are all the same, return default value 112 if (showVariantGroups == "all" || selectedVariantGroupsList == null || !selectedVariantGroupsList.Any()) return itemFieldValue; 113 114 // Get specific value for variant group 115 foreach (var selectedVariantGroupListItem in selectedVariantGroupsList) 116 { 117 var variantGroups = selectedVariantGroupListItem.GetList("VariantGroups").GetRawValue().OfType<string>().ToList(); 118 if (!variantGroups.Any(s => s.Equals(variantGroupId))) continue; 119 120 itemFieldValue = selectedVariantGroupListItem.GetBoolean(itemField); 121 } 122 123 return itemFieldValue; 124 } 125 else 126 { 127 return false; 128 } 129 } 130 } 131 132 @{ 133 ProductViewModel product = null; 134 if (Dynamicweb.Context.Current.Items.Contains("ProductDetails")) 135 { 136 product = (ProductViewModel)Dynamicweb.Context.Current.Items["ProductDetails"]; 137 } 138 else if (Pageview.Page.Item["DummyProduct"] != null && Pageview.IsVisualEditorMode) 139 { 140 var pageViewModel = Dynamicweb.Frontend.ContentViewModelFactory.CreatePageInfoViewModel(Pageview.Page); 141 ProductListViewModel productList = pageViewModel.Item.GetValue("DummyProduct") != null ? pageViewModel.Item.GetValue("DummyProduct") as ProductListViewModel : new ProductListViewModel(); 142 143 if (productList?.Products is object) 144 { 145 product = productList.Products[0]; 146 } 147 } 148 //CUSTOM CODE 149 string baseURL = string.Empty; 150 } 151 152 @if ((product is object)) 153 { 154 155 bool hideGroupHeaders = !string.IsNullOrEmpty(Model?.Item?.GetString("HideGroupHeaders")) ? Model.Item.GetBoolean("HideGroupHeaders") : false; 156 var productVariantGroups = product.VariantGroups(); 157 158 string itemId = Model?.Item?.SystemName != null ? $"item_{Model.Item.SystemName.ToLower()}" : string.Empty; 159 160 bool isModalSelector = Model?.Item == null; 161 string target = isModalSelector ? "data-response-target-element=\"DynamicModalContent\"" : string.Empty; 162 163 string variantSelectorServicePageId = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form.Get("VariantSelectorServicePage")) ? Dynamicweb.Context.Current.Request.Form.Get("VariantSelectorServicePage") : string.Empty; 164 string formAction = isModalSelector ? $"action=\"/Default.aspx?ID={variantSelectorServicePageId}\"" : string.Empty; 165 166 string getProductInfo = !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.Form["getproductinfo"]) ? Dynamicweb.Context.Current.Request.Form["getproductinfo"] : string.Empty; 167 168 if (productVariantGroups.Any() && product?.VariantInfo?.VariantInfo != null) 169 { 170 string[] variantId = product.VariantId.Split('.'); 171 int groupNumber = 1; 172 173 string baseUrl = $"Default.aspx?ID={GetPageIdByNavigationTag("Shop")}&GroupID={product.PrimaryOrDefaultGroup.Id}&ProductID={product.Id}"; 174 string variantUrl = string.Empty; 175 if (!string.IsNullOrEmpty(product.VariantId) && !isModalSelector) 176 { 177 variantUrl = Dynamicweb.Frontend.SearchEngineFriendlyURLs.GetFriendlyUrl($"Default.aspx?ID={GetPageIdByNavigationTag("Shop")}&GroupID={product.PrimaryOrDefaultGroup.Id}&ProductID={product.Id}&VariantID={product.VariantId}"); 178 } 179 // CUSTOM CODE 180 baseURL = $"/Default.aspx?ID={GetPageIdByNavigationTag("Shop")}&GroupID={product.PrimaryOrDefaultGroup.Id}&ProductID={product.Id}&VariantID="; 181 Dictionary<string, string> variantImages = new Dictionary<string, string>(); 182 variantImages = GetVariantImages(product.VariantInfo.VariantInfo, variantImages); 183 184 <form @formAction class="d-flex flex-column gap-2 js-variant-selector @itemId" @target data-combinations="@string.Join(",", product.VariantCombinations())" data-base-url="@baseUrl" data-friendly-url="@variantUrl"> 185 @if (isModalSelector) 186 { 187 <input type="hidden" name="productId" value="@product.Id"> 188 <input type="hidden" name="variantid" value="@product.VariantId"> 189 <input type="hidden" name="QuantitySelector" value="true"> 190 <input type="hidden" name="VariantSelectorServicePage" value="@variantSelectorServicePageId"> 191 <input type="hidden" name="ViewType" value="ModalContent"> 192 193 if (GetViewParameter("ButtonLayout") != null) 194 { 195 <input type="hidden" name="ButtonLayout" value="@GetViewParameter("ButtonLayout")"> 196 } 197 198 if (GetViewParameter("ButtonAspectRatio") != null) 199 { 200 <input type="hidden" name="ButtonAspectRatio" value="@GetViewParameter("ButtonAspectRatio")"> 201 } 202 203 if (!string.IsNullOrEmpty(getProductInfo)) 204 { 205 <input type="hidden" name="getproductinfo" value="@getProductInfo"> 206 } 207 } 208 209 @foreach (var variantGroup in productVariantGroups) 210 { 211 VariantGroupViewModel group = variantGroup; 212 string variantGroupLayout = GetLayoutForVariantGroup(variantGroup.Id) ?? "button"; 213 string horizontalAlign = GetDefaultOrVariantGroupValue(variantGroup.Id, "HorizontalAlignment", "", new Dictionary<string, string> { { "center", "justify-content-center" }, { "end", "justify-content-end" } }); 214 string horizontalTextAlign = GetDefaultOrVariantGroupValue(variantGroup.Id, "HorizontalAlignment", "", new Dictionary<string, string> { { "center", "text-center" }, { "end", "text-end" } }); 215 bool showSelectedOptionName = GetDefaultOrVariantGroupValue(variantGroup.Id, "ShowSelectedOptionName"); 216 217 <div> 218 @if (!hideGroupHeaders) 219 { 220 <h3 class="h6 @horizontalTextAlign"> 221 @group.Name 222 223 @if (showSelectedOptionName) 224 { 225 string selectedOptionName = group.Options.FirstOrDefault(opt => variantId.Contains(opt.Id))?.Name ?? string.Empty; 226 <span class="fw-light px-1 swift-selected-option-name">@selectedOptionName</span> 227 } 228 </h3> 229 } 230 <div class="d-flex gap-2 @horizontalAlign flex-wrap js-variant-group" data-group-id="@groupNumber"> 231 @if (variantGroupLayout == "button") 232 { 233 234 foreach (var option in group.Options) 235 { 236 @* CUSTOM CODE *@ 237 string productColor = product.VariantId.Split('.').FirstOrDefault() ?? ""; 238 string productSize = option.Id.Split('.').LastOrDefault() ?? ""; 239 string variantCombination = productColor + "." + productSize; 240 Product currentOptionProduct = Dynamicweb.Ecommerce.Services.Products.GetProductById(product.Id, variantCombination, Pageview.Area.EcomLanguageId); 241 242 bool isVariantMaster = currentOptionProduct.GetIsVariantMaster(); 243 244 Dictionary<string, bool> hasValidVariantOptionsByMaster = new Dictionary<string, bool>(); 245 Dictionary<string, List<string>> validSizesByColorId = new Dictionary<string, List<string>>(); 246 if (isVariantMaster) 247 { 248 var allVariantsOfMasterProduct = Dynamicweb.Ecommerce.Services.Products.GetProductsAndVariantsByProduct(currentOptionProduct).ToList(); 249 List<string> validVariantsList = new List<string>(); 250 251 foreach (var variant in allVariantsOfMasterProduct) 252 { 253 var colorId = variant.VariantId.Split('.').First() ?? ""; 254 if (!string.IsNullOrEmpty(colorId) && !hasValidVariantOptionsByMaster.ContainsKey(colorId)) 255 { 256 hasValidVariantOptionsByMaster[colorId] = false; 257 foreach (var variantProduct in allVariantsOfMasterProduct) 258 { 259 if (variantProduct.VariantId.Contains(colorId)) 260 { 261 if (variantProduct.Stock > 0) 262 { 263 if (!validSizesByColorId.ContainsKey(colorId)) 264 { 265 validSizesByColorId.Add(colorId, new List<string>()); 266 } 267 hasValidVariantOptionsByMaster[colorId] = true; 268 validSizesByColorId[colorId].Add(variantProduct.VariantId); 269 } 270 } 271 } 272 } 273 274 } 275 276 277 } 278 279 bool isOptionProductOutOfStock = currentOptionProduct.Stock <= 0 ? true : false; 280 var skipMaster = true; 281 282 foreach (var item in hasValidVariantOptionsByMaster) 283 { 284 if (item.Value) 285 { 286 if (option.Id.Contains(item.Key)) 287 { 288 skipMaster = false; 289 } 290 291 } 292 } 293 294 if (isVariantMaster && skipMaster) 295 { 296 continue; 297 } 298 299 if (!isVariantMaster && currentOptionProduct.Stock <= 0) 300 { 301 continue; 302 } 303 304 if (isVariantMaster && !validSizesByColorId.ContainsKey(option.Id)) 305 { 306 continue; 307 } 308 309 @* END OF CUSTOM CODE *@ 310 311 string active = variantId != null && variantId.Contains(option.Id) ? "active" : string.Empty; 312 string buttonId = $"{product.Id}_{option.Id}_{Pageview.CurrentParagraph.ID}"; 313 string contrastColor = string.Empty; 314 string buttonAspectRatio = GetDefaultOrVariantGroupValue(variantGroup.Id, "ButtonAspectRatio", "100%", new Dictionary<string, string> { { "100%", "--bs-aspect-ratio:100%" }, { "56%", "--bs-aspect-ratio:56%" }, { "177%", "--bs-aspect-ratio:177%" }, { "75%", "--bs-aspect-ratio:75%" }, { "133%", "--bs-aspect-ratio:133%" } }); 315 buttonAspectRatio = buttonAspectRatio == string.Empty ? "--bs-aspect-ratio:100%" : buttonAspectRatio; 316 317 string buttonLayout = GetDefaultOrVariantGroupValue(variantGroup.Id, "ButtonLayout", "rounded-circle", new Dictionary<string, string> { { "round", "rounded-circle" }, { "square", "rounded-0" }, { "square-rounded", "rounded-3" } }); 318 string buttonTextLayout = GetDefaultOrVariantGroupValue(variantGroup.Id, "ButtonTextLayout", "", new Dictionary<string, string> { { "default", "" }, { "square", "rounded-0" }, { "square-rounded", "rounded-3" } }); 319 var displayType = group.DisplayType; 320 displayType = displayType == VariantGroupDisplayType.NothingSelected && !string.IsNullOrEmpty(option.Color) ? VariantGroupDisplayType.VariantColor : displayType; 321 displayType = displayType == VariantGroupDisplayType.NothingSelected && string.IsNullOrEmpty(option.OptionImage.Value) && string.IsNullOrEmpty(option.Color) ? VariantGroupDisplayType.VariantName : displayType; 322 displayType = displayType == VariantGroupDisplayType.NothingSelected && !string.IsNullOrEmpty(option.OptionImage.Value) ? VariantGroupDisplayType.VariantOptionImage : displayType; 323 324 var btnWidth = displayType == VariantGroupDisplayType.VariantColor || displayType == VariantGroupDisplayType.VariantImage || displayType == VariantGroupDisplayType.VariantOptionImage ? $"style=\"width:64px\"" : string.Empty; 325 var btnClasses = string.Empty; 326 327 btnClasses = displayType == VariantGroupDisplayType.VariantColor ? $"overflow-hidden colorbox colorbox-auto p-0 border {buttonLayout}" : btnClasses; 328 btnClasses = displayType == VariantGroupDisplayType.VariantImage ? $"overflow-hidden p-0 {buttonLayout}" : btnClasses; 329 btnClasses = displayType == VariantGroupDisplayType.VariantOptionImage ? $"overflow-hidden colorbox colorbox-auto {buttonLayout} p-0" : btnClasses; 330 btnClasses = displayType == VariantGroupDisplayType.VariantName ? $"btn-secondary {buttonTextLayout}" : btnClasses; 331 332 var variantOptions = product.VariantId.Split("."); 333 334 string? selectedVariant = variantOptions.LastOrDefault(); 335 string? selectedMasterVariant = variantOptions.FirstOrDefault(); 336 337 <button type="button" 338 class="btn @btnClasses d-inline-block variant-option js-variant-option @active @(isVariantMaster ? "is-master" : string.Empty) @(isOptionProductOutOfStock ? "product-out-of-stock" : string.Empty)" @btnWidth 339 onclick="swift.VariantSelector.OptionClick(event)" 340 data-selected-master-variant="@selectedMasterVariant" 341 data-selectedvariant="@selectedVariant" 342 data-variant-id="@option.Id" id="@(product.Id)_@(option.Id)_@Pageview.CurrentParagraph.ID" 343 @(isVariantMaster ? "data-validvariants=" + string.Join(",", validSizesByColorId[option.Id]) : string.Empty)> 344 <div class="@(displayType == VariantGroupDisplayType.VariantName ? string.Empty : "ratio")" style="@(buttonAspectRatio)"> 345 346 @switch (displayType) 347 { 348 case VariantGroupDisplayType.VariantOptionImage: 349 if (!string.IsNullOrEmpty(option.OptionImage.Value)) 350 { 351 <img style="object-fit:cover;--variantoption-check-color:@(contrastColor)" src="/Admin/Public/GetImage.ashx?image=@(option.OptionImage.Value)&width=64&format=webp"> 352 } 353 else if (!string.IsNullOrEmpty(option.Color)) 354 { 355 <span class="" style="background-color:@(option.Color);--variantoption-check-color:@(contrastColor)"><span class="visually-hidden">@option.Color</span></span> 356 } 357 else 358 { 359 <span class="d-flex align-items-center justify-content-center">@(option.Name)</span> 360 } 361 break; 362 363 case VariantGroupDisplayType.VariantImage: 364 string variantImage = string.Empty; 365 variantImages.TryGetValue(option.Id, out variantImage); 366 <img class="theme" style="object-fit:contain" src="/Admin/Public/GetImage.ashx?image=@(variantImage)&width=64&format=webp"> 367 break; 368 369 case VariantGroupDisplayType.VariantColor: 370 contrastColor = GetContrastColor(option.Color); 371 <span class="" style="background-color:@(option.Color);--variantoption-check-color:@(contrastColor)"><span class="visually-hidden">@option.Color</span></span> 372 break; 373 374 case VariantGroupDisplayType.VariantName: 375 <span class="d-flex align-items-center justify-content-center">@(option.Name)</span> 376 break; 377 378 } 379 </div> 380 </button> 381 } 382 } 383 else 384 { 385 <select class="form-select" id="VariantDropdown_@variantGroup.Id" aria-label="@variantGroup.Name" onchange="swift.VariantSelector.OptionClick(event)"> 386 @if (string.IsNullOrEmpty(product.VariantId)) 387 { 388 <option value="" class="variant-option js-variant-option" data-variant-id="">@Translate("Nothing selected")</option> 389 } 390 391 @foreach (var option in variantGroup.Options) 392 { 393 string active = variantId != null && variantId.Contains(option.Id) ? "active" : ""; 394 var selected = variantId != null && variantId.Contains(option.Id) ? "selected" : ""; 395 var value = $"{product.Id}_{option.Id}"; 396 397 <option value="@(value)" class="variant-option js-variant-option @active" data-variant-id="@option.Id" id="@(value)_@(Pageview.CurrentParagraph.ID)" @selected>@option.Name</option> 398 } 399 </select> 400 } 401 </div> 402 </div> 403 404 groupNumber++; 405 } 406 </form> 407 408 <script type="module"> 409 swift.VariantSelector.init(); 410 </script> 411 } 412 else if (Pageview.IsVisualEditorMode) 413 { 414 string horizontalAlign = GetDefaultOrVariantGroupValue("", "HorizontalAlignment", "", new Dictionary<string, string> { { "center", "justify-content-center" }, { "end", "justify-content-end" } }); 415 string horizontalTextAlign = GetDefaultOrVariantGroupValue("", "HorizontalAlignment", "", new Dictionary<string, string> { { "center", "text-center" }, { "end", "text-end" } }); 416 417 <form class="d-flex flex-column js-variant-selector @itemId" data-combinations="VO1,VO2,VO3,VO4"> 418 <div> 419 @if (!hideGroupHeaders) 420 { 421 <h3 class="h6 @horizontalTextAlign">@Translate("Sizes")</h3> 422 } 423 <div class="mb-3 @horizontalAlign js-variant-group" data-group-id="0"> 424 <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> 425 <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> 426 <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> 427 <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> 428 </div> 429 </div> 430 </form> 431 432 <script type="module"> 433 swift.VariantSelector.init(); 434 </script> 435 } 436 } 437 else if (Pageview.IsVisualEditorMode) 438 { 439 <div class="alert alert-dark m-0" role="alert"> 440 <span>@Translate("No products available")</span> 441 </div> 442 } 443 @*CUSTOM CODE*@ 444 <style> 445 .disabled-option { 446 pointer-events: none; 447 opacity: 0.5; 448 cursor: not-allowed; 449 } 450 </style> 451 452 <script> 453 document.addEventListener('DOMContentLoaded', () => { 454 455 function selectFirstSizeIfNone(target) { 456 const context = target || document; 457 const sizeGroup = context.querySelector('.js-variant-group[data-group-id="2"]'); 458 if (!sizeGroup) return; 459 460 const activeSize = sizeGroup.querySelector('.js-variant-option.active'); 461 if (!activeSize) { 462 const firstSizeButton = sizeGroup.querySelector('.js-variant-option[data-variant-id]'); 463 if (firstSizeButton) { 464 465 setTimeout(() => firstSizeButton.click(), 1); 466 } 467 } 468 } 469 const hideInactiveVariants = () => { 470 const elements = document.querySelectorAll('.variant-option.in-active:not(option)'); 471 elements.forEach(element => { 472 const validVariants = element.dataset.validvariants ? element.dataset.validvariants.split(',') : ''; 473 if (validVariants.length > 0) { 474 element.classList.remove('in-active'); 475 return; 476 } else { 477 element.classList.add('disabled-option'); 478 } 479 480 }); 481 } 482 hideInactiveVariants(); 483 484 selectFirstSizeIfNone(); 485 486 487 document.addEventListener("updated.swift.pageupdater", (e) => { 488 selectFirstSizeIfNone(e.target); 489 hideInactiveVariants(); 490 }); 491 492 }); 493 </script> 494 @*END OF CUSTOM CODE*@
Ikke på lager
• Hvis varen er på lager, så findes den også i vores fysiske butik - Vester Voldgade 5, 1552 København
Hvorfor skal du handle på troelstrup.com?
Få fri fragt
30 dages returret
Bliv en del af Troelstrup Exclusive
Beskrivelse
Yderligere information
- Vævet med et diskret mønster
- Hakrevers
- Slank pasform
- Antal knapper: 2
- Lukning med hægte og lynlås
Detaljer
Specifikationer
| Foring | Helforet |
| Lukninger | Enkeltradet med to-knaplukning |
| Revers | Hakrevers |
| Slids | Dobbelt slids |
| Artikel | 50557268 |
| Materiale sammensætning | 52% bomuld 48% uld |
| Model | habit |