The JavaScript file for the widget defines a personalizeItem() function that implements the logic for the dialog:

personalizeItem: function(item, widget) {
     //Personalizing the item
     var totalQuantity = item.quantity();
     if(widget.cart().lineAttributes().length > 0) {
       for(var i=0; i< totalQuantity; i++) {
         var propObj = {};
         for(var j=0; j< widget.cart().lineAttributes().length;j++) {
           //Injecting default values of properties from the metadata
           propObj[widget.cart().lineAttributes()[j].id()] =
           ko.observable(widget.cart().lineAttributes()[j].value());
         }
         //Pushing each key-value pair to the result object to show onto the modal
         widget.itemProps.push(propObj);
       }
     }
     //Modal related functionality
     $('#cc-personalizationPane').on('show.bs.modal', function() {
         widget.item(item);
     });
     $('#cc-personalizationPane').modal('show');
     $('#cc-personalizationPane').on('hidden.bs.modal', function() {
         widget.itemProps([]);
     });
 },

If the custom properties have default values, these values are used to populate the dialog fields. However, providing defaults for these values is not recommended, because they will be applied to all line items, including ones that cannot actually be personalized.

The widget’s display.template file contains the following for rendering the dialog:

<!-- Personalization Modal -->
<div class="modal fade" id="cc-personalizationPane" tabindex="-1" role="dialog">
  <div class="modal-dialog cc-modal-dialog">
    <div class="modal-content">
    <!-- ko if: $parent && $parent.item()!=null -->
      <div class="modal-header CC-header-modal-heading">
        <h4>Personalize your Item</h4>
      </div>
      <div class="modal-body cc-modal-body">
      <h5>Item 1</h5>
      <!-- ko with: lineAttributes -->
      <!-- ko foreach: $data -->
        <label  class="control-label" data-bind="text: label"></label>
        <!-- ko if: $parents[2].itemProps()[0] -->
        <!-- ko if: uiEditorType() == "shortText" || uiEditorType() == "richText"
          || uiEditorType() == "number" || uiEditorType() == "date" -->
        <input  class="form-control" type="text" data-bind="attr: {name : id},
          value: $parents[2].itemProps()[0][id()]"><br>
        <!-- /ko -->
        <!-- ko if: uiEditorType() == "checkbox" -->
        <input  class="form-control" type="checkbox" data-bind="attr: {name : id},
          checked: $parents[2].itemProps()[0][id()]"><br>
        <!-- /ko -->
        <!-- /ko -->
      <!-- /ko -->
      <!-- /ko -->
      <input type="checkbox" data-bind="checked: $parent.noRepeat">Use this
        for all items</input>
      <div data-bind="visible: !$parent.noRepeat()">
      <!-- ko foreach: new Array($parent.item().quantity()-1) -->
      <h5><p>Item <span data-bind="text: $index()+2" /></p></h5>
      <!-- ko with: $parent.lineAttributes -->
      <!-- ko foreach: $data -->
        <label class="control-label" data-bind="text: label"></label>
        <!-- ko if: $parents[3].itemProps()[$parentContext.$index()+1] -->
        <!-- ko if: uiEditorType() == "shortText" || uiEditorType() == "richText"
          || uiEditorType() == "number" || uiEditorType() == "date" -->
        <input class="form-control" type="text" data-bind="attr: {name : id},
          value: $parents[3].itemProps()[$parentContext.$index()+1][id()]"/><br>
        <!-- /ko -->
        <!-- ko if: uiEditorType() == "checkbox" -->
        <input class="form-control" type="checkbox" data-bind="attr: {name : id},
          checked: $parents[3].itemProps()[$parentContext.$index()+1][id()]"/><br>
        <!-- /ko -->
       <!-- /ko -->
       <!-- /ko -->
      <!-- /ko -->
      <!-- /ko -->
      </div>
      </div>
      <div class="modal-footer CC-header-modal-footer">
        <button data-bind="click: $parent.cancelPersonalization.bind($parent)"
           type="button" class="cc-button-secondary">Cancel</button>
         <button data-bind="click: $parent.savePersonalization.bind($parent)"
           type="button" class="cc-button-primary">Save</button>
    </div>
    <!-- /ko -->
    </div>
  </div>
</div>

The JavaScript file for the widget also includes a savePersonalization() function, which is executed when the shopper clicks Save:

savePersonalization: function() {
    var widget= this;
    //Saving personalized values
    if(widget.noRepeat()) {
      //If the flag is checked, populate the entire quantity with the same set
      //of values.
      widget.item().populateItemDynamicProperties(widget.itemProps()[0]);
      widget.item().isPersonalized(true);
      widget.cart().markDirty();
    } else {
      //Splitting all quantities to 1 each if the flag is unchecked.
      //This can be customized further to split total quantity in any manner.
        var quantityList = new Array(widget.item().quantity()+1).join(1).
          split('').map(function(){return 1;})
      //Calling split items function to create multiple lines with
      //different custom properties provided.
        widget.cart().splitItems(widget.item(), quantityList,
        widget.itemProps());
      }
      //Modal related functionality
       $('#cc-personalizationPane').modal('hide');
},

If the shopper chooses to split a line item, the widget splits it into line items whose quantity is 1. For example, if the line item has a quantity of 3, it is split into three line items with a quantity of 1. After an item is split, the shopper can increase the quantity of one of the resulting items and then split that item. If the shopper splits an item and then adds more of the same SKU to the shopping cart, the addition is treated as a separate line item and not combined with the split items.

Note that the splitItems() function of the CartViewModel supports splitting in other ways than the above code implements. For example, splitItems() can split a line item with quantity 3 into two line items, one with a quantity of 1 and one with a quantity of 2. You can support this option in your own custom widget by creating controls that enable shoppers to specify different splitting options.

When the customer edits property values, the sample widget triggers one pricing call per edit. You can reduce the number of pricing calls by implementing a way for your custom widget to trigger pricing only after all personalization is complete.


Copyright © 1997, 2017 Oracle and/or its affiliates. All rights reserved. Legal Notices