50300201
Lejeblok PMC 20
Error executing template "Designs/Swift/Paragraph/Swift_ProductSpecification.cshtml" System.NullReferenceException: Object reference not set to an instance of an object. at Dynamicweb.Ecommerce.Products.GroupRelation.GetGroupRelationsByChildId(String childId) at Dynamicweb.Ecommerce.Products.Categories.ProductCategoryFieldGroupValueService.GetOrderedInheritableParentIds(Group group, String defaultLanguageId) at Dynamicweb.Ecommerce.Products.Categories.ProductCategoryFieldGroupValueService.RecursivelySearchForFieldValues(Group group, String defaultLanguageId, List`1 categoryFields) at Dynamicweb.Ecommerce.Products.Categories.ProductCategoryFieldGroupValueService.RecursivelySearchForFieldValues(Group group, String defaultLanguageId, List`1 categoryFields) at System.Lazy`1.CreateValue() at System.Lazy`1.LazyInitValue() at Dynamicweb.Ecommerce.Products.Categories.ProductCategoryFieldGroupValueService.GetGroupFieldValuesByLanguage(Group group, List`1 categoryFields, String languageId, Boolean isInheritedValue, Boolean searchRecursively) at Dynamicweb.Ecommerce.Products.Categories.ProductCategoryFieldGroupValueService.SearchForGroupFieldValue(Group group, List`1 categoryFields, Boolean allowFallback) at Dynamicweb.Ecommerce.Products.Categories.ProductCategoryFieldGroupValueService.GetGroupCategoryFieldValues(IEnumerable`1 groups, List`1 fields, Boolean allowFallback) at Dynamicweb.Ecommerce.Products.Categories.ProductCategoryFieldGroupValueService.GetDefaultCategoryValuesFromGroups(IEnumerable`1 groupInfos, List`1 catFields) at Dynamicweb.Ecommerce.Products.Categories.ProductCategoryFieldGroupValueService.GetDefaultCategoryValueFromGroups(IEnumerable`1 groupInfos, Field catField) at Dynamicweb.Ecommerce.Products.Categories.ProductCategoryFieldValueService.GetCategoryValue(Product product, String defaultLanguageId, IEnumerable`1 orderedGroups, Field catField, Boolean includeInheritance) at Dynamicweb.Ecommerce.Products.Categories.ProductCategoryFieldValueService.GetCategoryValue(Product product, String categoryId, String fieldId, Boolean includeInheritance) at Dynamicweb.Ecommerce.Products.Categories.ProductCategoryFieldValueService.GetProductCategoryFieldValue(Product product, String categoryId, Field field) at Dynamicweb.Ecommerce.ProductCatalog.ViewEngine.CreateView(ProductViewModelSettings settings, Product product, Field field) at Dynamicweb.Ecommerce.ProductCatalog.ViewEngine.GetFieldDisplayGroupValues(ProductViewModelSettings settings, Product product, String languageID, Lazy`1 productIds) at Dynamicweb.Ecommerce.ProductCatalog.ViewEngine.<>c__DisplayClass3_1.<BulkCreateView>b__60() at System.Lazy`1.CreateValue() at System.Lazy`1.LazyInitValue() at CompiledRazorTemplates.Dynamic.RazorEngine_54a13b9c536b4040961bc7c230086980.Execute() in D:\dynamicweb.net\Solutions\brdklee.cloud.dynamicweb-cms.com\files\Templates\Designs\Swift\Paragraph\Swift_ProductSpecification.cshtml:line 59 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 System.Globalization; 4 @functions 5 { 6 public static class NumberHelper 7 { 8 /// <summary> 9 /// Converts a scientific notation string with a comma (e.g. "5,8E-05") to a decimal. 10 /// Returns 0 if the string is invalid or empty. 11 /// </summary> 12 public static decimal ToDecimal(string input) 13 { 14 if (string.IsNullOrWhiteSpace(input)) 15 { 16 return 0m; 17 } 18 19 // Tell the parser to look for a comma 20 var format = new NumberFormatInfo { NumberDecimalSeparator = "," }; 21 22 // TryParse safely attempts to convert without throwing exceptions on bad data 23 if (decimal.TryParse(input, NumberStyles.Float, format, out decimal result)) 24 { 25 return result; 26 } 27 28 return 0m; // Return a default value if parsing fails 29 } 30 } 31 } 32 @{ 33 ProductViewModel product = null; 34 if (Dynamicweb.Context.Current.Items.Contains("ProductDetails")) 35 { 36 product = (ProductViewModel)Dynamicweb.Context.Current.Items["ProductDetails"]; 37 } 38 else if (Pageview.Page.Item["DummyProduct"] != null && Pageview.IsVisualEditorMode) 39 { 40 var pageViewModel = Dynamicweb.Frontend.ContentViewModelFactory.CreatePageInfoViewModel(Pageview.Page); 41 ProductListViewModel productList = pageViewModel.Item.GetValue("DummyProduct") != null ? pageViewModel.Item.GetValue("DummyProduct") as ProductListViewModel : new ProductListViewModel(); 42 43 if (productList?.Products is object) 44 { 45 product = productList.Products[0]; 46 } 47 } 48 } 49 50 @if (product is object && Model?.Item != null) 51 { 52 var displayGroupsRaw = Model.Item.GetRawValueString("DisplayGroups") ?? ""; 53 IEnumerable<string> selectedDisplayGroupIds = 54 displayGroupsRaw.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); 55 List<CategoryFieldViewModel> displayGroups = new List<CategoryFieldViewModel>(); 56 57 foreach (var selection in selectedDisplayGroupIds) 58 { 59 foreach (CategoryFieldViewModel group in product.FieldDisplayGroups?.Values ?? Enumerable.Empty<CategoryFieldViewModel>()) 60 { 61 if (selection == group.Id) 62 { 63 int fieldsWithNoValueOrZero = 0; 64 65 foreach (var field in group.Fields) 66 { 67 var value = field.Value?.Value?.ToString(); 68 69 if (string.IsNullOrWhiteSpace(value)) 70 { 71 fieldsWithNoValueOrZero++; 72 } 73 } 74 75 if (fieldsWithNoValueOrZero != group.Fields.Count) 76 { 77 displayGroups.Add(group); 78 } 79 } 80 } 81 } 82 83 bool showProductFields = Model.Item.GetBoolean("ProductFields"); 84 85 bool hideTitle = Model.Item.GetBoolean("HideTitle"); 86 87 string theme = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("Theme")) ? " theme " + Model.Item.GetRawValueString("Theme").Replace(" ", "").Trim().ToLower() : ""; 88 89 string titleFontSize = Model.Item.GetRawValueString("TitleFontSize", "display-4"); 90 91 string contentPadding = Model.Item.GetRawValueString("ContentPadding", ""); 92 contentPadding = contentPadding == "none" ? string.Empty : contentPadding; 93 contentPadding = contentPadding == "small" ? " p-2 p-md-3" : contentPadding; 94 contentPadding = contentPadding == "large" ? " p-4 p-md-5" : contentPadding; 95 96 string layout = Model.Item.GetRawValueString("Layout", "list"); 97 string size = Model.Item.GetRawValueString("Size", "full"); 98 string gaps = size == "full" ? " gap-4" : " gap-2"; 99 100 101 if (Pageview.IsVisualEditorMode && displayGroups.Count() == 0) 102 { 103 product.ProductFields.Clear(); 104 product.ProductFields.Add(Translate("Width"), new FieldValueViewModel { Name = Translate("Width"), Value = "99cm" }); 105 product.ProductFields.Add(Translate("Height"), new FieldValueViewModel { Name = Translate("Height"), Value = "195cm" }); 106 showProductFields = true; 107 } 108 109 if (layout == "commas") 110 { 111 gaps = size == "full" ? " gap-4" : " gap-2"; 112 113 } 114 115 <div class="h-100@(gaps)@(theme)@(contentPadding) item_@Model.Item.SystemName.ToLower()"> 116 <div class="grid"> 117 @if ((product.ProductFields != null && Model.Item.GetBoolean("ProductFields")) || (product.ProductCategories != null && Model.Item.GetBoolean("CategoryFields")) || (displayGroups.Count != 0)) 118 { 119 if (!hideTitle) 120 { 121 <h2 class="g-col-12 @titleFontSize">@Model.Item.GetString("Title")</h2> 122 } 123 } 124 125 @if (displayGroups.Count != 0) 126 { 127 if (layout != "accordion") 128 { 129 foreach (var group in displayGroups) 130 { 131 bool hideHeader = Model.Item.GetBoolean("HideGroupHeaders"); 132 133 if (!hideHeader) 134 { 135 <h4 class="g-col-12 h4 mb-0">@group.Name</h4> 136 } 137 138 { @RenderFieldsFromList(group.Fields, layout) } 139 140 } 141 } 142 else 143 { 144 <div class="g-col-12"> 145 <div class="accordion accordion-flush w-100" id="Specifications_@Model.ID"> 146 @foreach (var group in displayGroups) 147 { 148 <div class="accordion-item"> 149 <h2 class="accordion-header" id="SpecificationHeading_@group.Id"> 150 <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"> 151 @group.Name 152 </button> 153 </h2> 154 <div id="SpecificationItem_@group.Id" class="accordion-collapse collapse" aria-labelledby="SpecificationHeading_@group.Id" data-bs-parent="#Specifications_@Model.ID"> 155 <div class="accordion-body"> 156 @{ @RenderFieldsFromList(group.Fields, "list") } 157 </div> 158 </div> 159 </div> 160 } 161 </div> 162 </div> 163 } 164 } 165 166 @if (product.ProductFields != null && showProductFields) 167 { 168 if (product.ProductFields.Count > 0) 169 { 170 if (layout != "accordion") 171 { 172 {@RenderFieldsFromList(product.ProductFields, layout) } 173 } 174 else 175 { 176 <div class="g-col-12"> 177 <div class="accordion accordion-flush w-100" id="Specifications_@Model.ID"> 178 <div class="accordion-item"> 179 <h2 class="accordion-header" id="SpecificationHeading_@Model.ID"> 180 <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"> 181 @Translate("Specifications") 182 </button> 183 </h2> 184 <div id="SpecificationItem_@Model.ID" class="accordion-collapse" aria-labelledby="SpecificationHeading_@Model.ID" data-bs-parent="#Specifications_@Model.ID"> 185 <div class="accordion-body"> 186 @{ @RenderFieldsFromList(product.ProductFields, "List") } 187 </div> 188 </div> 189 </div> 190 </div> 191 </div> 192 } 193 } 194 } 195 196 @if (product.ProductCategories != null && Model.Item.GetBoolean("CategoryFields")) 197 { 198 if (product.ProductCategories.Count > 0) 199 { 200 if (layout != "accordion") 201 { 202 foreach (var group in product.ProductCategories) 203 { 204 CategoryFieldViewModel category = group.Value; 205 bool hideHeader = Model.Item.GetBoolean("HideGroupHeaders"); 206 207 if (!hideHeader) 208 { 209 <h4 class="g-col-12 h4 mb-0">@group.Value.Name</h4> 210 } 211 212 { @RenderFieldsFromList(category.Fields, layout) } 213 } 214 } 215 else 216 { 217 <div class="g-col-12"> 218 <div class="accordion accordion-flush w-100" id="Specifications_@Model.ID"> 219 @foreach (var group in product.ProductCategories) 220 { 221 CategoryFieldViewModel category = group.Value; 222 223 <div class="accordion-item"> 224 <h2 class="accordion-header" id="SpecificationHeading_@group.Value.Id"> 225 <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"> 226 @group.Value.Name 227 </button> 228 </h2> 229 <div id="SpecificationItem_@group.Value.Id" class="accordion-collapse" aria-labelledby="SpecificationHeading_@group.Value.Id" data-bs-parent="#Specifications_@Model.ID"> 230 <div class="accordion-body"> 231 @{ @RenderFieldsFromList(category.Fields, "list") } 232 </div> 233 </div> 234 </div> 235 } 236 </div> 237 </div> 238 } 239 } 240 } 241 </div> 242 </div> 243 } 244 else if (Pageview.IsVisualEditorMode) 245 { 246 <div class="alert alert-warning m-0">@Translate("No products available")</div> 247 } 248 249 @helper RenderFieldsFromList(Dictionary<string, FieldValueViewModel> fields, string layout) 250 { 251 string size = Model.Item.GetRawValueString("Size", "full"); 252 string gaps = size != "full" ? " gap-1" : string.Empty; 253 bool hideFieldLabels = Model.Item.GetBoolean("HideFieldLabels"); 254 bool hideFieldsWithZeroValue = Model.Item.GetBoolean("HideFieldsWithZeroValue"); 255 256 if (layout == "columns") 257 { 258 <div class="g-col-12"> 259 <div class="grid@(gaps)"> 260 @foreach (var field in fields) 261 { 262 {@RenderField(field.Value, layout)} 263 } 264 </div> 265 </div> 266 } 267 if (layout == "list") 268 { 269 <div class="g-col-12"> 270 <dl class="grid@(gaps)"> 271 @foreach (var field in fields) 272 { 273 {@RenderField(field.Value, layout)} 274 } 275 </dl> 276 </div> 277 } 278 if (layout == "table") 279 { 280 string tableSize = size == "full" ? "" : " table-sm"; 281 <div class="g-col-12"> 282 <table class="table table-striped@(tableSize)"> 283 @foreach (var field in fields) 284 { 285 {@RenderField(field.Value, layout)} 286 } 287 </table> 288 </div> 289 } 290 if (layout == "bullets") 291 { 292 string listSize = size == "full" ? "" : "m-0 p-0 lh-1 fs-7 opacity-75"; 293 string listStyle = size == "full" ? "" : "style=\"list-style-position: inside\""; 294 <div class="g-col-12"> 295 <ul class="@listSize" @listStyle> 296 @foreach (var field in fields) 297 { 298 {@RenderField(field.Value, layout)} 299 } 300 </ul> 301 </div> 302 } 303 if (layout == "commas") 304 { 305 List<string> featuresList = new List<string>(); 306 307 foreach (var field in fields) 308 { 309 string firstListItemValue = string.Empty; //Hack to support field type providers with a single value 310 311 if (field.Value?.Value != null) 312 { 313 if (field.Value.Value.GetType() == typeof(System.Collections.Generic.List<FieldOptionValueViewModel>)) 314 { 315 System.Collections.Generic.List<FieldOptionValueViewModel> values = field.Value.Value as System.Collections.Generic.List<FieldOptionValueViewModel>; 316 317 //Hack to support field type providers with a single value 318 if (values.FirstOrDefault() != null) 319 { 320 firstListItemValue = values.FirstOrDefault().Value; 321 } 322 } 323 } 324 325 if (!hideFieldsWithZeroValue || (firstListItemValue != "0" && firstListItemValue != "0.0" && field.Value.Value.ToString() != "0" && field.Value.Value.ToString() != "0.0")) 326 { 327 if (field.Value.Value is object && !string.IsNullOrEmpty(field.Value.Value.ToString())) 328 { 329 if (field.Value.Value.GetType() == typeof(System.Collections.Generic.List<FieldOptionValueViewModel>)) 330 { 331 List<string> options = new List<string>(); 332 foreach (FieldOptionValueViewModel option in field.Value.Value as System.Collections.Generic.List<FieldOptionValueViewModel>) 333 { 334 if (!string.IsNullOrWhiteSpace(option.Value)) 335 { 336 if (option.Value.ToString().Contains("#") && (Translate(field.Value.Name) == Translate("Color") || Translate(field.Value.Name) == Translate("Colour"))) 337 { 338 string colorSpan = "<span class=\"colorbox-sm\" style=\"background-color: " + option.Value + "\"></span>"; 339 options.Add(colorSpan); 340 } 341 else if (!string.IsNullOrEmpty(option.Value)) 342 { 343 options.Add(option.Name); 344 } 345 } 346 } 347 string optionsString = (string.Join(", ", options.Select(x => x.ToString()).ToArray())); 348 if ((Translate(field.Value.Name) == Translate("Color") || Translate(field.Value.Name) == Translate("Colour"))) 349 { 350 optionsString = (string.Join(" ", options.Select(x => x.ToString()).ToArray())); 351 } 352 353 if (!string.IsNullOrEmpty(optionsString)) 354 { 355 if (!hideFieldLabels) 356 { 357 featuresList.Add(field.Value.Name + ": " + optionsString); 358 } 359 else 360 { 361 featuresList.Add(optionsString); 362 } 363 } 364 } 365 else 366 { 367 if (!string.IsNullOrWhiteSpace(field.Value.Value.ToString())) 368 { 369 if (field.Value.Value.ToString().Contains("#") && (Translate(field.Value.Name) == Translate("Color") || Translate(field.Value.Name) == Translate("Colour"))) 370 { 371 string colorSpan = "<span class=\"colorbox-sm\" style=\"background-color: " + field.Value.Value + "\"></span>"; 372 373 if (!hideFieldLabels) 374 { 375 featuresList.Add(field.Value.Name + ": " + colorSpan); 376 } 377 else 378 { 379 featuresList.Add(colorSpan); 380 } 381 } 382 else 383 { 384 if (!hideFieldLabels) 385 { 386 featuresList.Add(field.Value.Name + ": " + field.Value.Value.ToString()); 387 } 388 else 389 { 390 featuresList.Add(field.Value.Value.ToString()); 391 } 392 } 393 } 394 } 395 } 396 } 397 } 398 399 string featuresString = (string.Join(", ", featuresList.Select(x => x.ToString()).ToArray())); 400 401 <div class="g-col-12 opacity-75 fs-7">@featuresString</div> 402 } 403 } 404 405 @helper RenderField(FieldValueViewModel field, string layout) 406 { 407 string size = Model.Item.GetRawValueString("Size", "full"); 408 string fieldValue = field?.Value != null ? field.Value.ToString() : ""; 409 bool hideFieldLabels = Model.Item.GetBoolean("HideFieldLabels"); 410 bool noValues = false; 411 string firstListItemValue = string.Empty; //Hack to support field type providers with a single value 412 bool hideFieldsWithZeroValue = Model.Item.GetBoolean("HideFieldsWithZeroValue"); 413 414 if (!string.IsNullOrEmpty(fieldValue)) 415 { 416 if (field.Value.GetType() == typeof(System.Collections.Generic.List<FieldOptionValueViewModel>)) 417 { 418 System.Collections.Generic.List<FieldOptionValueViewModel> values = field.Value as System.Collections.Generic.List<FieldOptionValueViewModel>; 419 noValues = values.Count > 0 ? false : true; 420 421 //Hack to support field type providers with a single value 422 if (values.FirstOrDefault() != null) 423 { 424 firstListItemValue = values.FirstOrDefault().Value; 425 } 426 } 427 } 428 429 if (!string.IsNullOrEmpty(fieldValue) && noValues == false) 430 { 431 if (!hideFieldsWithZeroValue || (firstListItemValue != "0" && firstListItemValue != "0.0" && field.Value.ToString() != "0" && field.Value.ToString() != "0.0")) 432 { 433 if (layout == "columns") 434 { 435 436 <div class="grid g-col-6 g-col-lg-4 gap-1"> 437 @if (!hideFieldLabels) 438 { 439 <dt class="g-col-12 g-col-lg-4">@field.Name</dt> 440 } 441 <dd class="g-col-12 g-col-lg-8 mb-0 text-break"> 442 443 @{ @RenderFieldValue(field)} 444 </dd> 445 </div> 446 } 447 if (layout == "list") 448 { 449 if (!hideFieldLabels) 450 { 451 <dt class="g-col-4">@field.Name</dt> 452 } 453 <dd class="g-col-8 mb-0 text-break"> 454 @{ @RenderFieldValue(field)} 455 </dd> 456 } 457 if (layout == "table") 458 { 459 <tr> 460 @if (!hideFieldLabels) 461 { 462 <th class="w-25 w-lg-50" scope="row">@field.Name</th> 463 } 464 <td class="text-break"> 465 @{ @RenderFieldValue(field) } 466 </td> 467 </tr> 468 } 469 if (layout == "bullets") 470 { 471 <li> 472 @if (!hideFieldLabels) 473 { 474 <strong>@field.Name</strong> 475 } 476 <span> 477 @{ @RenderFieldValue(field) } 478 </span> 479 </li> 480 } 481 } 482 } 483 } 484 485 @helper RenderFieldValue(FieldValueViewModel field) 486 { 487 string fieldValue = field?.Value != null ? field.Value.ToString() : ""; 488 if (field.SystemName == "ProductWeight") 489 { 490 491 decimal calculatedValue = NumberHelper.ToDecimal(fieldValue); 492 decimal baseValue = NumberHelper.ToDecimal("0,00001"); 493 494 495 fieldValue = calculatedValue.ToString("0.######", System.Globalization.CultureInfo.InvariantCulture).Replace(".", ","); 496 497 } 498 bool isLink = field?.Type == "Link"; 499 bool isColor = false; 500 bool isBrandName = field?.SystemName == "Brand_name"; 501 502 fieldValue = fieldValue == "False" ? Translate("No") : fieldValue; 503 fieldValue = fieldValue == "True" ? Translate("Yes") : fieldValue; 504 505 506 if (field.Value.GetType() == typeof(System.Collections.Generic.List<Dynamicweb.Ecommerce.ProductCatalog.FieldOptionValueViewModel>)) 507 { 508 int valueCount = 0; 509 System.Collections.Generic.List<FieldOptionValueViewModel> values = field.Value as System.Collections.Generic.List<FieldOptionValueViewModel>; 510 int totalValues = values.Count; 511 512 foreach (FieldOptionValueViewModel option in values) 513 { 514 if (!string.IsNullOrEmpty(option.Value)) 515 { 516 if (option.Value.Substring(0, 1) == "#") 517 { 518 isColor = true; 519 } 520 } 521 522 if (!isColor) 523 { 524 @option.Name 525 } 526 else 527 { 528 <span class="colorbox-sm" style="background-color: @option.Value" title="@option.Name"></span> 529 } 530 531 if (valueCount != totalValues && valueCount < (totalValues - 1)) 532 { 533 if (isColor) 534 { 535 <text> </text> 536 } 537 else 538 { 539 <text>, </text> 540 } 541 } 542 valueCount++; 543 } 544 } 545 else 546 { 547 if (fieldValue.Substring(0, 1) == "#") 548 { 549 isColor = true; 550 } 551 552 if (!isColor) 553 { 554 if (isLink) 555 { 556 string linktTitle = !fieldValue.Contains("aspx") ? fieldValue : Translate("Go to link"); 557 string target = Pageview.AreaSettings.GetBoolean("OpenLinksInNewTab") && fieldValue.Contains("http") ? "target=\"_blank\"" : string.Empty; 558 string rel = Pageview.AreaSettings.GetBoolean("OpenLinksInNewTab") && fieldValue.Contains("http") ? "rel=\"noopener\"" : string.Empty; 559 560 <a href="@field.Value" title="@field.Name" @target @rel>@linktTitle</a> 561 } 562 else if (isBrandName) 563 { 564 <span itemprop="brand" itemtype="https://schema.org/Brand" itemscope> 565 <span itemprop="name">@fieldValue</span> 566 </span> 567 } 568 else 569 { 570 @fieldValue 571 } 572 573 } 574 else 575 { 576 <span class="colorbox-sm" style="background-color: @fieldValue" title="@fieldValue"></span> 577 } 578 } 579 } 580
Ikke på lager
Error executing template "/Designs/Swift/Paragraph/Swift_ProductSpecification_Custom.cshtml" System.NullReferenceException: Object reference not set to an instance of an object. at Dynamicweb.Ecommerce.Products.GroupRelation.GetGroupRelationsByChildId(String childId) at Dynamicweb.Ecommerce.Products.Categories.ProductCategoryFieldGroupValueService.GetOrderedInheritableParentIds(Group group, String defaultLanguageId) at Dynamicweb.Ecommerce.Products.Categories.ProductCategoryFieldGroupValueService.RecursivelySearchForFieldValues(Group group, String defaultLanguageId, List`1 categoryFields) at Dynamicweb.Ecommerce.Products.Categories.ProductCategoryFieldGroupValueService.RecursivelySearchForFieldValues(Group group, String defaultLanguageId, List`1 categoryFields) at System.Lazy`1.CreateValue() at System.Lazy`1.LazyInitValue() at Dynamicweb.Ecommerce.Products.Categories.ProductCategoryFieldGroupValueService.GetGroupFieldValuesByLanguage(Group group, List`1 categoryFields, String languageId, Boolean isInheritedValue, Boolean searchRecursively) at Dynamicweb.Ecommerce.Products.Categories.ProductCategoryFieldGroupValueService.SearchForGroupFieldValue(Group group, List`1 categoryFields, Boolean allowFallback) at Dynamicweb.Ecommerce.Products.Categories.ProductCategoryFieldGroupValueService.GetGroupCategoryFieldValues(IEnumerable`1 groups, List`1 fields, Boolean allowFallback) at Dynamicweb.Ecommerce.Products.Categories.ProductCategoryFieldGroupValueService.GetDefaultCategoryValuesFromGroups(IEnumerable`1 groupInfos, List`1 catFields) at Dynamicweb.Ecommerce.Products.Categories.ProductCategoryFieldGroupValueService.GetDefaultCategoryValueFromGroups(IEnumerable`1 groupInfos, Field catField) at Dynamicweb.Ecommerce.Products.Categories.ProductCategoryFieldValueService.GetCategoryValue(Product product, String defaultLanguageId, IEnumerable`1 orderedGroups, Field catField, Boolean includeInheritance) at Dynamicweb.Ecommerce.Products.Categories.ProductCategoryFieldValueService.GetCategoryValue(Product product, String categoryId, String fieldId, Boolean includeInheritance) at Dynamicweb.Ecommerce.Products.Categories.ProductCategoryFieldValueService.GetProductCategoryFieldValue(Product product, String categoryId, Field field) at Dynamicweb.Ecommerce.ProductCatalog.ViewEngine.CreateView(ProductViewModelSettings settings, Product product, Field field) at Dynamicweb.Ecommerce.ProductCatalog.ViewEngine.GetFieldDisplayGroupValues(ProductViewModelSettings settings, Product product, String languageID, Lazy`1 productIds) at Dynamicweb.Ecommerce.ProductCatalog.ViewEngine.<>c__DisplayClass3_1.<BulkCreateView>b__60() at System.Lazy`1.CreateValue() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Lazy`1.get_Value() at CompiledRazorTemplates.Dynamic.RazorEngine_3312c79de35343b4bd83ca56d534bd40.Execute() in D:\dynamicweb.net\Solutions\brdklee.cloud.dynamicweb-cms.com\files\Templates\Designs\Swift\Paragraph\Swift_ProductSpecification_Custom.cshtml:line 29 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") && !string.IsNullOrEmpty(Dynamicweb.Context.Current.Request.QueryString.Get("ProductID"))) 7 { 8 product = (ProductViewModel)Dynamicweb.Context.Current.Items["ProductDetails"]; 9 } 10 else if (Pageview.Page.Item["DummyProduct"] != null && Pageview.IsVisualEditorMode) 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 && product != null) 23 { 24 IEnumerable<string> selectedDisplayGroupIds = Model.Item.GetRawValueString("DisplayGroups").Split(',').ToList(); 25 List<CategoryFieldViewModel> displayGroups = new List<CategoryFieldViewModel>(); 26 27 foreach (var selection in selectedDisplayGroupIds) 28 { 29 foreach (CategoryFieldViewModel group in product.FieldDisplayGroups.Values) 30 { 31 if (selection == group.Id) 32 { 33 int fieldsWithNoValueOrZero = 0; 34 35 foreach (var field in group.Fields) 36 { 37 if (string.IsNullOrEmpty(field.Value.Value.ToString())) 38 { 39 fieldsWithNoValueOrZero++; 40 } 41 } 42 43 if (fieldsWithNoValueOrZero != group.Fields.Count) 44 { 45 displayGroups.Add(group); 46 } 47 } 48 } 49 } 50 51 bool showProductFields = Model.Item.GetBoolean("ProductFields"); 52 53 bool hideTitle = Model.Item.GetBoolean("HideTitle"); 54 55 string theme = !string.IsNullOrWhiteSpace(Model.Item.GetRawValueString("Theme")) ? " theme " + Model.Item.GetRawValueString("Theme").Replace(" ", "").Trim().ToLower() : ""; 56 57 string titleFontSize = Model.Item.GetRawValueString("TitleFontSize", "display-4"); 58 59 string contentPadding = Model.Item.GetRawValueString("ContentPadding", ""); 60 contentPadding = contentPadding == "none" ? string.Empty : contentPadding; 61 contentPadding = contentPadding == "small" ? " p-2 p-md-3" : contentPadding; 62 contentPadding = contentPadding == "large" ? " p-4 p-md-5" : contentPadding; 63 64 string layout = Model.Item.GetRawValueString("Layout", "list"); 65 string size = Model.Item.GetRawValueString("Size", "full"); 66 string gaps = size == "full" ? " gap-4" : " gap-2"; 67 68 69 if (Pageview.IsVisualEditorMode && displayGroups.Count() == 0) 70 { 71 product.ProductFields.Clear(); 72 product.ProductFields.Add(Translate("Width"), new FieldValueViewModel { Name = Translate("Width"), Value = "99cm" }); 73 product.ProductFields.Add(Translate("Height"), new FieldValueViewModel { Name = Translate("Height"), Value = "195cm" }); 74 showProductFields = true; 75 } 76 77 if (layout == "commas") 78 { 79 gaps = size == "full" ? " gap-4" : " gap-2"; 80 81 } 82 83 <div class="h-100@(gaps)@(theme)@(contentPadding) item_@Model.Item.SystemName.ToLower()"> 84 <div class="grid"> 85 @if ((product.ProductFields != null && Model.Item.GetBoolean("ProductFields")) || (product.ProductCategories != null && Model.Item.GetBoolean("CategoryFields")) || (displayGroups.Count != 0)) { 86 if (!hideTitle) 87 { 88 <h2 class="g-col-12 @titleFontSize">@Model.Item.GetString("Title")</h2> 89 } 90 } 91 92 @if (displayGroups.Count != 0) 93 { 94 if (layout != "accordion") 95 { 96 foreach (var group in displayGroups) 97 { 98 bool hideHeader = Model.Item.GetBoolean("HideGroupHeaders"); 99 100 if (!hideHeader) { 101 <h4 class="g-col-12 h4 mb-0">@group.Name</h4> 102 } 103 104 { @RenderFieldsFromList(group.Fields, layout) } 105 106 } 107 } 108 else 109 { 110 <div class="g-col-12"> 111 <div class="accordion accordion-flush w-100" id="Specifications_@Model.ID"> 112 @foreach (var group in displayGroups) 113 { 114 <div class="accordion-item"> 115 <h2 class="accordion-header" id="SpecificationHeading_@group.Id"> 116 <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"> 117 @group.Name 118 </button> 119 </h2> 120 <div id="SpecificationItem_@group.Id" class="accordion-collapse collapse" aria-labelledby="SpecificationHeading_@group.Id" data-bs-parent="#Specifications_@Model.ID"> 121 <div class="accordion-body"> 122 @{ @RenderFieldsFromList(group.Fields, "list") } 123 </div> 124 </div> 125 </div> 126 } 127 </div> 128 </div> 129 } 130 } 131 132 @if (product.ProductFields != null && showProductFields) 133 { 134 if (product.ProductFields.Count > 0) 135 { 136 if (layout != "accordion") 137 { 138 {@RenderFieldsFromList(product.ProductFields, layout) } 139 } 140 else 141 { 142 <div class="g-col-12"> 143 <div class="accordion accordion-flush w-100" id="Specifications_@Model.ID"> 144 <div class="accordion-item"> 145 <h2 class="accordion-header" id="SpecificationHeading_@Model.ID"> 146 <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"> 147 @Translate("Specifications") 148 </button> 149 </h2> 150 <div id="SpecificationItem_@Model.ID" class="accordion-collapse" aria-labelledby="SpecificationHeading_@Model.ID" data-bs-parent="#Specifications_@Model.ID"> 151 <div class="accordion-body"> 152 @{ @RenderFieldsFromList(product.ProductFields, "List") } 153 </div> 154 </div> 155 </div> 156 </div> 157 </div> 158 } 159 } 160 } 161 162 @if (product.ProductCategories != null && Model.Item.GetBoolean("CategoryFields")) 163 { 164 if (product.ProductCategories.Count > 0) 165 { 166 if (layout != "accordion") 167 { 168 foreach (var group in product.ProductCategories) 169 { 170 CategoryFieldViewModel category = group.Value; 171 bool hideHeader = Model.Item.GetBoolean("HideGroupHeaders"); 172 173 if (!hideHeader) { 174 <h4 class="g-col-12 h4 mb-0">@group.Value.Name</h4> 175 } 176 177 { @RenderFieldsFromList(category.Fields, layout) } 178 } 179 } 180 else 181 { 182 <div class="g-col-12"> 183 <div class="accordion accordion-flush w-100" id="Specifications_@Model.ID"> 184 @foreach (var group in product.ProductCategories) 185 { 186 CategoryFieldViewModel category = group.Value; 187 188 <div class="accordion-item"> 189 <h2 class="accordion-header" id="SpecificationHeading_@group.Value.Id"> 190 <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"> 191 @group.Value.Name 192 </button> 193 </h2> 194 <div id="SpecificationItem_@group.Value.Id" class="accordion-collapse" aria-labelledby="SpecificationHeading_@group.Value.Id" data-bs-parent="#Specifications_@Model.ID"> 195 <div class="accordion-body"> 196 @{ @RenderFieldsFromList(category.Fields, "list") } 197 </div> 198 </div> 199 </div> 200 } 201 </div> 202 </div> 203 } 204 } 205 } 206 </div> 207 </div> 208 } 209 else if (Pageview.IsVisualEditorMode) 210 { 211 <div class="alert alert-warning m-0">@Translate("No products available")</div> 212 } 213 214 @helper RenderFieldsFromList(Dictionary<string, FieldValueViewModel> fields, string layout) 215 { 216 string size = Model.Item.GetRawValueString("Size", "full"); 217 string gaps = size != "full" ? " gap-1" : string.Empty; 218 bool hideFieldLabels = Model.Item.GetBoolean("HideFieldLabels"); 219 bool hideFieldsWithZeroValue = Model.Item.GetBoolean("HideFieldsWithZeroValue"); 220 221 if (layout == "columns"){ 222 <div class="g-col-12"> 223 <div class="grid@(gaps)"> 224 @foreach (var field in fields) 225 { 226 {@RenderField(field.Value, layout)} 227 } 228 </div> 229 </div> 230 } 231 if (layout == "list") { 232 <div class="g-col-12"> 233 <dl class="grid@(gaps)"> 234 @foreach (var field in fields) 235 { 236 {@RenderField(field.Value, layout)} 237 } 238 </dl> 239 </div> 240 } 241 if (layout == "table") 242 { 243 string tableSize = size == "full" ? "" : " table-sm"; 244 <div class="g-col-12"> 245 <table class="table table-striped@(tableSize)"> 246 @foreach (var field in fields) 247 { 248 {@RenderField(field.Value, layout)} 249 } 250 </table> 251 </div> 252 } 253 if (layout == "bullets") 254 { 255 string listSize = size == "full" ? "" : "m-0 p-0 lh-1 fs-7 opacity-75"; 256 string listStyle = size == "full" ? "" : "style=\"list-style-position: inside\""; 257 <div class="g-col-12"> 258 <ul class="@listSize" @listStyle> 259 @foreach (var field in fields) 260 { 261 {@RenderField(field.Value, layout)} 262 } 263 </ul> 264 </div> 265 } 266 if (layout == "commas") 267 { 268 List<string> featuresList = new List<string>(); 269 270 foreach (var field in fields) 271 { 272 if (field.Value.SystemName == "MaxCanBeBuilt") 273 { 274 if (field.Value.Value is int) 275 { 276 field.Value.Value = (int)field.Value.Value > 0 ? Translate("Yes") : Translate("No"); 277 } 278 } 279 string firstListItemValue = string.Empty; //Hack to support field type providers with a single value 280 281 if (field.Value?.Value != null) 282 { 283 if (field.Value.Value.GetType() == typeof(System.Collections.Generic.List<FieldOptionValueViewModel>)) 284 { 285 System.Collections.Generic.List<FieldOptionValueViewModel> values = field.Value.Value as System.Collections.Generic.List<FieldOptionValueViewModel>; 286 287 //Hack to support field type providers with a single value 288 if (values.FirstOrDefault() != null) 289 { 290 firstListItemValue = values.FirstOrDefault().Value; 291 } 292 } 293 } 294 295 if (!hideFieldsWithZeroValue || (firstListItemValue != "0" && firstListItemValue != "0.0" && field.Value.Value.ToString() != "0" && field.Value.Value.ToString() != "0.0")) 296 { 297 if (field.Value.Value is object && !string.IsNullOrEmpty(field.Value.Value.ToString())) 298 { 299 if (field.Value.Value.GetType() == typeof(System.Collections.Generic.List<FieldOptionValueViewModel>)) 300 { 301 List<string> options = new List<string>(); 302 foreach (FieldOptionValueViewModel option in field.Value.Value as System.Collections.Generic.List<FieldOptionValueViewModel>) 303 { 304 if (!string.IsNullOrWhiteSpace(option.Value)) 305 { 306 if (option.Value.ToString().Contains("#") && (Translate(field.Value.Name) == Translate("Color") || Translate(field.Value.Name) == Translate("Colour"))) 307 { 308 string colorSpan = "<span class=\"colorbox-sm\" style=\"background-color: " + option.Value + "\"></span>"; 309 options.Add(colorSpan); 310 } 311 else if (!string.IsNullOrEmpty(option.Value)) 312 { 313 options.Add(option.Name); 314 } 315 } 316 } 317 string optionsString = (string.Join(", ", options.Select(x => x.ToString()).ToArray())); 318 if ((Translate(field.Value.Name) == Translate("Color") || Translate(field.Value.Name) == Translate("Colour"))) 319 { 320 optionsString = (string.Join(" ", options.Select(x => x.ToString()).ToArray())); 321 } 322 323 if (!string.IsNullOrEmpty(optionsString)) 324 { 325 if (!hideFieldLabels) 326 { 327 featuresList.Add(field.Value.Name + ": " + optionsString); 328 } 329 else 330 { 331 featuresList.Add(optionsString); 332 } 333 } 334 } 335 else 336 { 337 if (!string.IsNullOrWhiteSpace(field.Value.Value.ToString())) 338 { 339 if (field.Value.Value.ToString().Contains("#") && (Translate(field.Value.Name) == Translate("Color") || Translate(field.Value.Name) == Translate("Colour"))) 340 { 341 string colorSpan = "<span class=\"colorbox-sm\" style=\"background-color: " + field.Value.Value + "\"></span>"; 342 343 if (!hideFieldLabels) 344 { 345 featuresList.Add(field.Value.Name + ": " + colorSpan); 346 } 347 else 348 { 349 featuresList.Add(colorSpan); 350 } 351 } 352 else 353 { 354 if (!hideFieldLabels) 355 { 356 featuresList.Add(field.Value.Name + ": " + field.Value.Value.ToString()); 357 } 358 else 359 { 360 featuresList.Add(field.Value.Value.ToString()); 361 } 362 } 363 } 364 } 365 } 366 } 367 } 368 369 string featuresString = (string.Join(", ", featuresList.Select(x => x.ToString()).ToArray())); 370 371 <div class="g-col-12 opacity-75 fs-7">@featuresString</div> 372 } 373 } 374 375 @helper RenderField(FieldValueViewModel field, string layout) 376 { 377 378 string size = Model.Item.GetRawValueString("Size", "full"); 379 string fieldValue = field?.Value != null ? field.Value.ToString() : ""; 380 bool hideFieldLabels = Model.Item.GetBoolean("HideFieldLabels"); 381 bool noValues = false; 382 string firstListItemValue = string.Empty; //Hack to support field type providers with a single value 383 bool hideFieldsWithZeroValue = Model.Item.GetBoolean("HideFieldsWithZeroValue"); 384 385 if (!string.IsNullOrEmpty(fieldValue)) 386 { 387 if (field.Value.GetType() == typeof(System.Collections.Generic.List<FieldOptionValueViewModel>)) 388 { 389 System.Collections.Generic.List<FieldOptionValueViewModel> values = field.Value as System.Collections.Generic.List<FieldOptionValueViewModel>; 390 noValues = values.Count > 0 ? false : true; 391 392 //Hack to support field type providers with a single value 393 if (values.FirstOrDefault() != null) 394 { 395 firstListItemValue = values.FirstOrDefault().Value; 396 } 397 } 398 } 399 400 if (!string.IsNullOrEmpty(fieldValue) && noValues == false) 401 { 402 if (!hideFieldsWithZeroValue || (firstListItemValue != "0" && firstListItemValue != "0.0" && field.Value.ToString() != "0" && field.Value.ToString() != "0.0")) 403 { 404 if (layout == "columns") 405 { 406 407 <div class="grid g-col-6 g-col-lg-4 gap-1"> 408 @if (!hideFieldLabels) 409 { 410 <dt class="g-col-12 g-col-lg-4">@field.Name</dt> 411 } 412 <dd class="g-col-12 g-col-lg-8 mb-0 text-break"> 413 @{ @RenderFieldValue(field) } 414 </dd> 415 </div> 416 } 417 if (layout == "list") 418 { 419 if (!hideFieldLabels) 420 { 421 <dt class="g-col-4">@field.Name</dt> 422 } 423 <dd class="g-col-8 mb-0 text-break"> 424 @{ @RenderFieldValue(field) } 425 </dd> 426 } 427 if (layout == "table") 428 { 429 <tr> 430 @if (!hideFieldLabels) 431 { 432 <th class="w-25 w-lg-50" scope="row">@field.Name</th> 433 } 434 <td class="text-break"> 435 @{ @RenderFieldValue(field) } 436 </td> 437 </tr> 438 } 439 if (layout == "bullets") 440 { 441 <li> 442 @if (!hideFieldLabels) 443 { 444 <strong>@field.Name</strong> 445 } 446 <span> 447 @{ @RenderFieldValue(field) } 448 </span> 449 </li> 450 } 451 } 452 } 453 } 454 455 @helper RenderFieldValue(FieldValueViewModel field) 456 { 457 string fieldValue = field?.Value != null ? field.Value.ToString() : ""; 458 459 bool isLink = field?.Type == "Link"; 460 bool isColor = false; 461 bool isBrandName = field?.SystemName == "Brand_name"; 462 463 fieldValue = fieldValue == "False" ? Translate("No") : fieldValue; 464 fieldValue = fieldValue == "True" ? Translate("Yes") : fieldValue; 465 466 467 if (field.SystemName == "MaxCanBeBuilt") 468 { 469 fieldValue = (int)field.Value > 0 ? Translate("Yes") : Translate("No"); 470 } 471 472 if (field.Value.GetType() == typeof(System.Collections.Generic.List<Dynamicweb.Ecommerce.ProductCatalog.FieldOptionValueViewModel>)) 473 { 474 int valueCount = 0; 475 System.Collections.Generic.List<FieldOptionValueViewModel> values = field.Value as System.Collections.Generic.List<FieldOptionValueViewModel>; 476 int totalValues = values.Count; 477 478 foreach (FieldOptionValueViewModel option in values) 479 { 480 if (!string.IsNullOrEmpty(option.Value)) 481 { 482 if (option.Value.Substring(0, 1) == "#") 483 { 484 isColor = true; 485 } 486 } 487 488 if (!isColor) 489 { 490 @option.Name 491 } 492 else 493 { 494 <span class="colorbox-sm" style="background-color: @option.Value" title="@option.Name"></span> 495 } 496 497 if (valueCount != totalValues && valueCount < (totalValues - 1)) 498 { 499 if (isColor) 500 { 501 <text> </text> 502 } 503 else 504 { 505 <text>, </text> 506 } 507 } 508 valueCount++; 509 } 510 } 511 else 512 { 513 if (fieldValue.Substring(0, 1) == "#") 514 { 515 isColor = true; 516 } 517 518 if (!isColor) 519 { 520 if (isLink) 521 { 522 string linktTitle = !fieldValue.Contains("aspx") ? fieldValue : Translate("Go to link"); 523 string target = Pageview.AreaSettings.GetBoolean("OpenLinksInNewTab") && fieldValue.Contains("http") ? "target=\"_blank\"" : string.Empty; 524 string rel = Pageview.AreaSettings.GetBoolean("OpenLinksInNewTab") && fieldValue.Contains("http") ? "rel=\"noopener\"" : string.Empty; 525 526 <a href="@field.Value" title="@field.Name" @target @rel>@linktTitle</a> 527 } 528 else if (isBrandName) 529 { 530 <span itemprop="brand" itemtype="https://schema.org/Brand" itemscope> 531 <span itemprop="name">@fieldValue</span> 532 </span> 533 } 534 else 535 { 536 @fieldValue 537 } 538 539 } 540 else 541 { 542 <span class="colorbox-sm" style="background-color: @fieldValue" title="@fieldValue"></span> 543 } 544 } 545 } 546
2D/3D tegninger og målskitse
| Navn | Download | Fil type | |
|---|---|---|---|
|
|
50300201-0-419814-SAT-Brd. Klee - PMC20.sat | 759 KB | .sat |
|
|
50300201-0-419816-STP-Brd. Klee - PMC20.stp | 621 KB | .stp |
|
|
50300201-0-419815-IGS-Brd. Klee - PMC20.igs | 1071 KB | .igs |
|
|
50300201-0-419813-IPT-Brd. Klee - PMC20.ipt | 813 KB | .ipt |