How does document.ready work with angular element directives? - javascript

In my current project I'm using angular directives to create custom html elements. See example below.
banner.js
app.directive('banner', function () {
return {
restrict: 'E',
replace: true,
templateUrl: './common/banner/banner.html'
};
});
Banner.html
<div>
<div class="banner-image"></div>
</div>
Issue: There is a javascript file that adds additional properties to elements with the banner-image class after document.ready. This worked perfectly before using angular element directives, but the properties are no longer being added.
Question: Does the document.ready callback occur prior to angular element directives being rendered in the dom? If so, that could explain why my javascript file is no longer making the necessary changes to the html elements.
Thank you

This is less a "directives" question, and more an Angular sequence of events question.
Angular itself (if not manually started with .bootstrap) will defer its loading until .onready.
At that point in time, Angular expects that all JS it needs to run will be there and registered.
Then Angular starts up.
Then after Angular starts up, Angular parses the DOM to find a root element to attach to (the one with the ng-app directive).
Then it recursively goes down the line, injecting controllers and building out directives and interpolating nodes as it goes.
Now we are way past any code that would have fired on DOMReady.

Related

Angular directive loading order.

I have a view containing two nested directives. The inner-directive depends upon the outer-directive to be present. When I load the page from scratch the directives are loaded as expected i.e the outer exists before the inner. But when I navigate from the page and then return, the order of directive-loading is reversed i.e the inner-directive is loaded before the outer-directive. Both directives are costume directives. When I change the outer-directive to instead being a ng-controller, the problem is solved. To perform the navigation ui-router is used. Does anybody know how to solve this issue without having to use a ng-controller as the outer-directive? And why ng-controller solves the problem?
<div outer-directive>
<inner-directive></inner-directive>
</div>
Without knowing a ton about your specific directives, you can take a look a this blog post about directive priority.
(Controller gets processed in a different cycle than directives, so it makes sense that putting whatever 'dependent' code inner-directive requires into a controller solves your problem).
Here's the interesting part: Angular will follow, it appears, this "path" for your nested directives:
outer-directive: compile
inner-directive: compile
outer-directive: pre-link
inner-directive: pre-link
inner-directive: post-link
outer-directive: post-link
The linked blog post explains "why," but this processing order explains your discrepancy between initial page load (where compile is run for the directive) and your page-back case (where the directive is already compiled and we just need to link).
Again, without knowing much about your directives, maybe you need to relocate the dependent outer-directive code into pre-link (instead of link) so that it gets processed first?
You do that by breaking up your Link object into:
Link: {
pre: function(){
},
post: function() {
}
}
Still need help, [here's a decent post] (http://www.undefinednull.com/2014/07/07/practical-guide-to-prelink-postlink-and-controller-methods-of-angular-directives/) on the breaking up link into pre/post.

AngularJS with jQuery DataTables intermittently working

I'm adding AngularJS to a project that is heavily dependent on jQuery's datatables plugin.
In my angular view, I have the datatables code (which only loads when the view is loaded).
Ex:
$('#datatable').DataTable();
In my layout, which is rendered by the server (everything else is rendered by the client), I have <script> tags for each of the JavaScript files.
However, when I load the page, all of the data comes in without the pagination and when I click a sorter (up or down), I see my Angular templating i.e. {{record.name}} and {{record.time}} in the first row and my data disappears.
The only table that is working with jQuery datatables is a table with a very small amount of records (6). Even then, it works intermittently.
This has lead me to believe that it's a problem with some data loading before/after (depending on the amount of data) the scripts do.
I know there are alternatives and directives out there, but I have yet to find one that works properly and does everything the native plugin does. So please, do not suggest any of those to me.
If it is a problem with the order of the data/scripts loading and one needs to load before another, I'm fine with adding a delay until everything has finished loading.
Does this seem like it's the problem? How can I test this?
Edit:
Another note to take: when everything has finished loading, and I enter in the console $('#datatable').DataTable(); it applies all of the datatables features.
The datatables code in my angular view is surrounded in a $(function() { //code });
This is how I get the data (for every table):
app.controller('PaymentsCtrl', function($scope, Payments) {
Payments.get()
.success(function(data) {
$scope.payments = data.payments;
});
});
I then run an ng-repeat on the table's <tr>
Directives are the correct way to wrap external libraries, so that's how you would want to invoke your DataTable. I haven't used jquery DataTables with Angular before, since it's a bit of an anti-pattern (though I understand it's unavoidable here), but if it's merely a case of invoking $().DataTables() at the correct time, then this directive should do it - keep in mind that jquery and datatables' tags should be included BEFORE angular.js so that Angular replaces jqlite with jquery internally - this way, the element param here is automatically wrapping the element with jquery for you, and should allow you to call the DataTable function.
angular.module('yourModule').directive('datatable', function() {
return {
restrict: 'AC',
link: function(scope, element, attrs) {
element.DataTable();
}
}
});
With that directive, rather than giving your table an ID #datatable, just add a "datatable" class or attribute and let the directive handle it from there!

angularjs - After changing views using routing the jquery elements doesn`t get rendered

My issue is that after changing views using routing, the jquery components in my page doesn´t get rendered. I have customized ui components like dropdowns that are not being processed. I saw this answer: Angular.js App with routing.. Cannot get jquery ui layout plugin working on 2nd view
But I can´t figure out how to make it work in my case. It seems that when angular renders the template, any but angularjs code is processed.
Thanks so much in advance.
Code: http://plnkr.co/1mwMcsqMxWGTheoQmJ22
In the example you've provided, you're not actually loading the file with the jQuery code in it (jqcode.js).
The real problem however, as you can see in this version of your example, is that the document ready event is executed before your template has been loaded and rendered. This means that the element your jQuery code is attempting to target does't exist when you try to manipulate it.
You should really look into Angular directives which is where you are advised to place any DOM manipulation logic within an Angular project:
If you have to perform your own manual DOM manipulation, encapsulate
the presentation logic in directives.
From the Angular documentation for controllers.

Difference between the directives and static DOM elements in AngularJS

I have already read the
Compilation process, and directive matching
on AngularJS Doc.
but I really didn't understand the directives.
Example:
I have static html:
<div class="test test2" cid="549" sid="a5e3c4f8a9">text-text-text</div>
when I do it manually, I know it will only created and called one time at browser's parse time.
but what happens when I create a directive with the same dom element ?
<x my-directive>text-text-text</x>
is this the same effect?
I am asking such a newbie question, because I am using over 200 elements on my html page.
If I change them to single directive: for sure it will be much more easier to manage them.
and its no problem if its only slow at browser's compile time but what happend in run time?
and I am sorry, if the qustion is not pro enought. I am just new to Stackoverflow.
Thank You
Daniel
If I understand you correctly, you want to know how AngularJS creates a directive and how many times your directive methods are called.
When you create a directive (with module.directive('myDirective', ...)), you are really just creating a definition. Every time you use that directive (like <div my-directive>), AngularJS will run through the process described in the guide: that is, it will compile and link each use. It has to be this way because the directive doesn't exist in isolation; it exists not only in the $scope in which it was called, but also it can make use of element attributes and transcluded contents. The definition occurs once, but each instance is compiled and linked.
Once the directive is created, it's technically done; if you don't set up any $watch or $observe or event bindings, your "directive" is now just whatever's in the DOM at the end of your link function - there's no more computation. In other words, what happens after compilation and linking is entirely up to you.
So back to your example: if you use 200 of the same directive on the page, the directive will be defined once, but all 200 will be compiled and linked separately. But I'm not really sure what you're implying by asking. What's the question behind your question?

Angular JS/Dojo widget parsing

I have an Angular JS application, in which I would like (actually I MUST) use dojo widgets. In the HTML template for the controller, I can return HTML that has dojo markup in it. However, the dojo parsing doesn't happen automatically when a view gets re-rendered. The only way I have been able to trigger reparsing is by manually calling the parser after a slight delay by doing something like this in the controller and then calling it when I know the model has changed.
refreshDojo = function() {
setTimeout(function() {
require(["dojo/parser"], function(parser) {
parser.parse()
});
}, 10);
}
This isn't really feasible for two reasons:
Having to do anything after a timeout is bound to cause trouble by
either happening to quickly before the html has been processed or
two slowly, causing a flash of content before the widgets are
created.
Secondly, if I am not mistaken, parser.parse() parses the whole DOM
which is not very efficient if I only updated a single div.
Is there a way to know for certain when the DOM has stabilized so that I can be sure to trigger this at the right time? And is there a way to access the root element of the controller (It appears that you can no longer inject $element)?
You should decorate the $compile service, so before angular compiles anything it will let dojo compile it.
Here's a small example:
http://plnkr.co/edit/9iJJFLWDqGtyqLV5Mbe3?p=preview
Documentation on decorators: http://docs.angularjs.org/api/AUTO.$provide#decorator
You could create an attribute directive dojoType that requires the named widget module (and mixins if needed) and instantiates them instead of the dojo parser.
For example, if you've loaded a part of the DOM ('ajax'), then you would first create a new scope for it, compile and link it against the scope (the dojoType directive gets applied), then you would call the dojo parser and specify the rootNode.
dojoParser.parse({
rootNode: dom.byId(domid)
}).then(/* access the widgets or whatever */);

Categories

Resources