如何从可观察数组中删除Knockout验证validatedObservable

时间:2013-10-03 16:24:09

标签: knockout.js knockout-validation

我的视图模型的属性上有一个observableArray:

self.rates = ko.observableArray([])

数组的内容显示在HTML表格中。有一个按钮可以向数组添加项目。这些是经过验证的可观测量:

self.newRate = function () {
        var rate = new Rate({id: self.id});
        rate.isEditing(true);
        rate.isNew = true;
        rate = ko.validatedObservable(rate);
        self.vendor().rates.push(rate);
    };

这很好用。该项目将添加到阵列中,并且视图会更新。新添加的项目旁边有一个取消链接,允许用户删除该行。

self.editRateCancel = function (item) {
    if (item.isNew === true) {
        self.vendor().rates.remove(item);
    } else {
        item.cancelEdit();
        ko.utils.arrayForEach(self.unitsOfMeasure(), function (uom) {
            if(item.cacheUnitOfMeasureID === uom.value) {
                item.selectedUOM(uom);
            }
        });
    }
};

remove(item)的调用不会删除该项目。如果我没有将项目设置为经过验证的observable,则删除成功。查看remove函数显示传入的项(valueOrPredicate)的类型为Object, (Rate),但从底层数组返回的值为Object, (Function),因此predicate(value)返回false,因此不会删除该项。

KnockoutJS删除功能:

ko.observableArray['fn'] = {
    'remove': function (valueOrPredicate) {
        var underlyingArray = this.peek();
        var removedValues = [];
        var predicate = typeof valueOrPredicate == "function" ? valueOrPredicate : function (value) { return value === valueOrPredicate; };
        for (var i = 0; i < underlyingArray.length; i++) {
            var value = underlyingArray[i];
            if (predicate(value)) {
                if (removedValues.length === 0) {
                    this.valueWillMutate();
                }
                removedValues.push(value);
                underlyingArray.splice(i, 1);
                i--;
            }
        }
        if (removedValues.length) {
            this.valueHasMutated();
        }
        return removedValues;
    },

如何从可观察数组中删除特定的经过验证的observable?有没有可用的实用功能?

2 个答案:

答案 0 :(得分:1)

我刚刚遇到这个问题而且我的研究引导我到这里,所以我会记下我为解决它而做的事情。

knockout中的foreach绑定允许使用$ index()访问当前元素的索引。而不是使用将对象传递给remove函数的常规机制,我传递了索引。

实施例

常用:

function ViewModel() {
    var self = this;
    .
    .
    .

    removeItem(item) {
        // Tries to remove matching object, fails on observables
        self.myArray.remove(item);
    }
}

我的解决方法:

function ViewModel() {
    var self = this;
    .
    .
    .

    removeItem(index) {
        // Removes 1 item at position of index 
        self.myArray.splice(index, 1);
    }
}

在解决方法中,html看起来像这样

<div data-bind="foreach: myArray">
    <p data-bind="text: somePropertyOfTheObject"></p>
    // The bind call puts the index into the list of parameters of the function so it is available in the removeItems function
    <input type="button" value="remove" data-bind="click: $root.removeItem.bind(null, $index())" />
</div>

最后这是我制作的小提琴。 https://jsfiddle.net/jimmypc15/yf5h0kf2/2/

答案 1 :(得分:0)

我遇到了同样的问题,这些是我尝试过的方法:

第一种方法

创建一个可观察数组,其实例为Rate和一个计算的observable,它将每个项目从Rate返回为validatedObservable。这种方法的问题在于,每次向数组添加或删除项时,都会重新创建所有validatedObservable,这样做效率不高并导致奇怪的UI行为。

第二种方法

deleted创建一个额外的Rate可观察字段,并根据此字段的值绑定visible。然后它不会从可观察数组中删除,但用户将无法看到它。

第三种方法

index创建一个额外的Rate字段,并在父视图模型中(包含self.rates的字段)保留lastIndex,初始值设置为0.然后添加费率的功能如下所示:

self.newRate = function () {
    var rate = new Rate({id: self.id});
    rate.isEditing(true);
    rate.isNew = true;
    rate.index = lastIndex++;
    rate = ko.validatedObservable(rate);
    self.vendor().rates.push(rate);
};

删除项目的功能将使用谓词函数,如下所示:

self.editRateCancel = function (item) {
    if (item.isNew === true) {
        self.vendor().rates.remove(function (value) {
            // remember about parenthesis after value()
            // because it's an instance of validatedObservable()
            // and not an instance of Rate()
            return value().index == item.index;
        });
    } else {
        item.cancelEdit();
        ko.utils.arrayForEach(self.unitsOfMeasure(), function (uom) {
            if(item.cacheUnitOfMeasureID === uom.value) {
                item.selectedUOM(uom);
            }
        });
    }
};

我继续使用第三种方法,但第二种方法也可以接受。