jQuery document ready with Knockout.js - javascript

I just got thrown into the Umbraco ASP.NET CMS for my latest project, I'm not sure if this is how it across the board but for my setup Knockout.js is doing all the templating.
I'm not too keen on knockout.js but so far it's been pretty straight forward except for when I start adding in some jQuery stuff, the problem I'm having is jQuery is firing before knockout has finished populating the page with all the elements.
The only solution that's worked for me thus far is all my jQuery stuff is wrapped in the setTimeout() function, which obviously is no good.
What's the most efficient way to make jQuery and Knockout work together so jQuery doesn't before knockout is done?

I recently had the same issue with the jSignature plugin and my Knockout view. I needed the KO view to have fully rendered before I invoked jSignature, otherwise it didn't size itself correctly.
I fixed it with a template binding and an afterRender callback function to invoke the jQuery work.
Here's the KO docs:
http://knockoutjs.com/documentation/template-binding.html
Here's a quick jsfiddle showing how you can use it:
http://jsfiddle.net/PCbFZ/
The trick is that you can use the afterRender callback of the template binding without actually using a template itself. Instead, you wrap all your existing HTML in a div that will invoke the afterRender callback:
<div data-bind="template: {afterRender: initApp}">
<!-- your existing HTML here -->
</div>
initApp is the function that does the jQuery work.
I think that should generally do what you need, though if your HTML is particularly complex, or you have many views you need to render inside the one page, you might need to do a bit more work. Let me know how you get on - maybe I can try to help a bit more if this doesn't quite fix your issue as easily as it did mine!
Update - following the comment from JACL below - here's an extended version of the fiddle showing this technique also working with ko-if. Each time you show/hide the 'widget' using the checkbox, a different random colour is applied to indicate the afterRender function doing its work.
http://jsfiddle.net/PCbFZ/15/

You might use:
$(window).load(function(){ /* code */ }); instead of $(document).ready();

Perhaps window.load instead of document.ready will do the trick

Related

Trigger jQuery function after page has loaded in AngularJS

I just started learning AngularJS and I'm not really familiar with the terminologies in AngularJS yet. Here's my concern, I created a Loading Animation that shows up when I go to pages, but then I want to stop the Loading Animation as soon as all the contents of the pages has loaded. It's fairly easy to do in plain jQuery since I can just trigger $(window).load() but it doesn't seem to work in angular. $(document).ready() seems to work but that's not what I actually need since it gets triggered even though the images are not finished loading yet. I already tried $scope.init inside my controller as well as $window.onload inside my controller but I still can't make it work.
Hotfix answer
Actually you do not need to wait for any of these events in angular.
Just use $().. in your angular controller - the site was already loaded. (similar to the window.load() event. In case jquery does not find the html elements please try to wrap it with $timeout( function() { ... } );
Recommendation
Please do not! There are angular ways to animate stuff which fits better than crazy $('#id'). logic. This will break in growing applications.
I would recommend you forget about jQuery when you are working on AngularJS application. So figure out how to work everything out in AngularJS way - move all jQuery logic that you have to angular controller and avoid direct DOM manipulation (jQuery way).
Also, there's a good tutorial online if you are moving to AngularJS from jQuery:
https://gabrieleromanato.name/introduction-to-angularjs-for-jquery-developers
If you need a solution for switching pages go with ui-router - it will give you even more flexibility with loading pages and resolving properties for different pages:
https://github.com/angular-ui/ui-router
And in this particular case you can use simple boolean property on $scope and show preloader div based on that:
<div ng-show="showOverlay" class="loader" />
then inside your controller you could put something like:
$scope.showOverlay = true;
and then after your page logic is loaded and promises are resolved you could just hide that preloader with:
$scope.showOverlay = false;
To illustrate I created simple fiddle with preloader for you. Also keep in mind there are tons of different ways of implementing this but this is simple one that should work for almost any case:
https://jsfiddle.net/pegla/ng1mn8qp/3/
There's also one answer here on stack overflow that could help you:
How to execute angular controller function on page load?

Calling jquery selector after Angular function not working (rendering issues?)

I'm having problems in several cases when attempting to update data / onscreen controls and then use these controls with jQuery, especially images. My present case is the following:
button click ---> call angularJs function that creates div controls on the screen ---> angularJS function at the end call JS function ---> JS function call JQuery selectors for the created divs.
The problem is that JQuery can't find the created divs.
What is the best/indicate solution for this case? (not only for this case, but for the cases where we need to wait for the dom render complete)
Regards.
There could be several cases that could apply depending on your implementation. First make sure jQuery doesn't override angularjs functionality or vice versa. Second angularjs makes any JavaScript code in script tags invalid. You have to include your JavaScript in your controllers. You can use debugging tools like Firebug to see what's going on. Posting some code here would also help a lot.

JqueryMobile issue when working with Knockoutjs

I found jquery mobile is not rendering correctly when the element is generated by knockoutjs (or probably not rendering correctly when element is generated dynamically). See the demo at http://jsfiddle.net/wRRZk/1/
updates:
One solution is to load jquery-mobile js file after KO binding finished as shown in http://jsfiddle.net/wRRZk/3/, however this doesn't solve the problem that jquerymobile render fail when changing KO model dynamically, as shown in http://jsfiddle.net/wRRZk/4/
I think you'll need to tell jQueryMobile to create those elements into the jQM enhanced version using the API. Check here :: http://jquerymobile.com/demos/1.1.1/docs/pages/page-scripting.html and look halfway down for "Enhancing new markup" and the section just below.
As for the create/refresh ... might need to be somewhat judicious in know when and where you're adding new stuff, and whether a create or refresh is needed.
I've done a new version of the jsFiddle here :: http://jsfiddle.net/wRRZk/5/.
I'm also removing from the model afterwards, which does seem to remove the links too, BUT, I think that may also be because the jQM enhancement is keeping the same anchor, thus the reference knockout as is still valid.
Not too sure how well that will work for the other enhancements done by jQM.

KnockoutJS bind event after template render

I've been searching for a while, and I'm pretty confident this is a new question, and not a repeat like the title suggests. :)
Basically, I'm trying to find out if there is a subscribe-able event that KnockoutJS creates after a template render when using something like jQuery templates.
I'd use the built-in "afterRender" but I found out that it doesn't fire if the observable array is cleared. I built this demo to illustrate that problem: http://jsfiddle.net/farina/YWfV8/1/.
Also, I'm aware that I could write a custom handler...but that seems really unnecessary for what I need.
I just want one event that fires after the template finishes rendering.
My colleague actually solved this last night using something we were playing with before I went home.
So the whole "problem" with the events “afterRender”, “afterAdd”, and “beforeRemove” is that they act differently in conjunction with a "foreach" binding. KnockoutJS is nice enough to tell you this on their page, but for whatever reason it didn't actually sink in for me until I saw it in practice.
What really works is to scrap the whole "foreach" binding and use Knockout's native "data" bind like this:
data-bind="template: { name: 'item-template', data: items, afterRender: caller }"
Then "afterRender" works exactly as the name suggests.
I was under the impression that you couldn't iterate the collection and render new UI without foreach, but these examples illustrate that it does work.
http://jsfiddle.net/farina/kuFx2/1/ (Using object array style ViewModel)
http://jsfiddle.net/farina/QtZm2/1/ (Using function style ViewModel)
I made an example for both ViewModel styles because I sometimes need one or the other.
Thanks for the help Dan!!
Is beforeRemove is what you are looking for? I am not sure what behaviour you want to achieve. Please checkout this sample: http://jsfiddle.net/romanych/YWfV8/8/
Is it what you want or not?

jQuery Mobile - Dynamically creating form elements

I'm creating a web-database driven offline web-app targeted at iOS devices. I'm trying to use jQuery Mobile, but I have a problem in creating the various forms.
The form options are taken from a database query, so they are inserted into the page after it has loaded, so the "jQuery-Mobilification" doesn't happen. Taking a quick look through the source, there doesn't seem to be any obvious way to call into this at this stage (of course it's an alpha release, and I think this would be a reasonably common request, so I'm hopeful it will come). Is there some kind of workaround I can put in to do this? I'm particularly interested in radio buttons, check boxes and select lists.
UPDATE
Beta2 has a create event. I will update my faq when the beta2 gets released. See http://jquerymobile.com/blog/2011/07/22/jquery-mobile-team-update-week-of-july-18th/
Updated faq: http://jquerymobiledictionary.pl/faq.html
As CaffeineFueled proposed - .page() is the way to make JQM work with any part of HTML
.page() can be called only once for an element. Call it on a wrapping element you add to the page. It should handle everything.
The current selected answer is slightly out of date. Use 'refresh', not 'page', for styling dynamically added content (lists or forms).
If you add items to a listview, you'll
need to call the refresh() method on
it to update the styles and create any
nested lists that are added. For
example, $('ul').listview('refresh');
via the jQuery Mobile docs, 1.0.4a
This is messing around in undocumented internals, but the following is working for me:
$("#some-div").load("/html/fragment/",
function() {
$(this).find("input").customTextInput();
});
There are equivalent methods for buttons, checkboxes etc.
Have a look at the _enchanceControls [sic] method in http://code.jquery.com/mobile/1.0a1/jquery.mobile-1.0a1.js.
Update for 1.0Alpha2: As can be expected when playing around with the internals of a library, this no longer works in the latest version. Changing customTextInput() to textinput() fixes it a bit, but the theme isn't fully applied for some reason. We were warned...
After your AJAX call finishes and you insert the form elements try calling:
$("#the-page-id").page();
I believe the jquery-mobile team will be adding a .refresh() method on the various UI elements to solve this issue in the future.
Yeah the issue is as you described. The 'mobilization' is fired when the document is ready. But since your offline DB queries are asynchronous it ends after the document.ready is fired. So the DOM is updated later in the process and doesn't have the extra CSS added to all the divs and list items.
I think you would have to change the source of the mobile js to not run on document ready but run when you tell it to run. Then you would have to call that function in your database callback.
Looks like that is the only option at the moment.
Traditionally I used jqtouch and now sencha. I haven't played much with jQuery mobile.
ALTERNATIVELY - you could write out your HTML after querying it out of the database with the necessary CSS styles on it. If you use Firebug plugin for Firefox you can see what styles / classes are getting applied when the mobilization runs. You could just write out your HTML using those conventions. Not ideal, but would work.
naugtur is right, you have to call .page() on any element that you add to the dom, then it works out nicely:
var el = $('<input type="text"/>')
el.page();
$('#something').append(el);
This worked for me (jquerymobile1.7.0):
$('#formular').append('<div data-role="fieldcontain" class="ui-hide-label">' +
'<label for="name" class="ui-hidden-accessible">Name:</label>' +
'<input type="text" name="name" size="25" id="name" placeholder="Name"/>' +
'</div>');
$('#name').textinput();
There are currently so called plugin functions for all kind of form elements (e.g. slider, textinput etc.) to create them.
Here's a link to the docs for this feature that Tom talked about. Not sure exactly when they were added, but I'm using it and it works for me!
http://jquerymobile.com/test/docs/forms/plugin-eventsmethods.html

Categories