Dynamic Filter value in ng-repeat - angularjs

is it possible to use a dynamic value for a filter variable in this manner:
<div ng-repeat="playlist in playlists" >
<a class="view-detail" ng-href="#/playlist/{{playlist.id}}">{{playlist.playlistName}}</a>
<a ng-href="#/playlist/{{playlist.id}}">check out this playlist >></a>
<span ng-repeat="genre in genres | filter:{name:'playlist.playlistGenre'}">
<img ng-src="{{genre.image}}">
</span>
</div>
As such its a repeat within a repeat - its not showing up like this, however if i hardcode in one of the values that the filter variable would return, then it works -
Or should i rethink my approach -
many thanks

filter:{name:'playlist.playlistGenre'}
That looks for genres whose name is the string 'playlist.playlistGenre'. What you want, if I understand correctly, is to display the genres whose name has the same value as the field playlistGenre of the playlist.
So you want
filter:{name:playlist.playlistGenre}
That said, this is quite inefficient. I guess there is a single genre that has a given name. So, instead of looping through all genres for each playlist, you'd better set the genre directly in the playlist, or at least use a hash that contains the genre for every name:
$scope.genresByName = {};
genres.forEach(function(genre) {
$scope.genresByName[genre.name] = genre;
});
and then
<div ng-repeat="playlist in playlists" >
<a class="view-detail" ng-href="#/playlist/{{playlist.id}}">{{playlist.playlistName}}</a>
<a ng-href="#/playlist/{{playlist.id}}">check out this playlist >></a>
<span><img ng-src="{{genresByName[playlist.playlistGenre].image}}"></span>
</div>

Related

Alternative to breaking a loop in Angular while iterating through an array?

I have read online that it is impossible to break *ngFor in Angular but was wondering if anyone has an alternative to this? I have been stuck on this for days on end.
I would like to loop a list all animal names for the user and when the user clicks a specific animal name, info appears below the button they have just clicked.
Please see the example below:
<div ="container" *ngFor="let animal of (this.animals || [])">
<h5 (click)="getAnimalInfo(animal.animalName)">{{animal.animalName}}</h5>
<ng-container *ngIf="getAnimalInfo(animal.animalName)">
<div class="container" *ngFor="let animalInfo of (this.animalInfo || []);">
<li {{animalInfo.title}} </li><br>
<li {{animalInfo.paragraph}} </li><br>
</div>
</ng-container>
</div>
Currently, when I click an animal name item my original list, it will display the details below every single animal name on the list instead of just the one I have clicked on.
How can I fix this so that the loop knows to break when I select one animal name?
N.B I am aware that if i take my second for loop out of the original for loop, this can work, however I want the data to populate directly under the original button and be toggle-able rather than having the info appear at the very bottom of the full list.
I don't know how to break loop in *ngFor loop but for you requirement i have given the solution below.
First of all i have defined dummy animals array and animalInfo array in ts file. You can replace with your original array.
animals = [{ animalName: 'dog' }, { animalName: 'cat' }];
animalInfo = [{ paragraph: 'dog paragraph', title: 'dog' }, { paragraph: 'cat paragraph', title: 'cat' }];
then i have declared selectedAnimalInfo which we can use to store the click animal info.
selectedAnimalInfo = {};
I am expecting animalName parameter in animal array is same as title parameter of animalInfo arrar.
After that your getAnimalInfo method will be look like below.
getAnimalInfo(animalName: string) {
this.selectedAnimalInfo = {
[animalName]: this.animalInfo.find((animal) => animal.title === animalName)
};
}
And at the end html code
<div class="container" *ngFor="let animal of (this.animals || [])">
<h5 (click)="getAnimalInfo(animal.animalName)">{{animal.animalName}}</h5>
<ng-container *ngIf="selectedAnimalInfo[animal.animalName]">
<div class="container">
<li> {{selectedAnimalInfo[animal.animalName].title}} </li><br>
<li> {{selectedAnimalInfo[animal.animalName].paragraph}} </li><br>
</div>
</ng-container>
</div>
Hope it will full fill you requirement.

AngularJS when I click a link I want to filter an array

I'm currently working with a website using PHP and AngularJS, I have a product list and a droplist that has some links which will allow the user to filter products by type(electric guitars, acoustic guitars, etc...) is there any way to do a function that filters the ng-repeat to only show products whose type are the selected one?
This is what I currently have:
<article class="producto" ng-repeat="product in dbproducts | filter:prodsearch">
<div class="img">
<img src="products/img/{{product.Imagen}}" alt="{{product.Marca + ' ' + product.Modelo}}">
<p class="product-model">{{product.Marca + ' ' + product.Modelo}}</p>
<span class="product-price">{{product.Precio | currency: '€'}}</span>
</div>
<div class="check">
<div class="paygroup">
<p class="price" ng-bind="product.Precio | currency: '€'"></p>
<button class="buy"><i class="fa fa-shopping-cart"></i>{{'BUTTON_BUY' | translate}}</button>
<p>{{'BUTTON_AVAILABLE' |translate}}: {{product.Unidades_disponibles}} </p>
</div>
</div>
<div class="txt">
<p>Test, hola, {{ $index }}</p>
</div>
<span class="close fa fa-times fa-inverse"></span>
</article>
So If I get your code right, you already have a pipe filter in your ng-repeat:
| filter:prodsearch
So I guess somewhere in an input directly or in your controller you hare binding a user input to the variable "prodsearch" and the ng-repeat is live filtered.
In the same way, you can have buttons, whether they are in a droplist or not, which click action would be assigning a certain text to the "prodsearch" variable.
A filter is what you want. Another way is Using a copy array of products to show and writing a function which update your array of products. This function receives a type and just add related products to showing items.
Something like this:
Controller
Call this function on ng-change of drop down
$scope.filters = ["all", "electric", "guitars", "acoustic", "guitars"];
$scope.selectedFilter = "all";
$scope.filterProds() {
if ($scope.selectedFilter == "all") {
$scope.dbproductsToShow = $scope.dbproducts;
} else {
$scope.dbproductsToShow = [];
$scope.dbproducts.forEach(function(itm) {
if (itm['type'] == filter) {
$scope.dbproductsToShow.push(itm);
}
});
}
}
And in your Html
<select ng-model="selectedFilter" ng-options="filter in filters" ng-change="filterProds()"></select>
<article class="producto" ng-repeat="product in dbproductsToShow">
I've fixed it, what I did was:
Adding another pipe in ng-repeat called filter: producttype
Added a $scope.producttypevariable;
Changed the value of the variable each time I clicked on the links in the dropdown so it would filter by type. This:
<li ng-click="producttype='electrica'"><a>Guitarras eléctricas</a></li>
Thanks for your help and tips, and sorry if this method is not the best, I learnt angularjs by myself(i'm not a good self-learner).

How to bind array with ng-bind-html directive in angularJS?

I want to show for every item different description.
This is the controller:
todoApp.controller('todos',function($scope,todoFactory){
todoFactory.getTodos().success(function (data) {
courses = x2js.xml_str2json(data);
$scope.todos = courses.rss.channel.item;
for(var i = 0 ; i < $scope.todos.length ; i++){
item = $scope.todos[i];
console.log(item.description);
$scope.message = item.description;
}
});
this is the html:
<div ng-controller="todos" class="list" style="padding-top: 8%">
<div class="list card" ng-repeat="todo in todos | filter:search" >
<div class="item item-avatar" ng-click="openLink(todo.link)" >
<img src="Bla-Bla-Logo-1.png">
<h2>{{todo.title}}</h2>
<p>{{todo.pubDate | limitTo:25 }}</p>
</div>
<div class="item item-body">
<p ng-bind-html="message"></p>
<p>
1 Like
5 Comments
</p>
</div>
</div>
<!--end list card-->
</div>
<!--end todos-->
Just to explain the code I get xml and convert into json so todos is array of objects.
Message is entering every object and get the description (but in the description has tags so i use ng-bind-html directive to show it properly).
I understand that $scope.message will hold just the last description. How to make it to belong in the ng-repeat so I can get different description for different item?
Thanks.
replace
<p ng-bind-html="message"></p>
with
<p ng-bind-html="todo.description"></p>
please provide the data which is you want to displayed repeatedly.
How data is represented.You are getting last one because it is overriding.
The "ngBind" attribute tells Angular to replace the text content of the specified HTML element with the value of a given expression, and to update the text content when the value of that expression changes.
Typically, you don't use "ngBind" directly, but instead you use the double curly markup like {{ expression }} which is similar but less verbose.

how to create greater than and less than filter in angularjs ng-repeat

I am trying to use range slider in angularjs to filter the grid. I want a greater than and less than filter in my ng-repeat. But I am not getting how to do this. I am using the following code for now. But this is not working for me. This code is not giving me desired output
Here is my html for grid
<div class="col-md-3 product-left-grid" ng-repeat="data in Products| filter:priceSlider.max |filter:priceSlider.min">
<div class="product-grid"></div>
<div class="product-grid-text">
<a href="javascript:void(0)">
<img alt="" src="{{data.Picture1}}">
</a>
<div class="products-grid-info">
<div class="price">
<a class="btn btn-sm btn-width btn-default btn-font-weight"
href="javascript:void(0)"
ng-click="viewDetails($index)">Quick View</a>
<a href="javascript:void(0)"
class="btn btn-sm btn-width btn-default btn-font-weight"
ng-click="addToCart (data.ProductID,data.Picture1,data.ProductName,data.UnitPrice,data.Discount,data.ShippingCharges,data.wieght)">Add to cart</a>
<div class="tovar_description clearfix">
<a class="tovar_title" href="#"><b>{{data.ProductName}} </b> | {{data.UnitPrice | currency:mycurrency}}</a>
</div>
</div>
<div class="clearfix"> </div>
</div>
</div>
</div>
this is my price range slider
<rzslider rz-slider-floor="priceSlider.floor"
rz-slider-ceil="priceSlider.ceil"
rz-slider-model="priceSlider.min"
rz-slider-high="priceSlider.max"
rz-slider-on-change="onSliderChange()"></rzslider>
Now I am using filter but I have doubt that I am going wrong somewhere. Please experts help to solve this problem. Price range filter I need like every eCommerce website have.
Thanks
You have to make a custom filter :
//create an angular filter named "price"
app.filter('price', function () {
//our function will need three arguments
return function(items, greaterThan, lowerThan) {
//then we filter the array with dedicated ES5 method
items = items.filter(function(item){
//if item price is included between the two boundaries we return true
return item.price > greaterThan && item.price < lowerThan;
});
//then we return the filtered items array
return items;
};
});
You can see how Array.filter() works here
Our function will need 3 arguments to work, the items list which is passed by default and the lower and higher boundaries that we will pass as arguments in our ng-repeat filter.
Then you can use the filter as follow :
<div ng-repeat="data in Products | price:priceSlider.min:priceSlider.max | orderBy:'price'">...</div>
As I said above, items array is passed by default, then, to specify other parameters you have to separate them with a colon : right after the filter name.
You can read about custom filters in the official documentation here.
Finally you can then specified as many other filters as you want by separating them with a pipe |.
In our example I'm ordering them by price after the array has been filtered.
Here is a working JSFiddle.

How to use ng-switch in angularjs

I was trying to display some content using ng-switch:
<div ng-app ng-controller="ctrl" >
<div ng-repeat="list in statusList">
<p ng-switch on="list">
<span ng-switch-when="incorrect">
i am incorrect
</span>
<span ng-switch-when="stuff">
i am stuff
</span>
<span ng-switch-when="wrong">
i am wrong
</span>
<span ng-switch-default>
Correct
</span>
</p>
</div>
</div>
controller
function ctrl($scope){
$scope.statusList=["incorrect","wrong","stuff"];
}
Getting the output like this:
i am incorrect
i am wrong
i am stuff
But I need output to display in order what I specified. i.e.
i am incorrect
i am stuff
i am wrong
How can I do this, and one important point is we should not change the order in controller.
You can create custom order by function, something like this.
<div ng-repeat="list in statusList | orderBy:myValueFunction">
You can order it alphabetically (with filter), but I would not recommend it because you will probably add new element that are not ordered alphabetically.
ng-repeat iteration uses the order of your list. You can either define a custom filter to order the list as you want or use another approach:
Define a 'contains' filter, returning true if an array contains an element:
.filter('contains', [function() {
return function(array, element) {
return array.indexOf(element) > -1;
}
}])
Use ng-ifs for your template (no repeat):
<div ng-if="statusList | contains : 'incorrect'">i am incorrect</div>
<div ng-if="statusList | contains : 'stuff'">i am stuff</div>
<div ng-if="statusList | contains : 'wrong'">i am wrong</div>
This way you can define whatever order you want to have.
Plunkr: http://plnkr.co/edit/yaYodJAVCVQ55KbOrf3A?p=preview

Resources