Given a list such as
var list = ['one','two','three'];
In angular, I want to iterate through the list only rendering certain items. Something like:
<ul ng-controller="main">
<li ng-repeat="item in list" ng-switch on="item">
<span ng-switch-when="one">{{item}}</span>
</li>
</ul>
And have the output look like this:
<ul>
<li><span>one</span></li>
</ul>
Instead, I get:
<ul>
<li><span>one</span></li>
<li></li>
<li></li>
</ul>
I have tried ng-hide but is woefully inefficient since I have a large number of items and only want to display one or two and ng-hide renders all of them and then hides the inactive ones with css. This is a problem because I am doing this in a JQuery Mobile app which tries to decorate all list items, including the hidden ones, killing performance.
JSFiddle at http://jsfiddle.net/ghendricks/MXu3a/
You are correct that ng-hide should not be used here, it is a job for filters.
You can provide a custom function to filter the list: http://jsfiddle.net/ERMVj/
$scope.selectOne = function (input) { return input == "two" || input == "one"; };
<li ng-repeat="l in list | filter:selectOne">
<span>{{l}}</span>
</li>
Related
Hey I'm looping thru an array using ng-repeat in my template. The list spits out 9 list elements and I would like change the background color of the selected list element but I want to do it in a way where multiple ones can be selected and the color of the selected ones with a different background color. Initially I had passed $event to the click function on the list element and added a class to event.target but that put the class on all the list elements rather than the selected one.
<ul>
<li class="info-items"
ng-repeat="card in config.cards"
ng-class="{'error-border': emptyCardsArray}">
<div class="inner-text"
ng-model="userSelection.cards"
ng-click="addCard(card.name, $event)">{{card.name}}{{$index + 1}}</div>
</li>
</ul>
HTML:
$(event.target).addClass('active.cards');
JS:
The list that I'm repeating thru unforunately doesn't have a unique ID or I would have passed in the ID and created a condition to check whether the selected items have one and applied the class.
It's a much better practice to simply use ng-class for this.
<ul>
<li class="info-items"
ng-repeat="card in config.cards"
ng-class="{'error-border': emptyCardsArray}">
<div class="inner-text"
ng-model="userSelection.cards"
ng-class="active.cards">{{card.name}}{{$index + 1}}
</div>
</li>
</ul>
I'm trying to create some functionality where the user would have an input box and all the data (li's) below are hidden.
Then when a user types into the input box, those li's that match that text are show.
What would the best way to do this using angular? I've set up plunker below:
http://plnkr.co/edit/T6JOBJE4LrAtshbmaoPk?p=preview
I was thinking of setting the li's to:
li {
display: none;
}
and then was going to try an ng-if with the ng-model as the value. Something like this:
<div class="input-group">
<span class="input-group-addon" id="basic-addon1">Search</span>
<input type="text" class="form-control" ng-model="search">
</div>
<ul>
<li ng-repeat="x in data | filter:search " ng-if="!search">{{x.name}}</li>
</ul>
Can someone help point me in the right direction? Even if its just explaining the logic.
You can just set ng-show attribute to your <ul> tag, where you will watch on length of search variable and if it's greater that zero, your list with filtered results will be shown. So, you don't need any css.
<ul ng-show="search.length">
<li ng-repeat="x in data | filter:search ">{{x.name}}</li>
</ul>
Demo on plunker.
Part of your problem is the filter matches on the empty search string. You could create a custom filter to handle this, something like this http://plnkr.co/edit/i4lsuVUmOLO3pbISu7FR?p=preview
$scope.filterName = function(datum) {
console.log($scope.search, datum);
return $scope.search !== '' && datum.name.indexOf($scope.search) !== -1;
};
Used in the template like:
<ul>
<li ng-repeat="x in data | filter:filterName">{{x.name}}</li>
</ul>
Then you would have greater control over the filter if you want to tweak it in future.
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.
Using AngularJS and Bootstrap, let say there are 3 tabs: tab1, tab2, and tab3. There are also some links on each tabs. Now for example, tab1 is active. The question is: how to change the content of the tab1 by clicking a link within the same tab?
main.html:
<div class="tabbable">
<ul class="nav nav-tabs">
<li ng-class="{active: activeTab == 'tab1'}"><a ng-click="activeTab = 'tab1'" href="">tab1</a></li>
<li ng-class="{active: activeTab == 'tab2'}"><a ng-click="activeTab = 'tab2'" href="">tab2</a></li>
<li ng-class="{active: activeTab == 'tab3'}"><a ng-click="activeTab = 'tab3'" href="">tab3</a></li>
</ul>
</div>
<div class="tab-content">
<div ng-include="'/'+activeTab"></div>
</div>
tab1.html:
<h1>TAB1</h1>
Something
something.html
<h1>SOMETHING</h1>
Now the question is how to change the tab1 content to something.html while the tab1 is active?
As pointed out in other examples there are many ways to do this. Direct DOM manipulation is not really the Angular way of thinking about this kind of use case. A better way to think about it might be:
What possible content can this tab contain?
What will control its' being displayed?
Using the ng-if or ng-switch directive allows you to selectively limit the content based on a variable defined in the scope.
Consider this possibility:
<div class="tabbable">
<ul class="nav nav-tabs">
<li ng-class="{active: activeTab == 'tab1'}"><a ng-click="activeTab = 'tab1'" href="">tab1</a></li>
<li ng-class="{active: activeTab == 'tab2'}"><a ng-click="activeTab = 'tab2'" href="">tab2</a></li>
<li ng-class="{active: activeTab == 'tab3'}"><a ng-click="activeTab = 'tab3'" href="">tab3</a></li>
</ul>
</div>
Based on your code for the included file you could do this:
<div class="tab-content">
<div ng-if="content==='A'" ng-include="'/'+activeTabA"></div>
<div ng-if="content==='B'" ng-include="'/'+activeTabB"></div>
</div>
Another approach is to utilize ng-view and routing. It is more complicated than conditionally including but less complicated than writing a whole new directive.
In short, you define a container element with the ng-view attribute like this
<div ng-view></div>
Then set up a routing table in your javascript code like this
$routeProvider.when('/tab1', {templateUrl: 'partials/tab1.html', controller: 'tab1Controller'});
$routeProvider.when('/tab2', {templateUrl: 'partials/tab2.html', controller: 'tab2Controller'});
For more detail see this link: http://docs.angularjs.org/api/ngRoute.directive:ngView
This is actually a fairly common AngularJS issue, and is handled pretty nicely by nested directives. It works well enough that it's actually one of the demos in the Custom Directive Guide on the AngularJS docs page. It's the last example, "Creating Directives that Communicate". You can see the full code there, but the idea is that you create a 'container' directive for the tab group and a 'pane' directive for the inside content. Your HTML ends up looking like this:
<my-tabs>
<my-pane title="Hello">
<h5 id="pane1">Hello</h5>
<p>This content is in the first pane.</p>
</my-pane>
<my-pane title="World">
<h5 id="pane2">World</h5>
<em>This content is in the second pane.</em>
</my-pane>
</my-tabs>
As #musically_ut pointed out in his comment, there are a lot of ways to handle this. This is just one way, but I think it works out pretty well.
I am using ui-sortable directive (from angular-ui ) in the view
<ul ui-sortable>
<li ng-repeat="item in items" >
{{item.property1}}
{{item.property2}}
</li>
</ul>
As a result the user can drag and drop to re-sort the items in the browser but this does not update the order of the $scope.items array. How can this be accomplished so that $scope.items array order stays in sync with user initiated drag and drop change in the browser?
You are Missing
ng:model
<ul ui:sortable ng:model="list">
<li ng:repeat="item in list" class="item">{{item}}</li>
</ul>
Please check below working example
Demo
It display the updated array
<div ng:repeat="item in list">{{item}}</div>
Array is updated automatically by the directive