I know that even if ngShow evaluates to false, it still performs dirty checking inside the directive.
So does ngShow (like ng-show=false):
compose the DOM inside ngShow (since it has to do $compile) and then hides/removes the contents, or
only performs dirty checking without the cost of creating DOM elements?
ng-show will only set the elements to display: none. So they will still be in the DOM and still be dirty checked by angular.
Try using something like ng-switch for actually removing elements from the DOM. http://docs.angularjs.org/api/ng.directive:ngSwitch
Angular.js doesn't create any DOM nodes during the compilation. It lets the browser build the DOM then simply goes through it and collect the directives.
So if the nodes are in your templates, they will indeed be created, but by the browser, not Angular.
Related
Is there any case when I don't need an ngCloak directive?
It seems that every tag that somehow uses Angular library needs to define this directive either via ng-cloak attribute or class="ng-cloak".
Is there any downside of using this directive for every possible element?
ng-cloak will cause your element not to render straight away. Often elements will look fine without ng-cloak, in which case it would be strange to opt for a blank space.
This will often be the case if you are not using the {{x}} syntax. Perhaps you could use ng-bind instead.
Lots of elements will not be in the DOM at page load. For example, the template of a directive will obviously not be available until after the digest cycle has already run. It would be strange to try to cloak something which was not visible in the first place.
Using ng-cloak more than you need to will just hurt performance.
I am developing a custom directive and now I need to handle ng-if. This is easy enough when ng-if is on the directive it self. However when ng-if is on an enclosing container element my compile function fails with run time errors.
Question is: what is the best and most efficient way to know, inside the compile function of a directive, that the directive is enclosed within a container with ng-if is false OR an expression that evaluates to false.
For example:
<div ng-if="false">
<my-directive></my-directive>
</div>
And another example:
<div ng-if="somescopeValue > 300">
<my-directive></my-directive>
</div>
Maybe the answer is using jquery to traverse the dom and find a parent with
an ng-if attribute but I was wondering if there is another more "angular" way of doing this.
Your directive shouldn't rely on knowing whether it is encapsulated in a ng-if expression. That breaks the principle of 'Separation of Concerns' and deteriorates code re-use. Consider redesigning your custom directive in such a way that it needs not be aware of its host elements, in the same fashion that all components (should) work.
If you are using same scope as parent controller or directive then you are able to access same variable in your directive(here my-directive) also. If this is not a case then you need to write code to access parent element in link function of my-directive. You will get directive element in link function as a parameter.
I'm not sure how the error happens, because when your directive is inside ng-if="false", your directive won't get called at all - all compile, link and controller function in the directive will only run as soon as your directive gets added in DOM.
Perhaps your error can be solved by initializing something in case your directive is not added.
I need to conditionally apply ng-disabled to an element that is enclosed by a controller but does not exists at time of original compile. It is created later on by an AJAX callback and needs to be enabled/disabled based on certain conditions. I guess it needs a directive, but how do I go about it?
I need to use ng-disabled and no other solution as it is well handled by IE<11, which do not support pointer-events.
The real code is too complicated to be quoted here, but let me rephrase the problem.
A jQuery lib does something like:
$.get(url, function(){
$('<a class="btn"/>').appendTo(myDiv)
});
myDiv is within an angular controller. The <a/> element does not exist at time of compilation/directive linkage. Right after it gets appended, I should call some code to test and apply ng-disabled condition. Should it be a directive or a watch?
You could create a directive with an ngIf (so that it's created just when ngIf condition equals true. You can enable this condition after the response returns). Then in the link function you could:
link: function( scope, element, attrs ){
element.removeAttr("name-of-the-directive");
element.attrs("ng-disabled", "{{myExpression}}");
$compile( element)(scope);
}
The line element.removeAttr("name-of-the-directive"); is necessary to avoid infinite compiling loop.
When you're inserting code into the DOM manually, you need to compile it and link it to your scope first.
If your use-case allows it, you could try using ng-bind-html in your template and then just put the loaded code into a $scope property without needing to $compile it yourself.
I have multiple custom directives in my ngApp. The demo code is:
<top-nav></top-nav>
<left-sidebar></left-sidebar>
<div class="content">
....
</div>
The height of the 'left-sidebar' needs to be adjusted according to the height of the 'top-nav'.
Similarly there are other interdependent UI tasks. I want to run the post-load code (say app.initializeUI();) only after ALL the directives have been loaded and rendered.
Now, How do I achieve that?
EDIT :
Currently I am using the following code :
App.run(function($timeout){
$timeout(function(){ app.init() },0);
});
This runs fine, however, I am not sure this is the perfect way of doing this.
EDIT 2:
For people who want to avoid setting styles in js - use CSS Flexbox. I find it much better than calculating heights post page load. I got a good understanding of flexbox here
I would create an attribute directive with isolated scope, set terminal=true and add it to your body tag. Then in your link function, setup a $watch - isInitialized which is initially false. In your $watch handler, call your app.init(), and then de-register the $watch, so that it is always initialized once.
Setting up a terminal directive has consequences - no other directive can run after the terminal directive on the same element. Make sure this is what you want. An alternative is to give your directive the lowest possible value so that it is compiled first, and linked last.
The important pieces to this solution are:
By adding your Directive to the body tag, you ensure that it is linked last.
By adding a $watch, you ensure that all other directives have gone through a digest cycle, so by the time your $watch handler is called, all other directives should have already rendered.
Note of caution: The digest cycle may run several times before scope changes stabalise. The above solution only runs after the first cycle, which may not be what you want if you really want the final rendering.
I have two custom directives define in my project:
<include-partial> - element directive which gets template via $http service, compiles it and inserts into DOM
on-show="someFn()" - attribute directive, which should call some function when the element becomes visible
I'd like to combine the two, so that I could write code like this:
<include-partial on-show="init()">
This, however won't work, as the content of <include-partial> is fetched asynchronously, so on-show has no DOM to attach to.
Do you have any ideas how to tackle this? How could I force on-show to wait until the <include-partial> is done compiling the DOM?
Thx in advance!
In your case "on-show" is never trigger because "include-aprtial" tag don't changes it's visibility. Try to hide "include-partial" in link function and show on content load.