ng-class if else not working with repeat value - angularjs

I been trying to change a class if a tab in a repeat, depending in the title of the tab. snippet shown below
<tab ng-repeat="tab in tabs" heading="{{tab.title}}" ng-class="{{tab.title}} === 'Logs' ? 'pull-right' : ''" active="tab.active">
<div class="col-md-12">
<div ng-include="tab.content">
</div>
</div>
</tab>
But it's not working. I tried changing the tab.title to $index.
<tab ng-repeat="tab in tabs" heading="{{tab.title}}" active="tab.active" ng-class="{{$index}} === 1 ? 'pull-right' : ''">
<div class="col-md-12">
<div ng-include="tab.content">
</div>
</div>
</tab>
try with and without surrounding it with {} and {{}}. but still. nothing works.
Can anyone tell me what i'm doing wrong here?
as always, thanks for your time.
----EDIT---------
well i found a post where there was a workaround. don't know what happen. but it works.
snippet shown below
<tab ng-repeat="tab in tabs" heading="{{tab.title}}" active="tab.active" class="{{ tab.title == 'Logs' ? 'pull-right':'' }} ">
<div class=" col-md-12">
<div ng-include="tab.content">
</div>

You should use this syntax for the ng-class. First the class name you want to set, second the condition to check for. Once it matches the condition, the class name will be added.
<tab ng-repeat="tab in tabs" heading="{{tab.title}}" ng-class="{ 'pull-right': tab.title == 'Logs' }" active="tab.active">
<div class="col-md-12">
<div ng-include="tab.content">
</div>
</div>
</tab>

As said in the docs, value of ng-class is an expression that can be evaluated to a string, an object, or an array. That means you don't have to use {{}} there: simple...
ng-class="tab.title === 'Logs' ? 'pull-right' : ''"
... should suffice. In fact, it's cleaner to write it as an object:
ng-class="{'pull-right':tab.title === 'Logs'}"
Sadly, that won't solve your case, as you're trying to apply ng-class to a custom directive (created with angular-ui Bootstrap package). That directive uses ng-class in its own template:
<li ng-class="{active: active, disabled: disabled}">
<a href ng-click="select()" tab-heading-transclude>{{heading}}</a>
</li>
... and it's created with replace flag set to true. This effectively means value of ng-class supplied by you will be glued together with value supplied by template, resulting in something ugly like:
<li ng-class="tab.title === 'Logs' ? 'pull-right' : '' {active: active, disabled: disabled}">
That certainly won't work as planned. In fact, there's a related issue (#1741) registered at the project's hub - which is closed with the following commentary:
Using ng-class on a directive that uses replace: true is a very bad
idea. There are numerous issues around replace: true and even talk of
deprecating/removing it. But, unfortunately, it's not going anywhere
soon and the caveat released by the core Angular team was that use it,
but do so at your peril. I.e., use it knowing that doing so
incorrectly can break your DOM.
I suspect this issue will not be addressed.
One possible workaround is using native class with an Angular expression supplied as its value:
class="{{tab.title === 'Logs' ? 'pull-right' : ''}}"
This won't be merged with a <tab> template class, as there's no such thing there - and you're clear to go!

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>

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.

Trouble with active tab default using AngularJS, UI Boostrap, and UI Router

When using a UI Boostrap tabset along with nested sticky states created with ui-router and ui-router-extras, I have an issue where navigating to a tab's state via URL will select the first tab along with the correct tab. It should only activate the tab whose state matches the URL route.
Here's what the tabset looks like:
<div style="position:relative">
<tabset>
<tab heading="Dashboard" ui-sref="LMS.Dashboard" ui-sref-active="active"></tab>
<tab heading="Modules" ui-sref="LMS.Modules" ui-sref-active="active"></tab>
<tab heading="Messages" ui-sref="LMS.Messages" ui-sref-active="active"></tab>
<tab heading="Settings" ui-sref="LMS.Settings" ui-sref-active="active"></tab>
</tabset>
<div ui-view="Dashboard" class="tab-content" ng-show="$state.includes('LMS.Dashboard')">
<h2>Dashboard</h2>
{{test}}
</div>
<div ui-view="Modules" class="tab-content" ng-show="$state.includes('LMS.Modules')">
<h2>Modules</h2>
</div>
<div ui-view="Messages" class="tab-content" ng-show="$state.includes('LMS.Messages')">
<h2>Messages</h2>
</div>
<div ui-view="Settings" class="tab-content" ng-show="$state.includes('LMS.Settings')">
<h2>Settings</h2>
</div>
</div>
I have a plunker here:
http://plnkr.co/edit/sQB58YKntDwNIUpAdLmT?p=preview
To see the issue, select a tab other than 'Dashboard', then reload the "live view" frame.
Another way is to open it in a window, switch the tab, then reload.
I have the same issue. Add active="false" to disable default behavior and use ui-sref-active to add active class.
<tab ui-sref-active="active" active="false">
Edit
While this method seems to works, it produces error because false is not assignable.
Edit 2
Combining ng-init with a local scope variable seems to do the trick.
<tab ui-sref-active="active" active="isActive" ng-init="isActive=false">
In your case, it might be simpler to just add an active variable for each tab. See this plunker:
http://plnkr.co/edit/73lm068buZf851h47FVQ?p=preview
I had exactly the same thing. After searching for while, I decided the "value" ui-bootstrap offers around tabs is not worth the effort. My simple manual implementation:
<ul class="nav nav-tabs">
<li ng-class="{active:$state.current.name == 'properties.edit.basic'}"><a ui-sref="properties.edit.basic">Basic</a></li>
<li ng-class="{active:$state.current.name == 'properties.edit.marketing'}"><a ui-sref="properties.edit.marketing">Marketing</a></li>
<li ng-class="{active:$state.current.name == 'properties.edit.rooms'}"><a ui-sref="properties.edit.rooms">Rooms</a></li>
<li ng-class="{active:$state.current.name == 'properties.edit.images'}"><a ui-sref="properties.edit.images">Images</a></li>
<li ng-class="{active:$state.current.name == 'properties.edit.rates'}"><a ui-sref="properties.edit.rates">Rates</a></li>
<li ng-class="{active:$state.current.name == 'properties.edit.availability'}"><a ui-sref="properties.edit.availability">Availability</a></li>
</ul>
<ui-view></ui-view>

angular-ui tab renders anchor tag without href

I am using AngularUI tabs as seen in the following sample code below and in this plunker.
http://plnkr.co/edit/YlbrObH4sBlyUFZO2tZh?p=preview
<tabset class="tabbable tabbable-custom tabbable-full-width">
<tab class="active" heading="Latest Customers" href="javascript:;">
<div class="tab-pane active" id="Div1">
Pane 1
</div>
</tab>
<tab heading="Feeds" href="javascript:;">
<div class="tab-pane" id="Div2" href="javascript:;">
<div class="tab-pane active" id="Div3">
Pane 2
</div>
</div>
</tab>
</tabset>
As you can see in the plunker, when the mouse hovers over the "tab", the cursor does not change to your typical pointing finger. The anchor tag that angularui is rendering does not have a href value on it, therefore, it is considered invalid html. if i manually add href="javascript:;" , the cursor works like i want it.
My question is, how can i tell the directive to add a href to the anchor tag? any advice?
Thanks,
Dan
You could add a style that targets the tabs:
.nav-tabs > li > a {
cursor: pointer;
}
just write:
<tabset
class="tabbable tabbable-custom tabbable-full-width"
style="cursor: pointer;"
>
....
Mmh this is weird, I too am using angular-ui tabs in my project. I copied and pasted the exact code you provided and it works just fine.
(see bottom of http://wiredbeast.com/coolframework/docs.html#/activity)
I might remove it later so look quick.
So my guess is that it's something wrong with your bootstrap css. I'm using ui-bootstrap-tpls-0.6.0.min.js, bootstrap.js/css v3.0.0, and https://ajax.googleapis.com/ajax/libs/angularjs/1.1.5/angular.min.js for angular

Resources