Я использую KnockoutJS с плагином Knockout-Validation для проверки полей в форме. У меня возникают проблемы с проверкой уникальности значения с использованием собственного правила проверки — unique
Я использую шаблон редактора от Райана Нимейера, чтобы позволить пользователю редактировать или создавать файл Location
. Вот моя скрипка, чтобы полностью увидеть мою проблему.
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());
}));
}
У меня проблема. Поскольку редактируемый Location
"отсоединен" от locations
observableArray (см. метод Location.edit
), когда я вношу изменения в name
в отсоединенном Location
, это значение не обновляется в вычисляемом массиве names
. Поэтому, когда правило проверки сравнивает его с массивом names
, оно всегда будет возвращать действительное состояние true, поскольку счетчик всегда будет только 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);
}
Я думал об использовании этого в качестве основы для создания пользовательского правила проверки, но я продолжаю застревать в том, как справиться с ситуацией, когда пользователь хочет вернуться к исходному значению.
Я ценю любую помощь.