Knockout.js Using “with” Binding woes

2019-08-13 03:39发布

问题:

I have an application that has the following setup (more or less):

JS

var ObjectVM = function(data) {
    var me = this;
    me.name = ko.observable(data.name);
    //Set other properties
    ...

    me.isSelected(false);
};
var VM = function () {
    var me = this;
    me.Records = [];
    me.Selected = ko.observable(undefined);
    me.Select = function (rec) {
        if (rec.hasChanges == undefined) {
            //attach editable functionality
            ko.editable(record);
        }
        rec.isSelected(true);
        rec.beginEdit();
        if (me.Selected() != undefined) {
            if (me.Selected().hasChanges()) {
                me.Selected().rollback();
            }
            me.Selected().isSelected(false);
            me.Selected().commit();
        }
        me.Selected(rec);
        //Do some hiding/showing of form...
    };
    me.Init = function(){
       $.ajax({...,
          success: function(data){
          for(var i = 0;i< data.length;i++){
           me.Records.push(new ObjectVM(data[i]));
          }
       }
    };
};

HTML

<div>
     RECORDS DISPLAY GRID (Pretend it's a table with 5 columns and 10 rows)
</div>
<div data-bind="with: Selected">
   <form id="editRec">
     <label>Name</label>
      <input data-bind="value: name" />
   </form>
</div>

I have a click binding setup on the table rows that calls VMs Select funciton. Using the "with" binding removes the form when Selected() is undefined and adds back when Selected() has a record. The issue that every time this occurs, I am losing my validation, tabs, and event bindings (non-KO bindings) that were attached to the form. The application functions perfectly, but with some performance hits when changing between records, as it is having to re-add the form, setup validation, ui config, and bindings.

Is there a way to have the form stay on the page, keeping my bindings and setup, or am I going to forced to deal with the hit every time the Selected value is changed?

回答1:

Currently the with binding treats its contents as a template and re-renders any time the with value changes. The only way to avoid the re-rendering is to not use with.

<div>
   <form id="editRec">
     <label>Name</label>
      <input data-bind="value: Selected().name" />
   </form>
</div>

Of course, if Selected can sometimes be undefined, this will not work, and you must look for another solution. The best one is to use a custom binding that sets up your event handlers, validation, tabs, etc.

<!--ko with: Selected-->
<div data-bind="setUpStuff: true">
   <form id="editRec">
     <label>Name</label>
      <input data-bind="value: name" />
   </form>
</div>
<!--/ko-->

A third alternative to avoid some re-rendering and also support an undefined value is to use Knockout 2.2 and the if binding (and avoid with). In 2.2, the if binding will only re-render if the value goes falsy to truthy, but not if it changes from one truthy value to another.

<!--ko if: Selected-->
<div data-bind="setUpStuff: true">
   <form id="editRec">
     <label>Name</label>
      <input data-bind="value: Selected().name" />
   </form>
</div>
<!--/ko-->