foreach not working after re-running ko.applyBinding

2,183 views
Skip to first unread message

Andrew Brownlee

unread,
Apr 23, 2013, 1:23:07 PM4/23/13
to knock...@googlegroups.com
I'm having an issues with arrays (or foreach) where is I run ko.applyBinding multiple times, the foreach data get messed up in one of two ways
  1. the foreach data does not get displayed on the second run.
  2. if I use cleanNode, then data get repeated.
here is a snip-it of the code

var CreateViewModel = function (item,array) {
           
var self = this;
           
//default the page to 1 for first call
           
self.thisData = ko.observable(item);
           
self.arrayData=ko.observableArray(array);
       
}
     
    $
("#click1").click(function () {
       
        ko
.applyBindings(CreateViewModel("one",array1),$("#one")[0]);
   
});


    $
("#click2").click(function () {
        ko
.cleanNode($("#two")[0]);
        ko
.applyBindings(CreateViewModel("two",array2),$("#two")[0]);
   
});
       
     
    $
("#click3").click(function () {
        ko
.applyBindings(CreateViewModel("two",array2));
   
});


and here is the html

<button id="click1">Set Data 1</button>
<div id="one">
 
<span>Result1 :  </span> <span data-bind="text: thisData"></span>
   
<br/>
 
<span>Result1 sub item :  </span> <span data-bind="text: arrayData()[2].userName"></span>
   
<br/>
   
<table>
       
<tbody id="body1"  data-bind="foreach: arrayData">
               
<td >
                   
<span data-bind='text: userName'/>
               
</td>    
               
<td >
                   
<span data-bind='text: userAge'/>
               
</td>            
       
</tbody>
   
</table>
</div>
<br/>
<button id="click2">Set Data 2</button>
<br/>
<div id="two">
 
<span>Result2 :  </span> <span data-bind="text: thisData"></span>
       
<br/>
 
<span>Result2 sub item :  </span> <span data-bind="text: arrayData()[2].userName"></span>
   
<table>
       
<tbody data-bind="foreach: arrayData">
               
<td >
                   
<span data-bind='text: userName'/>
               
</td>    
               
<td >
                   
<span data-bind='text: userAge'/>
               
</td>            
       
</tbody>
   
</table>
</div>
<br/>
<button id="click3">Set Global</button>

I have an example in jsfiddle show the issue more clearly 


initially on this fiddle no binding has been run...

If you press "Set Data One" , the first time the table will display correctly..
When you press "Set Data One" again, the second time, the table disappears.

If you press "Set Data Two" , the first time the table will display correctly...
When you press "Set Data Two" again , the second time, the table triplicates (as far as I can tell the data is not).

As a final check (after refreshing)  I set the binding globally (no second parameter on applyBinding)

If you press "Set Data Globally" , the first time the tables will display correctly...
When you press "Set Data Globally" again, the second time, the tables disappears.

if you press butting in other orders you get varying   results including massive tables that do not relate to the underling model.

on the other hand simple binding to individual elements appears to work fine always displaying what you would expect.

So does anyone have any ideas how to fix this issue or a workaround... is it a bug or am i missing something? 







Gunnar Liljas

unread,
Apr 23, 2013, 4:19:33 PM4/23/13
to knock...@googlegroups.com

You should never bind an element more than once. Manipulate the model, based on user input, but never rebind.


/g

Sent from Mailbox for iPhone


--
You received this message because you are subscribed to the Google Groups "KnockoutJS" group.
To unsubscribe from this group and stop receiving emails from it, send an email to knockoutjs+...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Andrew Brownlee

unread,
Apr 24, 2013, 5:14:07 AM4/24/13
to knock...@googlegroups.com
I'm sure I've seen advice (on other sites) that recommend re-applying binding to address other issues(dynamic HTML with binding etc). I guess I'll try and re engineer my code to take this in to consideration.

Cheers for the quick response.

soha...@gmail.com

unread,
May 20, 2013, 8:27:35 AM5/20/13
to knock...@googlegroups.com
Well i have the same issue, as I am using a control which generates dynamic html and so I have to ribind !
Any solutions to this foreach data re bind issue ?

Uğur Tılıkoğlu

unread,
May 20, 2013, 9:21:56 AM5/20/13
to knock...@googlegroups.com
hi sohaibuit,

did u try these steps? it may work for ur scenario

- generate the html content
- wrap it via $dyn = $(dyncontent);
- u must have an inner viewmodel for the dynamic content. bind it via ko.applyBindingsToNode(innerVm, $dyn.get(0))
- add the element to DOM as $(document).append($dyn)

mayankkh...@gmail.com

unread,
Sep 13, 2014, 6:18:53 PM9/13/14
to knock...@googlegroups.com
Hi,

I am also facing the same issue  - I have a Foreach insie the main div.

While First time  - Its working fine with Foreach.

  var CatalogView = new CatalogViewModel(result);
  ko.cleanNode($("#dlgMyVideoDetails")[0]);
   ko.applyBindings(CatalogView, $("#dlgMyVideoDetails")[0]);

Cancel  - > Open the Item Again call the same function and hitting above line again - 
Its repeating the rows like your case.

Have you find the solution for yours?

Gunnar Liljas

unread,
Sep 14, 2014, 2:16:04 AM9/14/14
to knock...@googlegroups.com
You should allow the binding system to take care of this. Not call cleanNode and applyBindings more than once.

You can modify the existing viewmodel...

CatalogView.loadResult(result)

or wrap in an observable

First time:

var vm={
  catalog:ko.observable()
}
ko.applyBindings(vm,....)

vm.catalog(new CatalogViewModel(result))

Use a "with:catalog" in the binding html.



--
You received this message because you are subscribed to the Google Groups "KnockoutJS" group.
To unsubscribe from this group and stop receiving emails from it, send an email to knockoutjs+...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

mayankkh...@gmail.com

unread,
Sep 14, 2014, 3:56:05 AM9/14/14
to knock...@googlegroups.com

Hi ,

 
Actually I have that ViewDetail Function which is outside the VM  in the same js file and opening the Popup,Please allow me to re create the scenario again  - 

MyVideo.js - 

InSide the CatalogViewModel() in same file

var CatalogViewModel = function (CatalogJSON) {


    var self = this;
   self.oTechnicalDetails = ko.observableArray(Details.oTechnicalDetails);

}

OutSide the CatalogViewModel() in same file

  var dialogContent = '<div><table><tr>'
  
   '<td class=" ellipsis td-transparent" colspan="2" "><span class="lnkEdit" onclick="ViewDetail(&quot;' + videoData[0].Id + '&quot;)" style="font-weight:bold;text-decoration: underline !important;">View Full Metadata<img src="' + siteBase + 'Content/Images/icons/EditMetaData.png" /></span></td>' +
   '</tr></table></div>' ;

 $("#dialogVideo").html(dialogContent);


Calling ViewDetail Function 

this.ViewDetail = function (AssetId) {


    $.ajax({

        url: siteBase + "Secure/Content/Catalog/Detail?assetId=" + AssetId,
        type: "POST",
        dataType: "json",
        success: function (data) {
          
            onGetCatalogDetail(data, '');

            $('#dlgMyVideoDetails').css('display', 'block');
            $('#dlgMyVideoDetails').popup();

            $("#dlgMyVideoDetails").focus(true);


        },
        error: function (ex) {

            alert("error");
        }


    })

this.onGetCatalogDetail = function (receive, textStatus) {

   
    result = $.parseJSON(receive.Output);
    if (result != undefined) {

       
        var CatalogView = new CatalogViewModel(result);
        
        ko.cleanNode($("#dlgMyVideoDetails")[0]);
        ko.applyBindings(CatalogView, $("#dlgMyVideoDetails")[0]);

        //ko.applyBindings(CatalogView.oTechnicalDetails(), $("#dvAssetDetailPopUp")[0]);


    }
};



Then  -  oTechnicalDetails array loading correctly

1> First Time Loading correctly
2> Cancel will close the popup and go to back page , Now Again click on view Meta Data Link and it will call "View Detail Function"[Outside the VM]
     Its repeating the oTechnicalDetails rows equivalent to no of actual rows[or index].We cant take this View Detail Function inside the VM as its calling from outside world where we are       creating dynamic content td tr for a dialogue and having View Meta Data Link for opening my Popup.And we cant remove ko.applyBindings(CatalogView, $("#dlgMyVideoDetails")[0]); as its binding the data in first time also and if we remove that then popup will not showing anything.


Please suggest the solution

Thanks and appreciated.
Reply all
Reply to author
Forward
0 new messages