2013-10-03 124 views
0

我有我的視圖模型的財產observableArray:如何刪除淘汰賽驗證validatedObservable從可觀察到的陣列

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)的調用不會刪除該項目。如果我不將該項設置爲驗證的可觀察項,則刪除成功。查看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; 
    }, 

如何從可觀察到的數組中刪除特定的驗證觀測?是否有任何實用功能可用?

回答

0

我遇到同樣的問題,這些都是我試過的方法:

第一種方法

創建一個可觀察的陣列,並與和Rate一個實例計算觀察到,這將返回來自Rate的每個項目作爲validatedObservable。這種方法的問題在於,每次向陣列中添加或刪除項目時,都會重新創建所有validatedObservable,這種效率不高並會導致奇怪的UI行爲。

第二種方法

創建Rate額外deleted觀察到的字段和具有visible結合基於該字段的值。然後它不會從可觀察數組中移除,但它對用戶不可見。

第三種方法

創建Rate和在父視圖模型的附加index字段(含有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); 
      } 
     }); 
    } 
}; 

我繼續第三種方法,但第二種方法也可以接受。

+0

我沒有意識到一個函數可以像第三種方法中描述的那樣傳遞給remove方法。這很好,因爲它使代碼簡短。我最終編寫了基於KnockOutJS代碼的自己的刪除函數,但我認爲我更喜歡你的代碼。謝謝您的幫助。 – DaveB

+0

很高興我可以幫助:)我實際上不知道我能做到這一點,直到我看到你發佈的問題和代碼,並提出這個想法。所以也要感謝你! –

1

我剛剛遇到這個問題,我的研究讓我在這裏,所以我會記下我所做的解決它。

敲除的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/