The easiest way is to manually subscribe to all the properties of all the items in the array, and update this subscriptions whenever the observable array changes. That's brute force, but it works. Take into account that you can subscribe a simple function to all the desired observables.
If you want a more efficient way, you can use ko.projections to map each item in the array to a computed observable that changes whenever any of the inner properties changes, and subscribe to all the computed observables in the mapped array. This plugin is fully optimized to remap only the necessary properties. As you make a simple subscription to each item, this is a bit more efficient.
Another brute force idea is to use the a computed observable that calculates the JSON representantion of the array, as in the isDirty that R Niemeyer explains here: Creating a Smart, Dirty Flag in KnockoutJS. Or use the dirty flag of kolite, resetting it after its change is detected.
You can also extend the items and do a manula notifications, as explained here: Knockout extenders notify. In this case, you also need to subscribe this notifications to all the items in the array.
I'm sure that, whith a little more information, this solution could be fine-tuned to your particular case. You don't specify why you need it, if you need to know which property or item changes or simply that something changed, what you want to do with the detected changes, and so on. If you improve the question, I can try to fine-tune the answer.
UPDATE
Once I know the specific scenario, I can show you a working sample.
It's important to note that you must access all the elements inside the array so that the computed get subscribed to all of them. If you short-circuit the code and don't access all of them (for example breaking the loop in the first not valid) subscriptions would not be created, and this wouldn't work. I've also made explicit the dependency to the observable array. This achieves that the allValid
is recomputed on any change of the observable array or of the valid property of any of its items.
var vm = {
vals: ko.observableArray([
{ n: 0, valid: ko.observable(true) },
{ n: 1, valid: ko.observable(false) },
{ n: 2, valid: ko.observable(true) }
])
};
vm.allValid = ko.computed(function() {
var valid = true;
// make dependen on observable array
var vals = vm.vals();
// make dependent on all the items
for (var i = 0; i<vals.length; i++) {
valid = valid && vals[i].valid();
}
return valid;
});
vm.make1Valid = function() {
vm.vals()[1].valid(true);
}
vm.make1NotValid = function() {
vm.vals()[1].valid(false);
}
vm.pushValid = function() {
vm.vals.push({n:100, valid:ko.observable(true)})
}
vm.pushNotValid = function() {
vm.vals.push({n:100, valid:ko.observable(false)})
}
vm.pop = function() {
vm.vals.pop()
}
ko.applyBindings(vm);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<div data-bind="foreach: vals">
<div>
n:<span data-bind="text: n"></span>
valid:<span data-bind="text: valid"></span>
</div>
</div>
<hr>
<div style="font-weight:bold">
<b>All valid:<span data-bind="text: allValid"></span> </b>
</div>
<div>
<input type="button" value="Make 1 valid" data-bind="click: make1Valid"/>
<input type="button" value="Make 1 not valid" data-bind="click: make1NotValid"/>
<input type="button" value="Push valid" data-bind="click: pushValid"/>
<input type="button" value="Push not valid" data-bind="click: pushNotValid"/>
<input type="button" value="Pop" data-bind="click: pop"/>
</div>
You can also see an extende version in this jsfiddle.
However I'd recommend you using the ko.validation plugin which already has this kind of functionality implemented. Both validating each individual properties, as well as all the properties of a viewmodel tree. For that case, please, see this: How to validate an array?