ko.computed不评估依赖值何时更改

时间:2014-04-09 14:11:36

标签: javascript jquery data-binding knockout.js computed-observable

我创建了这个小提琴http://jsfiddle.net/mj9f9/4/

视图不会更新按钮“搜索”和“创建”的启用状态。只有在用户选择产品类时才会发生,但必须在用户更改组件的值时发生。

该视图是一个搜索视图,使用户能够搜索由依赖于所选产品类别的组件标识的产品。

视图模型:

/// ProductClass
function ProductClassModel() {
    this.Id = 0;
    this.FullCode = "";
    this.Name = "";
    this.EntitiClass = "";

    this.CompClasses = [];
}

/// Component class that is part of a product class
function ComponentClassModel() {
    this.Id = 0;
    this.FullCode = "";
    this.Name = "";
    this.ProductClassId = 0;
    this.ComponentClass = "";
}

/// The product, it is the composition of a product class with values for each of its components
function ProductModel() {
    this.Id = ko.observable(0);
    this.Uid = ko.observable("");
    this.FullCode = ko.observable("");
    this.Name = ko.observable("");
    this.EntitiClass = ko.observable("");
    this.Components = ko.observable([]);
}

/// ComponentValue is a class of component with a value (actually an instance of that class of component)
function ComponentValueModel() {
    this.Id = ko.observable(0);
    this.FullCode = ko.observable("");
    this.Name = ko.observable("");
    this.ProductClassId = ko.observable(0);
    this.ProductId = ko.observable(0);
    this.ComponentClass = ko.observable("");
    this.Value = ko.observable();
}
/// Wrapper of ComponentValueModel with convenient observable properties (We cannot modify the original ComponentValueModel because it is extern)
function ComponentStateViewModel(prodcomp) {
    var self = this;

    console.log("CREA ComponentStateViewModel " + prodcomp);
    self.value = prodcomp.Value();
    self.component = prodcomp;
    self.changed = ko.observable(false);
    self.found = ko.observable(false);
    self.searched = ko.observable(false);
    self.required = true;
    self.isCreatable = ko.computed(function () {
        return self.searched() && !self.found();
    });
    self.isDefined = ko.computed(function () {
        return self.component.Value() !== undefined;
    });

    self.component.Value.subscribe(function () {
        var newval = self.component.Value();
        if (newval !== self.value) {
            self.changed(true);
            self.found(false);
            self.searched(false);
            self.value = newval;
        }
    });
}

/// View model
function ProductViewModel() {

    var self = this;
    self.customerId = ko.observable(111);
    self.prodClasses = ko.observable([]);
    self.currentProdClass = ko.observable();
    self.currentProd = ko.observable();
    self.currentUid = ko.observable(); 
    self.productsFound = ko.observableArray();
    self.componentStates = ko.observableArray();

    self.productFound = ko.computed(function () {
        var prod = self.currentProd();
        return self.prodClassSelected && (prod !== undefined && prod.Uid() !== undefined);
    });

    self.customerSelected = ko.computed(function () {
        return self.customerId() > 0;
    });

    self.prodClassSelected = ko.computed(function () {        
        return self.currentProdClass() !== undefined;
    });

    self.canSearch = ko.computed(function () {
        if (!self.prodClassSelected() || !self.productFound()) {
            return false;
        }

        var inuid = self.currentUid();
        var puid = self.currentProd().Uid();
        if ((inuid !== undefined) && (inuid !== puid) && (inuid.length > 5)) {            
            return true;
        }

        var comps = self.componentStates();
        for (var i = 0; i < comps.length; i++) {
            var c = comps[i];
            if (c.isDefined && !c.searched) {
                return true;
            }
        }

        return false;
    });

    self.canCreate = ko.computed(function () {
        if (!self.prodClassSelected() || self.productFound()) {
            return false;
        }

        var cstates = self.componentStates();
        for (var i = 0; i < cstates.length; i++) {
            var cm = cstates[i];
            if (!cm.component.Value()) {                
                return false;
            }

            if (!cm.isCreatable()) {                
                return false;
            }
        }        
        return true;
    });

    self.clear = function () {
        self.componentStates([]);
        var c = self.currentProdClass();
        if (c !== undefined) {
            self.currentUid(undefined);
            self.currentProd(undefined);
        }
    };

    self.initialize = function (compClassesData) {
            self.prodClasses(compClassesData);
    };

    self.currentUid.subscribe(function () {
        var uid = self.currentUid();
        if (uid === undefined) {
            return;
        }

        var prod = self.currentProd();
        if ((prod === undefined) || (prod.Uid() !== uid)) {
            if (uid.length < 5) {
                return;
            }

            self.currentProd(new ProductModel());
        }
    });

    self.currentProdClass.subscribe(function () {
       self.clear();
        var c = self.currentProdClass();
        if (c === undefined) {
            return;
        }

        var psearch = new ProductModel();
        psearch.FullCode(c.FullCode);
        psearch.Name(c.Name);
        psearch.EntitiClass(c.EntitiClass);
        for (var i = 0; i < c.CompClasses.length; i++) {
            var cca = c.CompClasses[i];
            var comp = new ComponentValueModel();
            comp.FullCode(cca.FullCode);
            comp.Name(cca.Name);
            comp.ProductClassId(cca.ProductClassId);
            comp.ComponentClass(cca.ComponentClass);
            psearch.Components().push(comp);
            self.componentStates.push(new ComponentStateViewModel(comp));
        }
        self.currentProd(psearch);
        self.currentUid(psearch.Uid());

    });

    self.searchProduct = function () {
        var compfilter = [];
        var comps = self.currentProd().Components();
        for (var i = 0; i < comps.length; i++) {
            var c = comps[i];
            if ((c.Value() !== undefined) && (c.Value() !== "")) {
                var filter = new ComponentValueModel();
                filter.FullCode(c.FullCode());
                filter.ComponentClass(c.ComponentClass());
                filter.Value(c.Value());

                compfilter.push(filter);
            }
        }
    };

    self.createProduct = function () {
        // TODO
    };
}

问题在于搜索和创建按钮。第一个是由一个涉及多个observable的计算函数启用或禁用的,但我感兴趣的是ComponentValueModel.Value类的一个组件的值:

<button data-bind="click: searchProduct, enable: canSearch()">Search</button>

我期望启用或禁用此按钮的代码在ProductViewModel.canSearch计算函数中定义:

self.canSearch = ko.computed(function () {
    if (!self.prodClassSelected() || !self.productFound()) {
        return false;
    }

    var inuid = self.currentUid();
    var puid = self.currentProd().Uid();
    if ((inuid !== undefined) && (inuid !== puid) && (inuid.length > 5)) {
        return true;
    }

    var comps = self.componentStates();
    for (var i = 0; i < comps.length; i++) {
        var c = comps[i];
        if (c.isDefined && !c.searched) {
            return true;
        }
    }

    return false;
});

似乎ko没有通知可观察组件中值的变化。值。任何帮助将不胜感激。

0 个答案:

没有答案