Stephen Porter Stephen Porter - 2 months ago 14
Javascript Question

Knockout.js | Observable array only triggers when last element changes

The Scenario

I have multiple input fields. The fields are NOT allowed to be empty. If any field is empty, I want to show some sort of error message.

The issue

The issue I am dealing with is that I have an observable array populating some inputs through a knockout foreach for the view.

Everything loads, displays, and saves properly, however, my validation (which is a computed) is only called when the last element in the observable array changes and not when any of the other elements change.

I found This SO Question, but OP's issue here was that he/she did not have their value as an observable which is not my problem as my value is wrapped as an observable.

The Code

Here's a fiddle

Here's the code:


<div data-bind="with: itemsModel">
<label data-bind="text: validMessage">Totally valid</label>
<div data-bind="foreach: items">
<label>Item: </label>
<input type="text " data-bind="value: name " />


function ItemModel(item) {
self = this;
self.item = item; = ko.observable(;

self.isValid = ko.computed(function() {
return && <= 256;

function ItemsModel(itemsModel) {
var self = this;
self.itemsModel = itemsModel;

self.items = ko.observableArray([
new ItemModel(itemsModel.items[0]),
new ItemModel(itemsModel.items[1]),
new ItemModel(itemsModel.items[2])

// This is only getting called when the last element in self.items changes
self.isValid = ko.computed(function() {
var isValid = true;

for (i = 0; i < 3; i++) {
isValid = isValid && self.items()[i].isValid();

return isValid;

self.validMessage = ko.computed(function() {
if (self.isValid()) {
return "Totally Valid";

return "Totally NOT Valid";

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

self.itemsModel = ko.observable(new ItemsModel(data.itemsModel));

var modelData = {
itemsModel: {
items: [{
name: "Item One"
}, {
name: "Item Two"
}, {
name: "Item Three"

ko.applyBindings(new ViewModel(modelData));


You're not declaring your first self locally, so it's global.

function ItemModel(item) {
  self = this;

should be

function ItemModel(item) {
  var self = this;