My JavaScript:
this.items = [
{name: 'Amsterdam1', id: '1'},
{name: 'Amsterdam2', id: '2'},
{name: 'Amsterdam3', id: '3'}
];
My HTML:
<ul>
<li *ngFor="#item of items" id={{item.id}}>
{{ item.name}}
</li>
</ul>
I want to assign a dynamic id to each element, but can't get it to work. The name is showing up but the id is not.
the way you said works, Angular 2.0.0.beta.8.
in this case you can use for example:
[id]="item.id"
[attr.id]="item.id"
id={{item.id}}
<ul>
<li *ngFor="#item of items" #elem [id]="item.id">
{{ item.name}} ID: {{elem.id}}
</li>
</ul>
<ul>
<li *ngFor="#item of items" #elem [attr.id]="item.id">
{{ item.name}} ID: {{elem.id}}
</li>
</ul>
<ul>
<li *ngFor="#item of items" #elem id={{item.id}}>
{{ item.name}} ID: {{elem.id}}
</li>
</ul>
Plunker
You can look here for more information in Template syntax.
https://angular.io/guide/cheatsheet
All the methods provided by #AngelAngel are correct but just to explain why to use [attr.id] posted as answer.
Angular by default uses property binding. To tell Angular explicitly to use attribute binding, we use instead:
<ul>
<li *ngFor="#item of items" #elem [attr.id]="item.id">
{{ item.name}} ID: {{elem.id}}
</li>
</ul>
With attr.id you have to explicitly opt in to attribute binding because attribute binding is expensive. Attributes are reflected in the DOM and changes require for example to check if CSS selectors are registered that match with this attribute set. Property binding is JS only and cheap, therefore the default.
<ul>
<li *ngFor="#item of items" attr.id={{item.name}}>
{{ item.name}}
</li>
</ul>
This should work (worked for me on angular2).
I found the answer. I can use [attr.id] tag on the 'li' tag.
Related
How can I make ONE link in the FOR-Loop active?
<ul>
<li v-for="channel in $store.state.forum.channels" v-bind:key="channel.key">
<a v-bind:class="{ active: toggle }" v-on:click="selectChannel({ key: channel.key })">{{ channel.title }}</a>
</li>
</ul>
Or:
How can I access an iteration in the for loop from outside the loop?
So using *ngFor i displayed the list of name property of object, this object also has a property named isAvailable I want to set isAvalable property to toggle between true and false when I click on it, and based on isAvalible a text next to li will display is available or not
<p>Authors</p>
<ul>
<li *ngFor='let author of authors' (click)='onClick()'>
{{author.name}}
</li>
</ul>
As I understand you want this
<p>Authors</p>
<ul>
<li *ngFor='let author of authors'>
<span [hidden]='author.isAvalible'>{{author.name}}</span>
<span (click)='author.isAvalible = !author.isAvalible '>author.isAvalible</span>
</li>
</ul>
<p>Authors</p>
<ul>
<li *ngFor='let author of authors'>
<span [hidden]='author.isAvalible'>{{author.name}}</span>
<span (click)='onClick()'>author.isAvalible</span>
</li>
</ul>
onClick(value){
value=!value;
}
How to send item from v-for to slot? In vue.js.
ListComponent:
<ul>
<li v-for="item in list">
<slot></slot>
</li>
</ul>
Page view:
<list-component :list="list">
<span v-text="item.value"></span>
</list-component>
Code <span v-text="item.value"></span> can't access item (from component's scope). Is it a way to send an item from component to code in tag?
P.S. I know, that as a workaround I can send $index from component to parent view, but it's a little bit hacky
UPD: Example of my current workaround (somebody may find this useful):
Declare index in view's data:
data () {
return {
index: 0,
list: [ ... ]
}
Add to index param to the view's template:
<list-component :list="list" :index="index">
<span v-text="list[index].value"></span>
</list-component>
Declare index in component's props:
props: {
index: {
type: Number
}
}
Add index to v-for's element:
<ul>
<li v-for="item in list" index="$index">
<slot></slot>
</li>
</ul>
the bind expression is compiled in the context who define them,so:
v-text="item.value"
can not be compiled because in Page view there is no "item" defined.
maybe you can try to change your code structure like below:
ListComponent:
//content in component
<span>i am text in component,item value is:{{item.value}}</span>
<slot></slot>
Page view:
<ul>
<li v-for="item in list">
<list-component :item="item"></list-component>
</li>
</ul>
Problem:
I have an unordered list of items which are returned from a json call and are output using ng-repeat. Each one of these items has a class name (there are about 9 categories).
I have a second unordered list which is simply a list of available categories.
Aim:
I want to be able to select one of the categories in the right hand list, which will apply a filter to the actual list of returned elements. This should be activated via a toggle (so click once: filtered, click again: filter removed). So it is simply looking to match the classname in the clicked element, to the elements that share the same classname in the list of json data.
I cannot use ng-model (as this is reserved for certain form elements).
For my jsfiddle I am simply using static html.
Here is my angular code:
/* angular custom filter on returned ajax api data */
var app = angular.module('app', []);
app.controller('main', function($scope) {
$scope.chFilters = {};
$scope.links = [
{name: 'atm'},
{name: 'internet'},
{name: 'mobile'},
{name: 'sms'},
{name: 'postal'}
];
$scope.channels = ["ATM", "INTERNET", "SMS", "POSTAL","MOBILE"];
});
(this is based on another question I found on SO). Unfortunately the fiddle is a bit messy and has some extraneous code in it.
HTML:
<div ng-app="app">
<div ng-controller="main">
<ul>
<li class="atm">Some stuff ATM</li>
<li class="internet">Some stuff INTERNET</li>
<li class="sms">Some stuff ATM</li>
<li class="atm">Some stuff ATM</li>
<li class="postal">Some stuff POSTAL</li>
<li class="atm">Some stuff ATM</li>
<li class="internet">Some stuff INTERNET</li>
<li class="postal">Some stuff POSTAL</li>
<li class="postal">Some stuff POSTAL</li>
<li class="atm">Some stuff ATM</li>
<li class="sms">Some stuff SMS</li>
<li class="mobile">Some stuff MOBILE</li>
<li class="internet">Some stuff INTERNET</li>
<li class="mobile">Some stuff MOBILE</li>
</ul>
<ul class="channel-filters">
<li ng-repeat="link in links | filter:chFilters" class="{{link.name | lowercase}}"><a ng-click="chFilters.name = link.name">{{link.name | uppercase}}</a></li>
<li class="last" ng-click="chFilters.name = ''">CLEAR FILTER</li>
</ul>
<ul>
<li ng-repeat="channel in channels | filter:chFilters">
<strong>{{channel}}</strong>
<a ng-click="chFilters = channel">{{channel}}</a>
</li>
</ul>
<!-- original -->
<ul>
<li ng-repeat="link in links | filter:chFilters">
<strong>{{link.name}}</strong>
<a ng-click="chFilters.name = link.name">{{link.name}}</a>
</li>
</ul>
</div>
</div>
This is the actual HTML from the application (with the call to the api).
<ul class="accordion">
<li class="search-text-channel">
<input type="textarea" ng-model="searchTextChannel.$" placeholder="Search"/>
</li>
<li ng-repeat="day in interactions.model.byDay | filter:searchTextChannel" ng-click="hidden = !hidden" ng-init="hidden = false" class="{{day.channel | removeSpace | lowercase}}" ng-class="{'closed': !hidden, 'open': hidden}">
<span class="date">{{day.date}}</span>
<span class="subheading">{{day.channel}}</span>
<ul ng-show="hidden">
<li ng-repeat="interaction in day.interactions">
{{interaction.time}} {{interaction.description | removeUnderscore}}
</li>
</ul>
</li>
<li class="load-more">
<i class="fa fa-plus"></i>LOAD MORE
</li>
</ul>
I have managed to recreate this functionality in jquery, but I think it would be better to implement an angular solution in an angular application.
I've tried researching and also attempted to implement show/hide as well as a custom filter, but so far no joy.
Here is my (messy) jsfiddle
<ul>
<li ng-repeat="channel in channels | filter:chFilters.name">
<strong>{{channel}}</strong>
<a ng-click="chFilters = channel">{{channel}}</a>
</li>
</ul>
<!-- original -->
<ul>
<li ng-repeat="link in links | filter:chFilters.name">
<strong>{{link.name}}</strong>
<a ng-click="chFilters.name = link.name">{{link.name}}</a>
</li>
</ul>
Update Plunker
Let me know if you have any question on this.
Here is part of the solution:
Suppose your items look like this:
$scope.items = [
{ class: "atm", label: "Some stuff ATM" },
{ class: "internet", label: "Some stuff INTERNET" },
{ class: "sms", label: "Some stuff SMS" },
{ class: "postal", label: "Some stuff POSTAL" },
...
];
To show a filtered list (only filtering by a single channel for now): create a separate list in the scope, with the filters applied:
$scope.click = function(name) {
$scope.chFilters.name = name;
$scope.filteredItems = $scope.items.filter(function(item) {
return item.class === $scope.chFilters.name;
});
};
Call this click handler from the bottom list:
...<a ng-click="click(link.name)">{{link.name | uppercase}}</a>....
And show filteredItems in the top list:
<ul>
<li ng-repeat="item in filteredItems" ng-class="item.class">{{item.label}}</li>
</ul>
So this is really just a starting point, it should be extended to handle multiple filters, etc...
I thought this would be a very common thing, but I couldn't find how to handle it in AngularJS. Let's say I have a list of events and want to output them with AngularJS, then that's pretty easy:
<ul>
<li ng-repeat="event in events">{{event.title}}</li>
</ul>
But how do I handle the case when the list is empty? I want to have a message box in place where the list is with something like "No events" or similar. The only thing that would come close is the ng-switch with events.length (how do I check if empty when an object and not an array?), but is that really the only option I have?
You can use ngShow.
<li ng-show="!events.length">No events</li>
See example.
Or you can use ngHide
<li ng-hide="events.length">No events</li>
See example.
For object you can test Object.keys.
And if you want to use this with a filtered list here's a neat trick:
<ul>
<li ng-repeat="item in filteredItems = (items | filter:keyword)">
...
</li>
</ul>
<div ng-hide="filteredItems.length">No items found</div>
You might want to check out the angular-ui directive ui-if if you just want to remove the ul from the DOM when the list is empty:
<ul ui-if="!!events.length">
<li ng-repeat="event in events">{{event.title}}</li>
</ul>
With the newer versions of angularjs the correct answer to this question is to use ng-if:
<ul>
<li ng-if="list.length === 0">( No items in this list yet! )</li>
<li ng-repeat="item in list">{{ item }}</li>
</ul>
This solution will not flicker when the list is about to download either because the list has to be defined and with a length of 0 for the message to display.
Here is a plunker to show it in use: http://plnkr.co/edit/in7ha1wTlpuVgamiOblS?p=preview
Tip: You can also show a loading text or spinner:
<li ng-if="!list">( Loading... )</li>
<ul>
<li ng-repeat="item in items | filter:keyword as filteredItems">
...
</li>
<li ng-if="filteredItems.length===0">
No items found
</li>
</ul>
This is similar to #Konrad 'ktoso' Malawski but slightly easier to remember.
Tested with Angular 1.4
Here's a different approach using CSS instead of JavaScript/AngularJS.
CSS:
.emptymsg {
display: list-item;
}
li + .emptymsg {
display: none;
}
Markup:
<ul>
<li ng-repeat="item in filteredItems"> ... </li>
<li class="emptymsg">No items found</li>
</ul>
If the list is empty, <li ng-repeat="item in filteredItems">, etc. will get commented out and will become a comment instead of a li element.
You can use this ng-switch:
<div ng-app ng-controller="friendsCtrl">
<label>Search: </label><input ng-model="searchText" type="text">
<div ng-init="filtered = (friends | filter:searchText)">
<h3>'Found '{{(friends | filter:searchText).length}} friends</h3>
<div ng-switch="(friends | filter:searchText).length">
<span class="ng-empty" ng-switch-when="0">No friends</span>
<table ng-switch-default>
<thead>
<tr>
<th>Name</th>
<th>Phone</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="friend in friends | filter:searchText">
<td>{{friend.name}}</td>
<td>{{friend.phone}}</td>
</tr>
</tbody>
</table>
</div>
You can use as keyword to refer a collection under a ng-repeat element:
<table>
<tr ng-repeat="task in tasks | filter:category | filter:query as res">
<td>{{task.id}}</td>
<td>{{task.description}}</td>
</tr>
<tr ng-if="res.length === 0">
<td colspan="2">no results</td>
</tr>
</table>
i usually use ng-show
<li ng-show="variable.length"></li>
where variable you define for example
<div class="list-group-item" ng-repeat="product in store.products">
<li ng-show="product.length">show something</li>
</div>
you can use ng-if because this is not render in html page and you dont see your html tag in inspect...
<ul ng-repeat="item in items" ng-if="items.length > 0">
<li>{{item}}<li>
</ul>
<div class="alert alert-info">there is no items!</div>