How to show 1 element in ngFor in angular2? - arrays

I have a simple ngFor that loops through an array. However, I've added a condition that while the index is < 5 keep add the tag. and After that, I want to add an extra tag just once that will be used a dropdown to view the rest of the tags. But it doesn't work.
<li *ngFor="let tag of module.Tags; let i = index">
<a *ngIf="i<5" href="#" class="span-tag tag">{{ tag }}</a>
<div *ngIf="module.Tags.length > 5 && i == 6">DropDown Button</div>
</li>
The feature here is that I don't want to show unlimited number of tags to the user, I want to limit it to only 5 tags, and have a button after 5 tags which will be used to show the dropdown with the remaining tags.
Is this possible to do in angular2?
If so, please enlighten me.

<li *ngFor="let tag of module.Tags | slice:0:5; let last=last">
{{ tag }}
<div *ngIf="last">DropDown Button</div>
</li>
https://angular.io/docs/ts/latest/api/common/index/SlicePipe-pipe.html
To get all added but the <div>DropDown Button</div> added after the 5th item you can use:
show = 5;
<li *ngFor="let tag of module.Tags|slice:0:show let i=index">
{{ tag }}
<div *ngIf="i==4 && show == 5" (click)="show = module.Tags.length">DropDown Button</div>
</li>

Related

Is there a way to generate new span elements for each value we iterate in *ngFor Angular 8?

I want to generate a span element for each saved tag from my collection tag's array.
I use firebase and get in *ngFor loop i get one big span element with all saved tags separated by comma, instead of getting a span for each tag. Is there any way that i can't prevent this from happening. Also i have created an interface for Saved.
Thanks in advance.
<div class="card">
<div class="card-body">
<h5 class="card-title text-center">{{saved?.title}}</h5>
<hr />
<div *ngFor="let tag of saved.tags">
<span class="badge badge-pill badge-primary">{{saved?.tags}}</span>
</div>
<hr /> View
</div>
</div>
//Saved interface in Saved.ts file
export interface Saved {
id: string;
title: string;
tags: string[];
}
Try having your code like this. This should make the span element repeat rather than the div and then make sure to reference the individual tag rather than the array inside.
If the tag has a name / title attribute swap {{ tag }} for {{ tag.title}}
looking at the interface its just {{ tag }}.
<div>
<span *ngFor="let tag of saved.tags" class="badge badge-pill badge-primary">
{{tag}}
</span>
</div>
Reference to Angular docs on using *ngFor to display data.
At the moment, you are referencing the array inside your *ngFor. So, as a result, you should see the whole list of n tags, for n times. If you switch from {{saved?.tags}} to {{tag}}. You will see one div per tag including one span and a single tag inside.
So for getting one span per tag, use it like the following:
<div class="card">
<div class="card-body">
<h5 class="card-title text-center">{{saved?.title}}</h5>
<hr />
<div>
<span class="badge badge-pill badge-primary" *ngFor="let tag of saved.tags">
{{tag}}
</span>
</div>
<hr />
View
</div>
</div>

ngIf array contains index

I have the following code:
<li *ngFor="let item of serviceList; let i = index;">
<button *ngIf="currentTools contains i" (click)="processService(item)">
Run Service</button>
</li>
Is there any way in Angular 2 to check if an array contains the index of my item?
I basically only want to show the items when their index number is in an array (currentTools), which is dynamically modified in a different process.
<li *ngFor="let item of serviceList; let i = index;">
<button *ngIf="currentTools.indexOf(i)>-1" (click)="processService(item)">
Run Service
</button>
</li>
Try this
You need to avoid function call inside a data binding like *ngIf. Taking this in to account, you should probably do this
<li *ngFor="let item of serviceList; let i = index;">
<ng-container *ngFor=let currentTool of currentTools>
<button *ngIf="currentTool === i" (click)="processService(item)">
Run Service</button>
</ng-container>
</li>
You can get more info about why not tu call function inside data binding here Don't Use Functions Inside Angular Templates and What to Use Instead
Also, you can check a similar answer here

Angularjs ng-repeat filter display the whole array but style the filtered ones

I need to apply a filter on ng-repeat that does not hide the no matching items but it will apply them a custom style for example different color.
<ul ng-repeat="friend in friends | filter:query">
<li>{{friend.name}}</li>
</ul>
So when i apply the filter i need to see all the names but the filtered ones with different color.
You could use ng-class to do what you want, and get rid of the filter part. Example:
<ul ng-repeat="friend in friends">
<li ng-class="friend.name.indexOf('Billy') >= 0 ? 'match' : 'no-match'">
{{ friend.name }}
</li>
</ul>
You can easily make the search part dynamic, but query would just be a simple string to test against:
<ul ng-repeat="friend in friends">
<li ng-class="friend.name.indexOf(query) >= 0 ? 'match' : 'no-match'">
{{ friend.name }}
</li>
</ul>
This is just one example. Without any other details about your query I can't completely answer your problem.

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.

How can I use the $index inside a ng-repeat to enable a class and show a DIV?

I have a set of <li> elements.
<ul>
<li ng-class="{current: selected == 100}">
<a href ng:click="selected=100">ABC</a>
</li>
<li ng-class="{current: selected == 101}">
<a href ng:click="selected=101">DEF</a>
</li>
<li ng-class="{current: selected == $index }"
ng-repeat="x in [4,5,6,7]">
<a href ng:click="selected=$index">A{{$index}}</a>
</li>
</ul>
When a user clicks on one of the address elements above then then it should, set the value of selected and show one of the <DIV> elements below:
<div ng:show="selected == 100">100</div>
<div ng:show="selected == 101">101</div>
<div ng-repeat="x in [4,5,6,7]" ng:show="selected == $index">{{ $index }}</div>
This works for the first two cases.
When the user clicks ABC then the first <DIV> shows 100 and changes color to red.
When DEF is clicked then 101 shows and DEF changes to red.
However it does not work at all for A0, A1, A2 and A3
When a user clicks A0, A1, A2 or A3 then the correct does not show, the selected value is not set and the color of ALL the ng-repeat A0,A1,A2 and A3 turn to red.
This is best shown if you look at this Plunker:
http://plnkr.co/edit/7HMeObplaBkx5R0SntjY?p=preview
Note that at the top I have added {{ selected }} as a debug aid at the top. Also the x in [4,5,6,7] are just meant to simulate a loop. In real life I have this as ng-repeat="answer in modal.data.answers".
Does anyone know how I can set this up so that the li class current is set at the right time and the DIV shows at the right time for the A0, A1, A2 and A3 <li> and <DIV>
The issue here is that ng-repeat creates its own scope, so when you do selected=$index it creates a new a selected property in that scope rather than altering the existing one. To fix this you have two options:
Change the selected property to a non-primitive (ie object or array, which makes javascript look up the prototype chain) then set a value on that:
$scope.selected = {value: 0};
<a ng-click="selected.value = $index">A{{$index}}</a>
See plunker
or
Use the $parent variable to access the correct property. Though less recommended as it increases coupling between scopes
<a ng-click="$parent.selected = $index">A{{$index}}</a>
See plunker
As johnnyynnoj mentioned ng-repeat creates a new scope. I would in fact use a function to set the value. See plunker
JS:
$scope.setSelected = function(selected) {
$scope.selected = selected;
}
HTML:
{{ selected }}
<ul>
<li ng-class="{current: selected == 100}">
<a href ng:click="setSelected(100)">ABC</a>
</li>
<li ng-class="{current: selected == 101}">
<a href ng:click="setSelected(101)">DEF</a>
</li>
<li ng-class="{current: selected == $index }"
ng-repeat="x in [4,5,6,7]">
<a href ng:click="setSelected($index)">A{{$index}}</a>
</li>
</ul>
<div
ng:show="selected == 100">
100
</div>
<div
ng:show="selected == 101">
101
</div>
<div ng-repeat="x in [4,5,6,7]"
ng:show="selected == $index">
{{ $index }}
</div>

Resources