ngIf
This attribute directive takes a boolean value, equation, or function that returns a boolean, as a value. When this value evaluates to true, then the element the attribute is on and all it's children elements are removed from the DOM.HTML
Given this HTML as written:<button ng-click="changClicked()"></button>
<p>This will always show</p>
<p ng-if="getClicked()">
This will show if clicked is true.
</p>
<p>This will always show</p>
This is what is rendered in the browser when the value evaluates as true:
<button ng-click="changClicked()"></button>
<p>This will always show</p>
<!-- ngIf: getClicked() --><p ng-if="getClicked()" class="ng-scope">
This will show if clicked is true.
</p><!-- end ngIf: getClicked() -->
<p>This will always show</p>
And when the value evaluates as false:
<button ng-click="changClicked()"></button>
<p>This will always show</p>
<!-- ngIf: getClicked() -->
<p>This will always show</p>
As you can see, AngularJs completely removes the element from the DOM, leaving behind only a placeholder.
When the element is brought back into the DOM it is returned in it's initial state, at the time of the page load. This means that any modifications you've made to this part of the DOM using jQuery or native JavaScript, etc., will be gone. This is definitely one of the times that you should never leave the AngularJs bubble whilst running.
CSS
One concern when using ngIf is that due to the elements being removed from and recreated in the DOM you need to be careful when using psuedo-classes. When an element is added or removed from the DOM the browser will recalculate the CSS and re-apply styles based on the new structure. This can be a really positive thing if you're design relies upon only certain elements having a particular style, such as margins in a grid layout, or alternate styling. Given this CSS:p:nth-child(odd){
background-color: deepskyblue;
}
p:nth-child(even){
background-color: greenyellow;
}
An ngIf element and it's siblings would appear like this whilst it's visible:
And it's siblings would look like this whilst it isn't:
This is really desirable to me, and is nearly always the reason why I use ngIf over ngShow / ngHide.
JavaScript
When the element is injected back into the DOM it is recreated from it's initial state as upon removal it's scope is destroyed along with all the changes on that section of the DOM from outside the AngularJs bubble. Be careful at this point as you could lose any user input that you've received within this element before it was removed. When the element is recreated the scope is recreated using prototypal inheritance from the parent scope. If you try to attach your user input to the parent scope it will be lost upon removal of the element as well.Another thing to consider is that by removing all of your AngularJs within this element when it's not visible to the user means that it isn't being touched during every digest cycle. This is a huge performance boost, which may not be noticeable on desktop but can be on mobile devices. I'm always amazed at how many times things get hit each digest cycle, so keeping as much out of the cycle as possible is always a really positive thing to do.
ngShow / ngHide
Both of these directives take a boolean value, equation, or function that returns a boolean, as a value. Both use the CSS display property to either show or hide the element based on whether the value equates to true. For ngShow, the element is visible when the value is true. For ngHide, the element is visible when the value is false.HTML
Given this HTML as written:<p>This will always show</p>
<p ng-show="getClicked()">
This will show if clicked is true.
</p>
<p>This will always show</p>
<p ng-hide="getClicked()">
This will show if clicked is false.
</p>
<p>This will always show</p>
This is what is rendered in the browser when the value of ngShow and ngHide evaluate as true:
<p>This will always show</p>
<p ng-show="getClicked()" class="">
This will show if clicked is true.
</p>
<p>This will always show</p>
<p ng-hide="getClicked()" class="ng-hide">
This will show if clicked is false.
</p>
<p>This will always show</p>
And when the value of ngShow and ngHide evaluate as false:
<p>This will always show</p>
<p ng-show="getClicked()" class="ng-hide">
This will show if clicked is true.
</p>
<p>This will always show</p>
<p ng-hide="getClicked()" class="">
This will show if clicked is false.
</p>
<p>This will always show</p>
As you can see, ngHide is added to the element when it's ngShow / ngHide value evaluates so that the element should not be visible. The styling for this is
display: none !important;
, which is built into AngularJs. You could also attach styles to this hook, but that important flag is going to be pretty hard to overrule.You can also use ngAnimate which allows you to use ngEnter and ngLeave as styling hooks. I'll blog about that some other time.
CSS
As ngShow and ngHide usedisplay
to change the element's visibility any styling from psuedo-classes that rely on how many elements there are in the structure will continue to count the elements regardless of their visibility. This means that something such as alternate styling would break whilst an element is hidden using ngShow or ngHide. Given this styling:p:nth-child(odd){
background-color: deepskyblue;
}
p:nth-child(even){
background-color: greenyellow;
}
The rendering of the DOM would appear like this when an element isn't showing:
This clearly isn't what is intended, and in this example the only problem is that it isn't very pretty. However, this affect in a grid layout would be disastrous as widget would be spaced in unintentional ways.
No comments:
Post a Comment