ng-if is not working as expected - angularjs

I'm trying to use ng-if to show and hide some data based on tabs because I don't want all the html to be on the DOM all the time. Here's what I'm trying to do. It seems the ng-if is working only when the page is loaded, after that on the click of the sub tabs, it's still updating the scope variable, but I don't see the change on the UI. Please help.
Thanks.

Remove ng-href="#" from your links. This is all you need:
<li ng-repeat="subTab in tabData.SubTabs">
<a ng-click="subTabClicked(subTab)">{{subTab.Name}}</a>
</li>
With ng-href present, currentTabId is being updated on a child scope for each tab. On the parent scope, where ng-if is watching, currentTabId was never changed.
Here is a demo: http://plnkr.co/ISwjaWKggdbGL38BW078

Related

angular - directive on an element under ng-if not working

I have a page with tabs, here's an example of one of them:
<li ng-if="userData.isMaster">
<a data-target="#debug-tab" data-toggle="tab" data-tab-name="debug" on-tab-shown>Debug</a>
</li>
This tab is similar to other tabs, with the exception that it is under ng-if. Each tab has an "on-tab-shown" directive which broadcasts an event each time the tab is shown. Inside each tab's controller there's an event listener that listens to this event. In other tabs, that are not under ng-if, the event is received by the listeners, but not in this tab. It is possible to replace the ng-if with ng-show to make it work, but are there better ways maybe?
If your ng-if is set to not show the tab (userData.isMaster == false), then the tab is removed from the DOM. Since it isn't on the DOM, it won't react to the broadcast. If you need it to react to the broadcast even though it isn't showing, you will need to use ng-show so it is simply hidden.
I'm afraid no. The thing is, that ng-if completely blocks the linking of the element it's put on and all its children (in fact, they're even removed from the DOM). That's why ng-show works, because ng-show does not block any linking.
There's no reason not to favor ng-show if it works better. All you're doing is adding to the DOM, or not. Per Angular's documentation:
ngIf differs from ngShow and ngHide in that ngIf completely removes and recreates the element in the DOM rather than changing its visibility via the display css property.
Here's the link if you'd like more info -- good luck!!
https://docs.angularjs.org/api/ng/directive/ngIf

make an element with ng-if start hidden (prevent it from showing during page load)

When i want to make something start as hidden with ng-show you can just add class="ng-hide" so the css will hide the element beforehand. This way an element won't be shown when the page is still loading
I want to do the same thing using ng-if but i don't know how to do it
As Michiel suggested, using the ngCloak directive is the solution.
Just add ng-cloak to the class attribute of the tag you want to keep hidden while your application is loading.
<div class="ng-cloak">test</div>
For more details: https://docs.angularjs.org/api/ng/directive/ngCloak

ng-if Function Gets Called on Click

I have my code on Plnkr:
http://plnkr.co/edit/6wz4zub2sEOfhrqps0c8
The html code is quite simple:
<div ng-app="myApp" ng-controller="MainCtrl">
<div ng-dropdown-multiselect="" options="myData" selected-model="myModel" extra-settings="mySettings" events="myEvents"></div>
<div ng-repeat="item in Items">
<item-input></item-input>
</div>
</div>
</div>
Basically, the problem is my function in ng-if gets called every time I click anywhere on the page. I think it has something to do with the multi-select control but I'm not sure where I should fix it. Any help is appreciated.
Thanks.
UPDATED
What I don't really understand is why this behavior stops when I comment out the multi-select dropdown (<div ng-dropdown-multiselect="" options="myData" selected-model="myModel" extra-settings="mySettings" events="myEvents"></div>)?
As shown in the picture below, taken from Chrome DevTools, the multi-select dropdown is generating two click event handlers :
One event is on the button and one on the whole document. Therefore, a click on the document is triggering at least that last event handler, which potentially changes the model. Angular then do a digest cycle, and that implies that the displayMe function bound to the ngIf directive is evaluated in case the element should be removed of the DOM or not.
If you remove the dropdown component, and thus these two click handlers, you are left with 3 text inputs. Indeed, now there are no digest after a click on the document because no handler are executed, but you can still trigger digests essentialy by typing inside the input elements.
This answer by Miško Hevery has some valuable info about the dirty-checking process in Angular 1.x.

How can I tell Angular not to compile child nodes when using $compile

The situation is I have an HTML structure somewhat similar to this:
<div class="dynamicDirectiveGoesHere">
<p>{{SomeExpressionThatDiffers}}</p>
</div>
I need to display a bootstrap http://angular-ui.github.io/bootstrap/ popover when the text within p has an ellipsis. That's why I'm adding the popover attribute dynamically. I can get the popover to display using $compile, but the problem is the text within {{ }} goes away. I can't use the template trick since I don't really know what the template will be since the popover will happen on several different child tags that have different templates. So that's why there is the need to only $compile what's in div, and not in the child element (p tag). Is this possible with angular?
You can add the property terminal to your directive and adjust the priority to fit your needs.
terminal: true prevents other directives from getting instantiated and is used by for example the ng-repeat and ng-if directive.
You can read more here https://docs.angularjs.org/api/ng/service/$compile (scroll down to terminal).

jPanelMenu is breaking AngularJS ng-click

I am using jPanelMenu in a ToDo application for the left side menu. I have created a directive to apply the jPanelMenu to the appropriate elements.
Everything is working as expected except there is a nested ng-repeat with a nested ng-click inside of the element that gets reassigned with jPanelMenu.
<jpmenu>
<ul class="unstyled">
<li ng-repeat="category in categories">
{{ category }}
</li>
</ul>
</jpmenu>
The ng-click event is not firing in the created jpanel menu.
Notes:
jPanelMenu coppies the jpmenu element and applies it's styles to it, not using the original dom elements
The original DOM elements still exist and they are "display:none;"
the class ng-scope is missing from the recreated jpanel menu element
The ng-click element fires properly on the original DOM element if I unhide it and click it, but the recreated elements do NOT fire at all.
I've added a timeout to the directive to delay the jpanel menu recreation (to wait for angular to finish it's other directives first) but that didn't help
Here is a jsfiddle example of exactly what's going on (THIS FIDDLE DOES NOT RUN IN CHROME BECAUSE OF CROSS SITE SECURITY): http://jsfiddle.net/47PXj/
If you click the unhidden original menu items in the jsfiddle you'll see the text updating, but if you click the menu items in the left menu they do not work.
You forgot to bootstrap your app. Try this:
<body ng-app="myApp">

Resources