How to get an observableArray's length?
I am attempting to create an array of contract line items (CLINs) that will be displayed as individual div
elements below a header of general contract information.
I am able to get the normal observables to work, but it appears that the passing of the array via the constructor for the view model is not creating any part of the clins observable array.
I have a jsFiddle that illustrates my problem. What is strange to me is that the data-bind="text: clins.length()
on the HTML span tag does not even return zero, but instead renders nothing.
Is there anyway to enable debugging within a jsFiddle or should I see a warning/error?
Solution 1:
Errors from jsfiddle pages do get sent to your browser.
As for your error, try this:
<span data-bind="text: clins().length">
This turns the observableArray
into an array
and uses the array's length
property.
See the updated the jsfiddle as well.
Solution 2:
TL;DR / Quick Fix
Execute the observableArray
as a function to get the underlying array, then get its length:
<!-- ↓↓ -->
myObsArray's length is: <span data-bind="text: myObsArray().length"></span>
Why does this happen?
Let me provide an answer that provides some details in addition to @kendaleiv's solution, and that also answers a highly related question I feel many people have:
Why does
myObsArray.length
always return 0 (zero)?
A typical repro of such a scenario would be this:
ko.applyBindings({ myObsArray: ko.observableArray(["one", "two", "three"]) });
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
myObsArray.length = <span data-bind="text: myObsArray.length"></span>
The snippet says "length = 0", instead of "length = 3".
The key thing to note here: ko.observableArray
is a function... that returns a function.
That's right: if you assign the result of it to a variable or member, such as myObsArray
in the example, that variable will be a reference to a function. So if you're asking for
myObsArray.length
then you're actually asking for the Function.length
property: the number of arguments that function takes. For a function returned from ko.observableArray
this will be 0 (zero).
How do we fix this?
The fix given in other answers is fine, let me reiterate here with this answer's example. To get the length of "the array being observed", you need to invoke said function to get the array, and then get its length:
ko.applyBindings({ myObsArray: ko.observableArray(["one", "two", "three"]) });
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
myObsArray.length = <span data-bind="text: myObsArray().length"></span>
Finally, as a footnote, OP's code is something equivalent to:
myObsArray.length()
This will find aforementioned Function.length property and try to execute it as a function (which it isn't), and will not return 0 but instead crash. Beware to not invoke length
as a function, but the observable. Always invoke length
as a member variable.
Will / Can / Could this be changed?
Very early on KO's developers considered this issue; as early as Github issue no 4. That issue explains the things I've tried to cover above too, and also shows that in the end there wasn't much that could be done to change it.
Solution 3:
For anyone who wants to get the length of an observableArray without the _destroy
ed items, you can use this function:
ko.observableArray.fn.totalVisible = function() {
var items = this(), count = 0;
if (items == null || typeof items.length === "undefined") {
return 0;
}
for (var i = 0, l = items.length; i < l; i++) {
if (items[i]._destroy !== true) {
count++;
}
}
return count;
};
Then to use it:
myObservableArray.totalVisible();