2013-04-08 63 views
1

我使用KnockoutJS和Knockout-Validation插件來驗證表單上的字段。我在使用本機驗證規則驗證某個值是唯一值時遇到問題 - 我使用Ryan Niemeyer的編輯器模式允許用戶編輯或創建Location。這是我的fiddle,以查看我的問題的完整。Knockout-Validation插件的獨特值驗證

function Location(data, names) { 
    var self = this; 

    self.id = data.id; 
    self.name = ko.observable().extend({ unique: { collection: names }}); 
    // other properties 
    self.errors = ko.validation.group(self); 

    // update method left out for brevity 
} 

function ViewModel() { 
    var self = this; 

    self.locations = ko.observableArray([]); 

    self.selectedLocation = ko.observable(); 
    self.selectedLocationForEditing = ko.observable(); 

    self.names = ko.computed(function(){ 
     return ko.utils.arrayMap(self.locations(), function(item) { 
      return item.name(); 
     }); 
    }); 

    self.edit = function(item) { 
     self.selectedLocation(item); 
     self.selectedLocationForEditing(new Location(ko.toJS(item), self.types)); 
    }; 

    self.cancel = function() { 
     self.selectedLocation(null); 
     self.selectedLocationForEditing(null); 
    }; 

    self.update = function(item) { 
     var selected = self.selectedLocation(), 
      updated = ko.toJS(self.selectedLocationForEditing()); //get a clean copy 

     if(item.errors().length == 0) { 
      selected.update(updated); 
      self.cancel(); 
     } 
     else 
      alert("Error");   
    }; 

    self.locations(ko.utils.arrayMap(seedData, function(item) { 
     return new Location(item, self.types, self.names()); 
    })); 
} 

雖然我有問題。由於正在編輯的Locationlocations observableArray(請參見Location.edit方法)「分離」,因此當我在分離的Location中更改name時,names計算數組中的值未更新。因此,當驗證規則將它與names數組進行比較時,它將始終返回有效狀態爲真,因爲計數器將只有1或0.(請參閱下面的淘汰算法驗證算法)

在options的參數unique驗證規則我可以​​通過一個屬性爲externalValue。如果這個值不是未定義的,那麼它將檢查匹配名稱的計數是大於還是等於1而不是2.除了用戶更改名稱,繼續到另一個字段,然後返回到名稱並想要將其更改回原始值。該規則只是看到該值已存在於names數組中,並返回有效狀態爲false。

這裏是knockout.validation.js算法處理該unique規則...

function (val, options) { 
    var c = utils.getValue(options.collection), 
     external = utils.getValue(options.externalValue), 
     counter = 0; 

    if (!val || !c) { return true; } 

    ko.utils.arrayFilter(ko.utils.unwrapObservable(c), function (item) { 
     if (val === (options.valueAccessor ? options.valueAccessor(item) : item)) { counter++; } 
    }); 
    // if value is external even 1 same value in collection means the value is not unique 
    return counter < (external !== undefined && val !== external ? 1 : 2); 
} 

我想過用這個作爲基礎來創建自定義的驗證規則,但我一直被陷關於如何處理用戶想要回到原始值的情況。

我感謝任何和所有的幫助。

回答

1

一個可能的解決方案是(創建你所需要的完整列表,一個新的項目時,當然)的唯一驗證不包括當前編輯項目的name

所以當改變位置名稱回其原始值的唯一支票將不會被觸發:

self.namesExceptCurrent = function(name){ 
    return ko.utils.arrayMap(self.locations(), function(item) { 
     if (item.name() !== name) 
      return item.name(); 
    }); 
} 

self.edit = function(item) { 
    self.selectedLocation(item); 
    self.selectedLocationForEditing(
     new Location(ko.toJS(item), 
     self.types, 
     self.namesExceptCurrent(item.name()))); 
}; 

演示JSFiddle.

+0

是,但我可以通過調用'self.selectedLocationForEditing處理新項目(new Location({},self.types,self.namesExceptCurrent('')));'。這是一個優雅,簡單的解決方案 - 謝謝nemesv! – bflemi3 2013-04-11 20:28:25

+0

嗨nemesv這個小提琴現在不工作 – user2142786 2014-08-21 04:56:18

+0

@ user2142786感謝您注意它,我現在修復它 – nemesv 2014-08-21 06:00:15