foreach rendering too many times

813 views
Skip to first unread message

awj100

unread,
Mar 16, 2012, 10:30:18 AM3/16/12
to KnockoutJS
I'll try to keep this description as simple as possible.

I'm making a jQuery AJAX request to a server, and in the 'success'
callback I have

success: function (data, textStatus) {
var jsonData = $.parseJSON(data);
jsonInitialUpload = jsonData;
ko.applyBindings(new AccountViewModel());
}


Accompanying this I have

function AccountViewModel() {
var self = this;
self.fields = ko.observableArray([]);

var mappedFields = $.map(jsonInitialUpload.Account.Fields,
function(item) { return new Field(item) });
self.fields(mappedFields);
}

function Field(data) {
this.FriendlyName = ko.observable(data.FriendlyName);
}


And then in the markup I have

<table>
<tbody>
<tr data-bind="foreach: fields">
<th data-bind="text: FriendlyName"></th>
</tr>
</tbody>
</table>


The array which is returned from the server contains 21 objects, so I
would expect to see a single <tr> containing 21 <th> elements. But
instead, when I use Firefox or Opera (not Chrome, IE or Safari - these
work as expected), I see a single <tr> containing 21 <th> elements
containing the first value in the array, followed by 21 <th> elements
containing the second value in the array, followed by 21 <th> elements
containing the third value in the array, and so on.

In other words, the 'foreach' renders each element in the array
fields().length times before iterating to the next element in the
array.

For example, here is a short snippet of the first 20-something <th>
elements:

<tr data-bind="foreach: fields">
<th data-bind="text: FriendlyName">Valuation date</th>
<th data-bind="text: FriendlyName">Valuation date</th>
<th data-bind="text: FriendlyName">Valuation date</th>
<th data-bind="text: FriendlyName">Valuation date</th>
<th data-bind="text: FriendlyName">Valuation date</th>
<th data-bind="text: FriendlyName">Valuation date</th>
<th data-bind="text: FriendlyName">Valuation date</th>
<th data-bind="text: FriendlyName">Valuation date</th>
<th data-bind="text: FriendlyName">Valuation date</th>
<th data-bind="text: FriendlyName">Valuation date</th>
<th data-bind="text: FriendlyName">Valuation date</th>
<th data-bind="text: FriendlyName">Valuation date</th>
<th data-bind="text: FriendlyName">Valuation date</th>
<th data-bind="text: FriendlyName">Valuation date</th>
<th data-bind="text: FriendlyName">Valuation date</th>
<th data-bind="text: FriendlyName">Valuation date</th>
<th data-bind="text: FriendlyName">Valuation date</th>
<th data-bind="text: FriendlyName">Valuation date</th>
<th data-bind="text: FriendlyName">Valuation date</th>
<th data-bind="text: FriendlyName">Valuation date</th>
<th data-bind="text: FriendlyName">Valuation date</th>
<th data-bind="text: FriendlyName">Banking relationship</th>
<th data-bind="text: FriendlyName">Banking relationship</th>
<th data-bind="text: FriendlyName">Banking relationship</th>
<th data-bind="text: FriendlyName">Banking relationship</th>


While debugging I've placed a <textarea> on the page and bound this to
the same 'fields' observableArray, like so:

<textarea name="_flds" data-bind="value: ko.toJSON(fields)"></
textarea>


In this <textarea> I can see that the 'fields' observableArray is
correct - the JSON object contains one of each expected element, and
21 in total.

So can anyone explain to me why the 'foreach' iterator is rendering
[fields().length x each element in the 'fields' observableArray]
before moving on to the next element in the 'fields' observableArray?
I.e., why it is rendering 441 <th> elements rather than 21?

Please note, as I mentioned above, this problem is only occurring in
Firefox and Opera. Chrome, IE and Safari render 21 <th> elements, one
for each item in the 'fields' observableArray.

awj100

unread,
Mar 16, 2012, 12:33:32 PM3/16/12
to KnockoutJS
I've realised what the problem was, and it's not related to
Knockout,js.

I had accidentally bound the click() event of the submit button twice,
so the model was being bound twice.

efr...@rmckenna.org

unread,
Feb 7, 2013, 5:42:06 PM2/7/13
to knock...@googlegroups.com, andrew_...@hotmail.com
I'm having this same problem, but not related to submit buttons or ajax loading.

Anyone know what I'm doing wrong?

Here's a simplified example that creates the problem:
http://jsbin.com/axebiv/5/edit

Thank you!

efr...@rmckenna.org

unread,
Feb 7, 2013, 7:49:13 PM2/7/13
to knock...@googlegroups.com, andrew_...@hotmail.com, efr...@rmckenna.org
Found it.  Solved version is at:

The jQuery Mobile library is interfering somehow.  (If I stop it from loading, the foreach loop functions as expected)

The default way jsbin script is added might be part of the issue too.

I explicitly told jsbin where to place the javascript in my html (after the libraries are loaded) and then also had to wrap the applyBindings() in a jQuery on-document-ready event.

weezy

unread,
Nov 18, 2015, 6:13:14 AM11/18/15
to KnockoutJS, andrew_...@hotmail.com
How did you know the model was bound twice?
I have a exactly the same problem, but trying to figure out why?

Ian Yates

unread,
Nov 19, 2015, 8:31:32 AM11/19/15
to KnockoutJS, andrew_...@hotmail.com
How many places in your code are you calling ko.applyBindings?  I tend to call it once per page and let view models own view models, etc.  

Are you calling applyBindings from a click handler?  If so, I think the OP's issue was that the click handler was running twice, so applyBindings was running twice, and causing the strange output.

Try to instead have a view model own a region on your page, and if there's dynamic content to come in later, set some observables on your view model and let the screen react to those observables changing rather than explicitly trying to manage applyBindings calls.
Reply all
Reply to author
Forward
0 new messages