How to `switch` the content by condition - angularjs

In my ng-repeat, i require the DOM to be switched, according to the active status.
i tried like this, but not working for me:
<ul>
<li ng-click="activate(item)" ng-repeat="item in items" ng-class="{active : active == item}">
<span ng-if="item==active">
<span>{{item}}</span><!-- when active nested under span -->
</span>
<!-- else without nesting the span -->
<span ng-if="item== !active">{{item}}</span> //this is not working
</li>
</ul>
Live Demo

Replace your last ng-if statement to this (you've just made syntax error):
<span ng-if="item !== active">{{item}}</span>
Your active variable isn't boolean, so you can't toggle it in your statement.

Related

ng-class not working in one situation. What are some possible cause of this?

I'm stuck. Cannot figured this out. This question is very simple to show, but I'm not really sure how to put it as a question, therefore I'll try my best.
First, here's the layout of my whole app (The problem lies in the Header.jsp):
<jsp:include page="../home/Header.jsp" />
<jsp:include page="../home/Modals.jsp" />
<div data-ng-view data-save-scroll-position data-position-relative-to-menu></div>
<jsp:include page="../home/Footer.jsp" />
The problem is very simple. I have the following data-ng-class in the data-ng-view section that change a tab to active if something is true (The problem is it won't work in one scenario even though it displayed true in the tab name):
<ul class="nav nav-tabs">
<li role="presentation" data-ng-class="tab.isSelected ? 'active' : ''" data-ng-repeat="tab in ctrl.tabs"
data-ng-click="ctrl.fetchBIReports(tab)">
</li>
</ul>
In the JSP that use data-ng-include for the above markup, there's a side nav to change to this page. Once clicked this side-nav, it highlighted the tab 'active' as expected (trying not to include the whole jsp):
<div class="side-navbar">
<ul>
<li class="{{ ctrl.navigate.path == 'bi/schedule' ? 'active-link' : 'normal-link'}}">
Schedule Reports
</li>
</ul>
</div>
<div class="content-right" data-ng-include="ctrl.navigate.path"></div>
content-right includes the JSP mentioned in the second markup.
So far, so good. Here's a demo of it working (including both side-navbar and content-right):
The problem is, in my Header.jsp, there's a nav bar that takes me to the same page. If it is clicked from a different page with different controller, then it works. But if I'm in the current controller and click that nav bar link, then data-ng-class does not take 'active' as its class. Here's the markup for the Header.jsp for that link:
<li class="dropdown" data-roles="['ROLE_ADMIN']">
<a href="#/bi" class="dropdown-toggle" data-toggle="dropdown" data-ng-click="ctrl.changeNavigation('bi/schedule')"
role="button" aria-haspopup="true" aria-expanded="false">BI Management<span class="caret"></span></a>
<ul class="dropdown-menu">
<li>Schedule Reports</li>
</ul>
</li>
Here is the demo of it not working even though it is printing out true in the UI:
The only problem is with this UI. All the data are populated. Records are displayed for the correct tab. Even side nav-bar is displaying the correct active class.
Your syntax for ng-class is off a bit. The format is "{ '[class-name]': [expression that evaluates to true or false] }". You can have multiple class values separated by commas each with their own expression. When an expression is true, the corresponding class is applied to the element and when it is false the class is removed from the element. The way you have written it would almost work for the plain class attribute, but you would need to include the interpolation characters: {{ and }}. Here is a very simple example to illustrate ng-class.
angular.module('app', []);
.red {
color: #fff;
background-color: #e21d1d;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script>
<div ng-app="app">
<label>
<input type="checkbox" ng-model="applyRedClass" /> Apply 'red' class
</label>
<div ng-class="{'red': applyRedClass}">
This is a simple example of how to use ng-class.
</div>
</div>

Geting incorrect $index value for parent ng-repeat loop

I have following code and try to use $index in delete function but it gives incorrect value of it.
<li ng-repeat="joinMember in data.teamMember | orderBy:'member.screenName || member.fname' ">
<div class="member-list-img">
<a ng-href="">
<img ng-src="{{joinMember.member.data.image ? (joinMember.member.data.imageType == 'avatar' ? '/public/images/avatars/' + joinMember.member.data.image : '/public/images/' + joinMember.member.data.image) : '/public/images/avatars/avatar-73.png'}}" width="100%" alt="{{joinMember.member.screenName ? joinMember.member.screenName : joinMember.member.fname + ' ' + joinMember.member.lname }}" />
</a>
</div>
<div class="member-list-cont">
<h4>
<a ng-href="#">
{{joinMember.member.screenName ? joinMember.member.screenName : joinMember.member.fname + ' ' + joinMember.member.lname }}
</a>
</h4>
<span>{{joinMember.created | date : "MMMM d, y"}}</span>
</div>
<div ng-if="data.canModify" class="membr-delete">
<a ng-href="">
<i class="fa fa-trash text_link" aria-hidden="true" ng-click="deleteTeamMember($parent.$index, joinMember.id)"></i>
</a>
</div>
</li>
That's because the directive ng-if creates a new scope for itself, when you refer to $parent, it access the immediate $parent's scope, i.e., the inner repeat expression's scope.
So if you want to achieve something you wanted like in the former, you may use this:
<div ng-repeat="i in list">
<div ng-repeat="j in list2">
<div ng-if="1">
({{$parent.$parent.$index}} {{$parent.$index}})
</div>
</div>
</div>
if you have more than one inner directives, you can use ng-init for storing $index in a variable for references in child scopes.
<div ng-repeat="i in list" ng-init="outerIndex=$index">
<div ng-repeat="j in list2" ng-init="innerIndex=$index">
<div ng-if="1">
({{outerIndex}} {{innerIndex}})
</div>
</div>
</div>
So try $parent.$parent.$index in your example and please check understanding the scopes
You are using $parent.$index in a div that have ng-if tag. which delete dom element(div) if condition is fall so that case you will receive incorrect $index value. but with ng-show it only add hide class to that div.
So try to ng-show if it is not important to remove div element instead just hide it.
Note:- You are also using orderBy filter in ng-repeat which will sort in only your DOM so if you will find incorrect object value in your controller.
As you can see in the official documentation of angularjs you should get a zero-based index via $index within a ng-repeat. Try the example by angularjs here. Try to debug data.teamMember in your controller to make sure that this is the correct array you'd like to iterate.

angularJS ng-attr- expression

hello i am working on a navigation direction.
if there are any child entries i have to add a attribute "uib-dropdown"
<li ng-attr-uib-dropdown="{{!!tree[$index].children ? '' : undefined }}" ng-repeat="nav in tree" ng-class="{ 'active' : isActive(nav.path) }">
the variable "!!tree[$index].children" would return true or false.
i am behind google now since 2hours but i cannot see how to use this expression with ng-attr the right way.
because now its adding the uib-dropdown to every li. doesn´t matter if it is true or false.
i hope someone can help me.
thanks
Because our answer for tree[$index].children can be truthy, if tree[$index].children has an answer, it will be true, if it's empty or undefined, then it will be false/falsey. There is no need for the !! or the ternary operator.
<li ng-attr-uib-dropdown="{{tree[$index].children}}">
You could also use the || (or operator) to better illustrate "falsey" of undefined.
<li ng-attr-uib-dropdown="{{tree[$index].children || undefined}}">
Created a plunkit. Here I used ng-if where if the array "food" exist, then allow the dropdown. If you remove the "food" array, the link is replaced without the dropdown.
<a href ng-if="!food">
Click me, no dropdown, yo!
</a>
<!-- Simple dropdown -->
<span ng-if="food" uib-dropdown on-toggle="toggled(open)">
<a href id="simple-dropdown" uib-dropdown-toggle>
Click me for a dropdown, yo!
</a>
<ul class="dropdown-menu" uib-dropdown-menu aria-labelledby="simple-dropdown">
<li ng-repeat="choice in items">
<a href>{{choice}}</a>
</li>
</ul>
</span>

Bind different dom elements in Angular

I have this HTML
<div class="pageContent">
<aside class="left-cont">
<ul class="btn-menu" >
<li ng-repeat="tab in tabs" ><a class="ng-scope ng-binding" href="#" ng-click="show={{tab.id}}"> {{tab.name}}</a> </li>
</ul>
</aside>
<section class="main-content" ng-show="show === 1">
<h1> {tab.title}}</h1>
<p>{{tab.content}}</p>
</section>
<section class="main-content" ng-show="show === 2">
<h1> {{tab.title}}</h1>
<p>{{tab.content}}</p>
</section>
<section class="main-content" ng-show="show === 3">
<h1> {{tab.title}}</h1>
<p>{{tab.content}}</p>
</section>
</div>
And I have three problems with it:
1)ng-click="show={{tab.id}}"shows me the right id number in the dom, for instance, id=1 does show <a class="ng-scope ng-binding" href="#" ng-click="show=1">but I do get an error in my console - Error: [$parse:syntax] http://errors.angularjs.org/1.3.8/$parse/syntax?p0=%7B&p1=invalid%20key&p2=7&p3=show%3D%7B%7Btab.id%7D%7D&p4=%7Btab.id%7D%7D Why is that? I have tried to to write tab.id instead of {{tab.id}}, but it doesn't even fetch the element.
2) I want the section tags to be appended whenever there's a click on the a, but I can not do so since the section tags aren't wrapped in the li tags (when I do put them in the li they do fire, but that's not what I want). How do I bind these two different elements?
3) I want each section to append the content of its specific tab for the section that has - ng-show="show === 1" I want tab.title and tab.content of the tab that has the id=1, and so on..
How is that all possible?
Help is very much appreciated here
#HarishR is right: this is not the AngularJS way to do things. The imperative way of doing things would be to have an ng-click set the isActive property to true on an instance of tab.
Then the directive would would watch the isActive property and change class accordingly.
Since you probably don't want to reinvent the wheel, you could consider using Angular strap ( http://mgcrea.github.io/angular-strap/#/tabs#tabs ) or check out this code https://github.com/angular-ui/bootstrap/blob/master/src/tabs/tabs.js.

ng-repeat - content to show if array is empty or null

I've a deep nested ng-repeat lists, and only in the last loop I've to display alternate content if list was empty. I'm new to angular, saw some posts online please help me where can I use content if list is empty. The ng-repeat=sessions in day could be empty.
<ul class="day">
<li ng-repeat="sessions in day">
<ul class="table-view">
<li class="table-view-cell" ng-repeat="(heading, session) in sessions">
<span class="group">{{heading}}</span>
<ul class="cell">
<li class="cell-content" ng-repeat="val in session" ng-click="getSession(val.id)">
<div class="time" style="background-color:#{{val.color}}">
<span>{{val.start | date:"h:mma"}}</span>
<span>to</span>
<span>{{val.end | date:"h:mma"}}</span>
</div>
<div class="session" ng-class-odd="'odd'" ng-class-even="'even'">
<span class="name">{{val.name}}</span>
<span class="room">Room: {{val.room}}</span>
</div>
</li>
</ul>
</li>
</ul>
</li>
</ul>
1). CSS approach. I usually use pure CSS approach in such cases. With this markup (stripped extra-html):
<ul class="day">
<li ng-repeat="sessions in day">
...
</li>
<li class="no-sessions">
No sessions on this day.
</li>
</ul>
and CSS rules to hide .no-sessions li by default and make it visible only if there are no previous li tags:
li.no-sessions {
display: block;
}
li + li.no-sessions {
display: none;
}
So when sessions array is empty, there will be no li rendered and only no-sessions one will be visible. And if will hide as soon as there is at least one session on this day.
Demo: http://plnkr.co/edit/KqM9hfgTTiPlkdmEevDv?p=preview
2). ngIf approach. Of course you can use ngIf/ngShow directives for show no-records element when sessions array is empty:
<li ng-if="!day.length">
No sessions on this day.
</li>
I think this would work for your case:
<li ng-hide="day.length > 0">
No sessions on this day.
</li>
No extra CSS needed. Assumes day is an array.
http://plnkr.co/edit/WgDviOKjHKS1Vt5A5qrW
I would recommend handling that in your controller. Keeping your logic in the controller and javasript makes debugging easier and more manageable. I can think of 2 approaches: using ng-show/ng-hide or a condition for your day variable when its empty.
Option 1
ng-show/ng-hide approach:
$scope.isDayEmpty = function(){
return $scope.day.length > 0 ? false : true;
}
html:
<ul class="day">
<li ng-repeat="sessions in day" ng-hide="isDayEmpty">
...
</li>
<li ng-show="isDayEmpty">
No Sessions this Day
</li>
</ul>
Option 2:
ng-repeat approach
if($scope.day.length == 0){
$scope.day.push("No Sessions this Day");
}
This should get you essentially the same result. The first approach would make your CSS styling easier assuming you want to do something different in that case.
The second approach can vary in style depending on your code but thats an example of how you can do it. I don't know your javascript so I can't be more specific to your scenario.

Resources