Knockout:对一个可观察数组进行推送使得每个项目的计算可观察量都被执行

时间:2015-02-20 07:13:43

标签: knockout.js

在下面的代码中,我将一个项添加到observable数组中。这会导致所有先前的项在执行.push时执行其计算的observable。这是不必要的。怎么预防这个? 我拥有的项目越多,就意味着将运行每个计算出的可观察项目。

请参阅小提琴示例。 http://jsfiddle.net/k8kbdnnv/3/

html代码

    <div id="logs"></div>
<table>  

<tbody data-bind="foreach: CompanySearchRows">
                <tr >
                    <td>
                        <input data-bind='textInput: ClientReference' type="text"  />

                    </td>
                    <td>
                        <input data-bind='textInput: CompanySearchReference' type="text"  />
                    </td>
                </tr>

            </tbody>
</table>

jscode

var viewModel;
var maxTitleRefRows = 50;

function ViewModel() {
    var self = this;
    self.CompanySearchRows = new ko.observableArray([new ItemViewModel()]);
    self.Executions = ko.observable(0);

    self.addRow = function (clientReference) {  


    var newRow = new ItemViewModel();       

    self.CompanySearchRows.push(newRow);  //this causes the code to jump 

into each array item's OnCompanySearchReferenceChanged computed observable 
    };
}


function ItemViewModel() {
    var self = this;   
    self.ClientReference = ko.observable(""); 
    self.CompanySearchReference = ko.observable(""); 

self.OnCompanySearchReferenceChanged = ko.computed(function () {               
    var reference = self.CompanySearchReference();

   logIt("computed executed" + reference);


    if (reference !== ""  ) {                    
        var currentIndex = viewModel.CompanySearchRows.indexOf(self);
        viewModel.Executions(currentIndex);
        var length = viewModel.CompanySearchRows().length;
        var lastItemIndex = length - 1;   
        if (currentIndex === lastItemIndex && length < maxTitleRefRows ) {          
            viewModel.addRow(self.ClientReference());               
        }
    }

    return;
});      
}

var logs=document.getElementById('logs');
function logIt(msg){
    var e=document.createElement('div');
    e.innerHTML=msg;
    logs.insertBefore(e,logs.firstChild);
}

$(document).ready(function () {
    viewModel = new ViewModel();
    ko.applyBindings(viewModel);    
});

1 个答案:

答案 0 :(得分:0)

computed函数包含对主ViewModel中observableArray的引用。这意味着如果数组发生更改(例如,从push所有,则会重新评估所有项目上的计算函数。

读取代码时,计算函数的意图似乎是在第二个字段中输入值时添加新行。因此,我们只需跟踪 last 项即可执行此操作。通常建议不要在子对象内部执行此操作 - 主viewModel应该管理数组,子应该独立于它。

为实现这一目标,我在CompanySearchReference可观察对象上使用subscription ,但仅在最后一项上使用http://jsfiddle.net/Quango/fgfw6Ld0/。当此值更改时,父ViewModel将添加新行,并且还会删除上一行的订阅,因此任何时候只有一个订阅处于活动状态。

// subscribe to changes on the child's search reference
// when this has a value, create a new row
var subscription = newRow.CompanySearchReference.subscribe(function (newValue) {
   if (newValue && self.CompanySearchRows().length < maxTitleRefRows) {
       // value has been changed: first remove this subscription
       logIt("removing subscription");
       subscription.dispose();
       // add a new row (creates a new subscription on new row)
       logIt("adding new row");
       self.addRow();
   }
});

完整的JSFiddle位于{{3}}