Knockout Unique Name Validation

Awesome validataor that checks whether an array element has duplicate values

by Dejan Vasic

HTML

<script src="//cdnjs.cloudflare.com/ajax/libs/knockout/2.3.0/knockout-min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/knockout-validation/1.0.2/knockout.validation.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.5.2/underscore-min.js"></script>
<div data-bind="foreach: items">
	<input type="text" data-bind="value: word" />
	<br />
</div>

JavaScript

var listItemVm = function (data) {
	var self = this;
	self.parent = data.parent;
	self.word = ko.observable(data.word).extend({
		validation: {
			validator: function (name, params) {
				console.log("validating " + name);
                
                //return true; // uncommenting this line causes the behaviour I expect
                
				// word we are editing must be different from all other words
				var allWords = params.parent.items.peek();
                
				// exclude current view model we are editing
				var otherWordViewModels = _.filter(allWords, function (row) {
					return row !== params.currentRow;
				});

				var otherWords = _.map(otherWordViewModels, function (item) {
					return item.word.peek();
				});

				return !_.contains(otherWords, name);
			},
			message: 'Must be unique',
			params: {
				currentRow: self,
				parent: self.parent
			}
		}
	});
};

var vm = function (data) {
	var self = this;

	self.items = ko.observableArray();

	_.each(data.words, function (word) {
		self.items.push(new listItemVm({parent: self, word: word.word}));
	});
};

var data = {
	words: [
		{ word: "hello" },
		{ word: "world" },
	]
};

ko.applyBindings(new vm(data));