Wp3Dev
Wp3Dev

Reputation: 2079

Check if value is in array for ng-if within ng-repeat

I have an ng-repeat looping through a list of wines retrieved from an API. I also have a array variable containing all wine ids that have been added to favorites fetched from database. I want to be able to display an "Add To Favorites" button if the user has not yet added a specific result wine from the list. To do this I thought I would do something like:

HTML:

<tr ng-repeat="wine in wines">
    <td>{{$index+1}}</td>
    <td>{{ wine.Name }}</td>
    <td>{{ wine.Appellation.Name }}</td>
    <td>${{ wine.PriceMin }} - ${{ wine.PriceMax }}</td>
    <td>
        <!-- If wine.Id is not yet in the array of all favorite ids, display "Add Button" -->
        <a href="#" class="btn btn-primary btn-dark" ng-click="addToFavorites(wine.Id)" ng-if="favorites.indexOf(wine.Id) !> -1"> Add </a>
        <!-- Else Display Already Added -->
        <span ng-if="favorites.indexOf(wine.Id) > -1">Added</span>
    </td>
</tr>

Here is my JS:

app.controller("MainController", function($scope, $http){
    $scope.favorites = [];
    var getAllFavorites = function(){
        $http.get("/home/getAllFavoriteIds").success(function(response) {
            angular.forEach(response, function(r) {
                $scope.favorites.push(r);
            });
        });
    };
});

I am new to .indexOf() so I am thinking maybe that is the problem. But Maybe I am wrong.

Upvotes: 26

Views: 65429

Answers (5)

Artem Petrosian
Artem Petrosian

Reputation: 2954

I would recommend you to move this logic to controller an keep your view as clean as possible:

   $scope.isFavorites = function(id) {
       return $scope.favorites.indexOf(id) !== -1;
   }

And your view should be:

<!-- If wine.Id is not yet in the array of all favorite ids, display "Add Button" -->
<a href="#" class="btn btn-primary btn-dark" ng-click="addToFavorites(wine.Id)" ng-if="!isFavorites(wine.Id)">Add</a>
<!-- Else Display Already Added -->
<span ng-if="isFavorites(wine.Id)>Added</span>

Upvotes: 12

fracz
fracz

Reputation: 21278

You can use angular-filter's contains filter:

<span ng-if="favorites | contains:wine.Id">Added</span>

or write your own filter that does the same:

angular.module('module').filter('contains', function() {
  return function (array, needle) {
    return array.indexOf(needle) >= 0;
  };
});

Upvotes: 31

Frank van Wijk
Frank van Wijk

Reputation: 3262

favorites.indexOf(wine.Id) !> -1 does not look like a proper angular expression. Note that when you have expressions in your templates, only some basic javascript conditionals are allowed. See the docs for what is possible.

Instead of having a list of all wines and a list with favorite wines, you better extend the list with all wines with a boolean property isFavorite. This is also better for performance, since it does not need to search for the wine in the second list every iteration.

In the reponse callback loop (quick and dirty):

var index = $scope.favorites.indexOf(r.id);
if(index > -1) {
  $scope.favorites[index].isFavorite = true;
} // else isFavorite is undefined, which is falsy

Array operations like this can be done more elegantly with Underscore or Lodash.

Note that if you have an object with wines (ids as key), wines can be retrieved by id instead of lookup by index every time. ngRepeat supports objects just like arrays.

In your template:

<!-- If wine.Id is not yet in the array of all favorite ids, display "Add Button" -->
<a href="#" class="btn btn-primary btn-dark" ng-click="addToFavorites(wine.Id)" ng-if="!wine.isFavorite"> Add </a>
<!-- Else Display Already Added -->
<span ng-if="wine.isFavorite">Added</span>

Upvotes: 1

Ced
Ced

Reputation: 1301

I think you have to change

favorites.indexOf(wine.Id) !> -1

into

favorites.indexOf(wine.Id) < 0

Upvotes: 7

Pratik
Pratik

Reputation: 1138

!> is not valid. ! can only be used with =, or with a boolean value. Use

favorites.indexOf(wine.Id) == -1

indexOf returns -1 if it can't find the element in the array. Thanks for the correction. I was stuck on !>

Upvotes: 0

Related Questions