536

I understand that ng-show and ng-hide affect the class set on an element and that ng-if controls whether an element is rendered as part of the DOM.

Are there guidelines on choosing ng-if over ng-show/ng-hide or vice-versa?

XML
  • 19,206
  • 9
  • 64
  • 65
Patrice Chalin
  • 15,440
  • 7
  • 33
  • 44

7 Answers7

723

Depends on your use case but to summarise the difference:

  1. ng-if will remove elements from DOM. This means that all your handlers or anything else attached to those elements will be lost. For example, if you bound a click handler to one of child elements, when ng-if evaluates to false, that element will be removed from DOM and your click handler will not work any more, even after ng-if later evaluates to true and displays the element. You will need to reattach the handler.
  2. ng-show/ng-hide does not remove the elements from DOM. It uses CSS styles to hide/show elements (note: you might need to add your own classes). This way your handlers that were attached to children will not be lost.
  3. ng-if creates a child scope while ng-show/ng-hide does not

Elements that are not in the DOM have less performance impact and your web app might appear to be faster when using ng-if compared to ng-show/ng-hide. In my experience, the difference is negligible. Animations are possible when using both ng-show/ng-hide and ng-if, with examples for both in the Angular documentation.

Ultimately, the question you need to answer is whether you can remove element from DOM or not?

Nhan
  • 3,595
  • 6
  • 30
  • 38
markovuksanovic
  • 15,676
  • 13
  • 46
  • 57
  • 19
    You can use CSS3 animations with `ng-if`. Check the Animations paragraph and the example in the [docs](http://docs.angularjs.org/api/ng/directive/ngIf). Also with `ng-hide/ng-show` the css selectors like `:first-child` or `:nth-child` won't work properly since the hidden elements will be also counted. – Łukasz Wojciechowski Mar 17 '14 at 08:38
  • 4
    Animation service in angular.dart is relatively new. At the time of writing this it wasn't available. – markovuksanovic Mar 17 '14 at 22:23
  • 45
    You first point is a non-issue if you're using directives (like ng-click) to bind handlers , as you should be. – Kevin C. Jun 18 '14 at 19:18
  • 1
    To summarize: always use ng-if unless there is a reason not to. – Pylinux Aug 28 '14 at 11:25
  • How do screen readers and other assistive technologies interpret DOM elements hidden with CSS? If the reason for hiding elements is more than just for visual effect, I would think ng-if is the appropriate choice. Also, having just run into this, scope issues associated with ng-if may require a little more work. – Matt Oct 03 '14 at 21:07
  • 9
    Also, `ng-if` creates a new scope while `ng-show` doesn't. – martin Oct 08 '14 at 17:17
  • 8
    It should also be mentioned that adding and removing elements from the DOM can incur a high performance cost if done frequently. – Kevin C. Nov 12 '14 at 01:29
  • 1
    @KevinC. Agreed, but there does seem to be a trade-off to some degree. What if there's a significant number of expressions (i.e. watchers) within the ng-hidden DOM element? Your digest cycles with elongate the more watchers you have, which affects overall performance. Would you agree with that trade-off? – lux Nov 21 '14 at 19:14
  • 1
    @lux yup, that is correct. You need to take all of these factors into consideration when optimizing your app. – Kevin C. Nov 24 '14 at 06:43
  • 1
    http://plnkr.co/edit/gyYbFdZqOMcipizqX0XE?p=preview ng-if will attach handlers auto. – jiahut Jan 14 '15 at 14:08
  • What is the impact of having a new scope with ng-if? Does it change anything, really? – Wouter Sep 14 '15 at 11:35
  • It should be noted that `ng-if` is executed at a higher priority than `ng-show`/`ng-hide`. So if you're having problems with something not showing up / being hidden fast enough, give `ng-if` a try. – Lukas Knuth Oct 07 '15 at 14:44
  • Also, with ng-show if a child element is required="true", it will be required even though it is not visible. – Scott Carlson Feb 04 '16 at 18:50
  • Suppose I have a LOT of bindings inside a *div*, and those bindings only make sense when the *div* is visible.. then ng-if should have better performance..right? – chesscov77 Feb 18 '16 at 19:18
  • 1
    @Wouter - having a new scope can lead to a world of pain if you are caught unawares :) It breaks two-way binding! – Ben George Aug 12 '16 at 02:29
  • I would say it also depends on how frequently the element gets togglet. If it toggles rarely i would prefere ng-if, because handlers do not need to watch for events anymore. BUT (and i think thats the more important fact): If it toggles often, i would prefere ng-show, it's much cheaper to hide an element via CSS as to remove and append it from the DOM, especially the dedicated handlers. – Ruwen Nov 09 '16 at 13:36
130

See here for a CodePen that demonstrates the difference in how ng-if/ng-show work, DOM-wise.

@markovuksanovic has answered the question well. But I'd come at it from another perspective: I'd always use ng-if and get those elements out of DOM, unless:

  1. you for some reason need the data-bindings and $watch-es on your elements to remain active while they're invisible. Forms might be a good case for this, if you want to be able to check validity on inputs that aren't currently visible, in order to determine whether the whole form is valid.
  2. You're using some really elaborate stateful logic with conditional event handlers, as mentioned above. That said, if you find yourself manually attaching and detaching handlers, such that you're losing important state when you use ng-if, ask yourself whether that state would be better represented in a data model, and the handlers applied conditionally by directives whenever the element is rendered. Put another way, the presence/absence of handlers is a form of state data. Get that data out of the DOM, and into a model. The presence/absence of the handlers should be determined by the data, and thus easy to recreate.

Angular is written really well. It's fast, considering what it does. But what it does is a whole bunch of magic that makes hard things (like 2-way data-binding) look trivially easy. Making all those things look easy entails some performance overhead. You might be shocked to realize how many hundreds or thousands of times a setter function gets evaluated during the $digest cycle on a hunk of DOM that nobody's even looking at. And then you realize you've got dozens or hundreds of invisible elements all doing the same thing...

Desktops may indeed be powerful enough to render most JS execution-speed issues moot. But if you're developing for mobile, using ng-if whenever humanly possible should be a no-brainer. JS speed still matters on mobile processors. Using ng-if is a very easy way to get potentially-significant optimization at very, very low cost.

XML
  • 19,206
  • 9
  • 64
  • 65
  • 6
    Very nice addition to the above answer. Given with some good context, which also helps the decision making. Thanks. – Sean Jul 31 '14 at 12:36
  • 1
    `ng-show` can be useful when you have, say tabs each with a lot of content that takes time to render. After the first rendering, moving between tabs will be instant, whereas `ng-if` would require re-rendering, binding events etc. The downside as you say, is that creates watches executing in the background. Angular desperately needs [`ng-ifshowwatch`](https://github.com/angular/angular.js/issues/5301) – poshest Sep 03 '16 at 12:03
54

From my experience:

1) If your page has a toggle that uses ng-if/ng-show to show/hide something, ng-if causes more of a browser delay (slower). For example: if you have a button used to toggle between two views, ng-show seems to be faster.

2) ng-if will create/destroy scope when it evaluates to true/false. If you have a controller attached to the ng-if, that controller code will get executed every time the ng-if evaluates to true. If you are using ng-show, the controller code only gets executed once. So if you have a button that toggles between multiple views, using ng-if and ng-show would make a huge difference in how you write your controller code.

Yi Z
  • 933
  • 1
  • 10
  • 13
  • 5
    That's a huge true! ng-if does not necessarily make your frontend faster. It depends on your needs. Actually it could make the other way around if you are using in the wrong situation. – Thiago C. S Ventura Oct 14 '15 at 13:52
  • 1
    But according to me as ng-if does't render onto DOM so it is fast as compared to ng-show/hide. am i wrong pls let me correct at that point. – Pardeep Jain Nov 21 '15 at 07:38
  • 1
    ng-if would be faster if it evaluates to false, since, as you say, nothing needs to be inserted into the DOM. But, if it is true then you have an overhead of inserting the - possibly quite complicated - element into the DOM. – Mawg says reinstate Monica Feb 15 '16 at 08:29
  • "2) ng-if will create/destroy scope when it evaluates to true/false. If you have a controller attached to the ng-if, that controller code will get executed every time the " – Nate Anderson Oct 08 '17 at 00:24
37

The answer is not simple:

It depends on the target machines (mobile vs desktop), it depends on the nature of your data, the browser, the OS, the hardware it runs on... you will need to benchmark if you really want to know.

It is mostly a memory vs computation problem ... as with most performance issues the difference can become significant with repeated elements (n) like lists, especially when nested (n x n, or worse) and also what kind of computations you run inside these elements:

  • ng-show: If those optional elements are often present (dense), like say 90% of the time, it may be faster to have them ready and only show/hide them, especially if their content is cheap (just plain text, nothing to compute or load). This consumes memory as it fills the DOM with hidden elements, but just show/hide something which already exists is likely to be a cheap operation for the browser.

  • ng-if: If on the contrary elements are likely not to be shown (sparse) just build them and destroy them in real time, especially if their content is expensive to get (computations/sorted/filtered, images, generated images). This is ideal for rare or 'on-demand' elements, it saves memory in terms of not filling the DOM but can cost a lot of computation (creating/destroying elements) and bandwidth (getting remote content). It also depends on how much you compute in the view (filtering/sorting) vs what you already have in the model (pre-sorted/pre-filtered data).

Christophe Roussy
  • 16,299
  • 4
  • 85
  • 85
  • 2
    Other answers for technical facts. This one for wisdom. You have clearly built non-trivial Angular apps sir! +1 – poshest Sep 04 '16 at 14:05
  • This problem goes beyond angular, it is a fundamental problem in computer science, there is a point from which on one method is more efficient than the other. Usually this can be found through some benchmarking. So you could even switch between one method and the other depending on the item count ... Similar topic: https://math.stackexchange.com/questions/1632739/in-common-tongue-what-is-the-differences-between-sparse-and-dense-matrices – Christophe Roussy Oct 17 '17 at 07:59
13

One important note:

ngIf (unlike ngShow) usually creates child scopes that may produce unexpected results.

I had an issue related to this and I've spent MUCH time to figure out what was going on.

(My directive was writing its model values to the wrong scope.)

So, to save your hair just use ngShow unless you run too slow.

The performance difference is barely noticable anyway and I am not sure yet on who's favour is it without a test...

user2173353
  • 4,316
  • 4
  • 47
  • 79
  • 8
    Using `$parent.scopevar` in data bindings within an *ngIf* will rectify things like child scopes issues when using *ngIf* – m.e.conroy Oct 28 '14 at 18:58
  • 2
    This is not entirely true (the original @user2173353's comment, that is). If you stick to good practices, you won't get into trouble. That's a pretty basic rule: "if there's no dot, you're doing it wrong". See here for a demo of how it works: http://bit.ly/1SPv4wL. Another great reference (see mistake #2): http://bit.ly/1QfFeWd > (My directive was writing its model values to the wrong scope.) This is the result of not sticking to the above practice. – piotr.d Jun 26 '15 at 09:10
  • 1
    @piotr.d You are right, but that is not something a beginner may need to focus on and there is another best practice that says that it is better to leave performance improvements for the end (especially performance improvements that may not be improvements in reality). I have seen people putting `ngIf` everywhere believing that this will improve performance. This is simply not true and one can't say which is best, `ngIf` or `ngShow`, without a test or a deep analysis in the particular case. So, I still recommend forgetting about `ngIf`, until one sees bad performance or knows what he is doing – user2173353 Jun 30 '15 at 08:36
  • 2
    Good point. But using controllerAs makes this a non-issue. See, for instance, [John Papa's take on controllerAs and vm](http://www.johnpapa.net/angularjss-controller-as-and-the-vm-variable/). – jsruok Feb 26 '16 at 09:30
5

If you use ng-show or ng-hide the content (eg. thumbnails from server) will be loaded irrespective of the value of expression but will be displayed based on the value of the expression.

If you use ng-if the content will be loaded only if the expression of the ng-if evaluates to truthy.

Using ng-if is a good idea in a situation where you are going to load data or images from the server and show those only depending on users interaction. This way your page load will not be blocked by unnecessary nw intensive tasks.

appdroid
  • 573
  • 7
  • 18
  • This is especially useful as most browsers will load images even if the CSS hides their DOM containers. They usually just look for the `src` attribute of the `img` tag, when present it gets loaded ! – Christophe Roussy Oct 20 '15 at 08:41
4

ng-if on ng-include and on ng-controller will have a big impact matter on ng-include it will not load the required partial and does not process unless flag is true on ng-controller it will not load the controller unless flag is true but the problem is when a flag gets false in ng-if it will remove from DOM when flag gets true back it will reload the DOM in this case ng-show is better, for one time show ng-if is better

Saad Ahmed
  • 1,077
  • 9
  • 9