Successful callback after knockout.js completes, rendering all elements

I implemented a foreach knockout binding with several templates on one page, here is one example, I am interested to know when the block finishes rendering, I tried afterRender and afterAdd , but I assume that it is executed for each element, and not after the end of the whole cycle .

 <ul data-bind="foreach: {data: Contacts, afterAdd: myPostProcessingLogic}"> <li> <div class="list_container gray_bg mrgT3px"> <div class="list_contact_icon"></div> <div class="contact_name"><span data-bind="text: first_name"></span> <span data-bind="text: last_name"></span></div> <div class="contact_number"><span data-bind="text: value"></span></div> <div class="callsms_container"> <a href="#notification-box" class="notifcation-window"> <div class="hover_btn tooltip_call"> <div class="hover_call_icon"></div> <span>Call</span></div> </a> <a class="sendsms" href="#sendsms" rel="#sendsms"> <div class="hover_btn tooltip_sms"> <div class="hover_sms_icon"></div> <span>SMS</span></div> </a> <a href="#"> <div class="hover_more_btn"></div> </a> </div> <!-- close callsms container --> <div id="notification-box" class="notification-popup"> <a href="#" class="close"><img class="btn_close" src="images/box_cross.png" /></a> <img class="centeralign" src="images/notification_call.png" /> <span>Calling... +44 7401 287366</span> </div> <!-- close notification box --> <!-- close list gray bg --> <div class="tooltip_description" style="display:none" id="disp"> asdsadaasdsad </div> </div> </li> </ul> 

I'm only interested in learning the success callback when the loop completes the rendering.

here is my afterAdd function, which basically attaches some jQuery events and nothing special.

 myPostProcessingLogic = function(elements) { $(function(){ $(".list_container_callog").hover(function(){ $(".callsms_container", this).stop().animate({left:"0px"},{queue:false,duration:800}); }, function() { $(".callsms_container", this).stop().animate({left:"-98%"},{queue:false,duration:800}); }); }); } 

Thanks in advance and say there is a success callback :)

+46
jquery foreach
Jan 10 '13 at 9:15
source share
7 answers

You have an afterRender in knockout.js :

 foreach: { data: myItems, afterRender: renderedHandler } 

Here is the documentation.

Inside the handler, check if the length of the selected collection is equal to the length of the collection of elements. If you do not complete the full visualized logic that you are going to use.

 renderedHandler: function (elements, data) { if ($('#containerId').children().length === this.myItems().length) { // Only now execute handler } } 
+66
Jan 10 '13 at 9:19
source share

Try to wrap ul with

 <div data-bind='template: {afterRender: myPostProcessingLogic }'> 

It will work only for the first time, when everything that is inside the template will be displayed. But you only get one call to myPostProcessingLogic. Here fiddle

 <div data-bind='template: {afterRender: myPostProcessingLogic }'> <ul data-bind="foreach: Contacts"> <li> <div class="list_container gray_bg mrgT3px"> <div class="list_contact_icon"></div> <div class="contact_name"><span data-bind="text: first_name"></span> <span data-bind="text: last_name"></span></div> <div class="contact_number"><span data-bind="text: value"></span></div> <div class="callsms_container"> <a href="#notification-box" class="notifcation-window"> <div class="hover_btn tooltip_call"> <div class="hover_call_icon"></div> <span>Call</span></div> </a> <a class="sendsms" href="#sendsms" rel="#sendsms"> <div class="hover_btn tooltip_sms"> <div class="hover_sms_icon"></div> <span>SMS</span></div> </a> <a href="#"> <div class="hover_more_btn"></div> </a> </div> <!-- close callsms container --> <div id="notification-box" class="notification-popup"> <a href="#" class="close"><img class="btn_close" src="images/box_cross.png" /></a> <img class="centeralign" src="images/notification_call.png" /> <span>Calling... +44 7401 287366</span> </div> <!-- close notification box --> <!-- close list gray bg --> <div class="tooltip_description" style="display:none" id="disp"> asdsadaasdsad </div> </div> </li> </ul> </div> 
+10
Apr 11 '14 at 15:19
source share

Just wrap foreach in another foreach loop using a smaller knockout method, for example:

 <!-- ko foreach:{data: Contacts, afterRender: myPostProcessingLogic }--> <ul data-bind="foreach: $data}"> <li> <div class="list_container gray_bg mrgT3px"> <div class="list_contact_icon"></div> <div class="contact_name"><span data-bind="text: first_name"></span> <span data-bind="text: last_name"></span></div> <div class="contact_number"><span data-bind="text: value"></span></div> <div class="callsms_container"> <a href="#notification-box" class="notifcation-window"> <div class="hover_btn tooltip_call"> <div class="hover_call_icon"></div> <span>Call</span></div> </a> <a class="sendsms" href="#sendsms" rel="#sendsms"> <div class="hover_btn tooltip_sms"> <div class="hover_sms_icon"></div> <span>SMS</span></div> </a> <a href="#"> <div class="hover_more_btn"></div> </a> </div> <!-- close callsms container --> <div id="notification-box" class="notification-popup"> <a href="#" class="close"><img class="btn_close" src="images/box_cross.png" /></a> <img class="centeralign" src="images/notification_call.png" /> <span>Calling... +44 7401 287366</span> </div> <!-- close notification box --> <!-- close list gray bg --> <div class="tooltip_description" style="display:none" id="disp"> asdsadaasdsad </div> </div> </li> </ul> <!-- /ko --> 
+4
Jun 13 '14 at 8:09
source share

Chuck Schneider's answer above is the best. I had to use control without a container since foreach is on the tbody element:

 <!-- ko template: {afterRender: SetupCheckboxes } --> <tbody data-bind="foreach: selectedItems" id="gridBody"> <tr> <td> <input type="checkbox" /> </td> </tr> </tbody> <!-- /ko --> 
+3
Sep 06 '16 at 5:15
source share

The solution above works fine. Also, if you need to use the foreach "like" option, you can do it like this:

 data-bind="foreach: { data: myItems, afterRender: renderedHandlet, as: 'myItem'}"> 
+1
Feb 10 '14 at 20:22
source share

I just recently made a knockout upload request for them to add two events to define in binding, expand, then call the correct points before rendering the elements and after all the elements have been displayed. I have not heard anything from them, but it does exactly what you want to do, but you do not need to write hacker code to make it work. I am surprised that no one has done this before. I used these callbacks that I added to the source to destroy and reinitialize the knockout related jquery datatable. This was the easiest solution. I have seen many online attempts that try and do it differently, but this is the easiest solution.

Pull request: → pr 1856

 ko.bindingHandlers.DataTablesForEach = { init: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) { var nodes = Array.prototype.slice.call(element.childNodes, 0); ko.utils.arrayForEach(nodes, function(node) { if (node && node.nodeType !== 1) { node.parentNode.removeChild(node); } }); return ko.bindingHandlers.foreach.init(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext); }, update: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) { var value = ko.unwrap(valueAccessor()), key = "DataTablesForEach_Initialized"; var newValue = function() { return { data: value.data || value, beforeRenderAll: function(el, index, data) { if (ko.utils.domData.get(element, key)) { $(element).closest('table').DataTable().destroy(); } }, afterRenderAll: function(el, index, data) { $(element).closest('table').DataTable(value.options); } }; }; ko.bindingHandlers.foreach.update(element, newValue, allBindingsAccessor, viewModel, bindingContext); //if we have not previously marked this as initialized and there is currently items in the array, then cache on the element that it has been initialized if (!ko.utils.domData.get(element, key) && (value.data || value.length)) { ko.utils.domData.set(element, key, true); } return { controlsDescendantBindings: true }; } }; 

Knockout Datatables JSFiddle

0
Jun 05 '15 at 17:41
source share

Try the afterRenderAll callback in knockout.js:

foreach: {data: myItems, afterRenderAll: myPostProcessingLogic}

0
Dec 17 '17 at 22:07
source share



All Articles