When does Angular add a directive template to the DOM? - javascript

I need to use a Javascript library (scrollReveal) that assumes that the full DOM is ready. I am currently using AngularJS.
The problem is, I don't know when to initialize scrollReveal via
window.sr = new scrollReveal();
If I do this in the link function of one directive, it may not apply to the template of another directive, because the other template may not have been added to the DOM yet.
So I have two questions:
1) At what time is the directive template added to the DOM? Does it differ if I use template vs templateUrl?
2) How do I add in additional code that assumes a full DOM?
Thanks.

1) At what time is the directive template added to the DOM? Does it differ if I use template vs templateUrl?
You can use what you prefer.However, it is a much cleaner solution to write your html in a separate file. I personally prefer templateUrl because I think putting your html code into a string is not a good practice. But it has no difference when executing the code.
2) How do I add in additional code that assumes a full DOM?
$timeout is an Angular's wrapper for window.setTimeoutset. Timeout removes the function from the execution queue and it will only be invoked after JavaScript has finished with the current execution queue. So that is why your model will be updated before the excecution.
Here is an example:
$timeout(function(){
// template should be visible now
[,optional delay]);
$timeout will not run until digest cycle completes.

Related

AngularJS: Parse HTML events in timeline

During the debugging of my angularjs application, I found a lot of parse html events in the dev tools.
The timeline says that this event is invoked by jQuery.extend.buildFragment and it's hard for me to understand, what directive invokes parse html.
How can I detect, what exactly causes parse html events? Probably the reason could be in the ng-repeat, but I'm not sure.
These events slow down $scope.$apply as well.
Every partial html in angular will trigger Parse HTML event, like ng-includes, ng-repeats, directives, and $digest cycles.
Also using jQuery will give you a lot of overhead for initalize jquery instances. jQuery or jQlite buildFragment is called when you or directives or angular call element.html('something tags'), which in turn write to innerHTML which cause parse HTML event in browser and angular walk those children to find more directives and compile those until its complete.
To minimize those, you need to batch process those, but nature of angular will be hard to do directly. May be you can try to use one-time binding syntax :: in angular 1.3+ or make less watchers, so angular won't have to parse html again and again.

AngularJS: How can I initialize controller embedded with ajax loaded template?

I am loading an angular 'template' using ajax. This template renders a bootstrap modal form when I call $compile ... this works, everything fine here. But what I need is support of embedding controllers within this lazy loaded 'template' (Preferably I want to handle this client side so on server side everything can just look normal).
The thing is when I use ng-controller inside this template and define a function controller inside a script tag it fails. It tells me it cant find the controller function. I understand why this is happening, the script has not yet been initialized. I am just looking for a solution. How can I make the embedded script tags initialize first? Should I extract them, inject them somewhere and then compile the remainder? Or is there a more elegant way?
Lets have look in AngularJS documentation and show the integration with the browser event loop.
So you can see that AngularJS have its own event loop, which consists of three phases: compile, digest and apply.
When you call compile it will only loads the html markup and insert it. You should call apply also.
With apply you will set the execution scope. This will register an watcher that listens to changes.

AngularJS - Get elements in a factory when elements are in a ng-include

I'm trying to catch each "noscript" tag in my view.
I create a function in my factory, and call it when the controller is launched.
Here's my function :
angular.forEach(angular.element(document.querySelector('noscript')), function (value, key) {
// some code
The problem is that the "noscript" elements are in a ng-include, and it seems that the include is launched after the controller ..
Then, I can't catch the elements !
What is the best way to do that ?
Thanks by advance :)
You could write a directive that exposes a function for handling noscript tags within an include. You could call the function via the onload attribute of the ng-include.
Fiddle: http://jsfiddle.net/REYhN/
Please note, that you should avoid doing DOM manipulation in controllers. That's what directives are for: http://docs.angularjs.org/api/ng/service/$compile
Get it !
I called my controllers in my routes.. I read somewhere that it isn't a good practice.
Understand why now.
The solution is to call your controller in the partial via ng-controller.
And then, you can do whatever you want and get every dom elements :).
Not sure why you want to catch the noscript tags, but have you considered using modernizr instead of noscript tags?
w3c noscript
The noscript element is a blunt instrument. Sometimes, scripts might
be enabled, but for some reason the page's script might fail. For this
reason, it's generally better to avoid using noscript, and to instead
design the script to change the page from being a scriptless page to a
scripted page on the fly...

Remove helper HTML comments in Angular JS?

Is there a way to prevent Angular from creating "helper" HTML comments? For example,
<div ng-include="myTemplate"></div>
Will transform into something like
<!-- ngInclude: 'hurr-durr.html' -->
<div ng-include="myTemplate"></div>
How do I stop this? I've looked into the Angular source, and I've seen these "helpers" are generated by an unconditional document.createComment inside almost every directive, so I guess there's no way to stop them all at once by using a config setting on a provider or something.
But maybe there is some custom Angular build without "helpers"?
I suppose I could write some Yeoman/Grunt task to remove/comment the .createComment-s from Angular's source whenever I scaffold a new project. Or maybe you guys know of a fiddle that already does that? And also, this raises my last question:
Are those comments somehow crucial to the Angular's normal functioning? And if I remove them, will it cause some kind of instability in my app? Should a just rewrite the CSS and "deal with it"?
The comments are crucial to how Angular handles certain elements. Removing them is not currently an option. What issues are you having with it?
You are able to remove the contents of these angular comments, as well as some of the classes angular attaches to elements (e.g ng-scope) by adding this config to your angular module:
myApp.config(['$compileProvider', function ($compileProvider)
{
$compileProvider.debugInfoEnabled(false);
}]);
According to the angular.js docs, it is actually good to do this in production and should result in a performance boost.
From Angular Doc:
Disabling Debug Data By default AngularJS attaches
information about binding and scopes to DOM nodes, and adds CSS
classes to data-bound elements:
As a result of ngBind, ngBindHtml or {{...}} interpolations, binding
data and CSS class ng-binding are attached to the corresponding
element.
Where the compiler has created a new scope, the scope and either
ng-scope or ng-isolated-scope CSS class are attached to the
corresponding element. These scope references can then be accessed via
element.scope() and element.isolateScope().
Tools like Protractor and Batarang need this information to run, but
you can disable this in production for a significant performance boost
with:
myApp.config(['$compileProvider', function ($compileProvider) {
$compileProvider.debugInfoEnabled(false);
}]);
If you wish to debug an application with this information then you
should open up a debug console in the browser then call this method
directly in this console:
angular.reloadWithDebugInfo();
The page should reload and the debug information should now be
available.
For more see the docs pages on $compileProvider and
angular.reloadWithDebugInfo.

How to fire an event when a Knockout.js Template has been loaded

I'm using the knockout external templating engine to create a section of my webpage. The template has a ul inside of it that I would like to perform a function on.
<ul id="myTags"></ul
So, for instance, once the template has been loaded from the server, I would like to call some method:
$("#myTags").doSomething(...)
How do I call this method once the template has been downloaded from the server, and inserted into the document? NOTE This may happen more than once....
The template binding does have an afterRender callback that you could use to process the new elements: http://knockoutjs.com/documentation/template-binding.html#note_3_using_afterrender_afteradd_and_beforeremove
I don't know what you want to do with your element, but I would consider using a custom binding for this purpose. Custom bindings are described: http://knockoutjs.com/documentation/custom-bindings.html and http://www.knockmeout.net/2011/07/another-look-at-custom-bindings-for.html
Even if you just use the init function of your custom binding, it will run every time that your template is rendered.
The way that I'm doing this is using the jQuery livequery plugin:
$('#myTags').livequery(doSomething);
Is there a better way?

Categories