Change icon when clicked (add class, remove class)

Um trying to change the icon when clicked on using addClass and removeClass but it’s not working (um using ionic icons) … I want to change the icon when it’s clicked (like and unlike for example) … any help?
Thanks,

You need to be doing this is a directive. Here is a working example for you:

This may not be the BEST way to do it, but it works.

1 Like

Hi,

do you know the way to do it in response of an ajax request.
For example, change the icon not with a click, but when I receive the promise from an ajax request.

  • create a directive ofr the icon switcher
  • set into $scope.XXX the response of my ajax response
  • into my directive, watch that $scope.XXX variable

I don’t know if it would be nice code.

Thanks :slight_smile:

You don’t need a directive, as AngularJS has a built-in solution for exactly this problem.

Let’s say you want to toggle between the icons ion-ios7-heart-outline and ion-ios7-heart (for unlike, and like, respectively).

On the element you want to click, you need to use ng-class and ng-click directives.

Let’s start with the click - you can “toggle” an ng-click like so: ng-click="liked=!liked" - that’ll set the “liked” scope variable the inverse of its current truthiness.

Then you can add a conditional class using ng-class to change the icon.

<i id="like" ng-class="{'icon ion-ios7-heart': liked, 'icon ion-ios7-heart-outline': !liked}" ng-click="liked=!liked"></i>

Simple and elegant right there in your HTML view. No need to write any JavaScript or directives.

13 Likes

@nicolasca - see my answer about ng-class - if you want to set a scope var on an ajax request rather than a click you can still use the same ng-class technique, but instead of setting a boolean variable on click you can just set it when your ajax request starts/ends (I don’t know what you’re trying to do, but I’ve done this before to change an icon to a spinner on ajax - just set something like $scope.loading = true; when you start and then $scope.loading = false; when your deferred promise has been reified, and you can evaluate the expressions in your ng-class.

Indeed it is an elegant and simple way to do it.
Thanks :wink:

@jough Nice job with that idea. I don’t know why I got off on the directive path when the built-in directives would have been better.

Hi could u please be more specific ? or write an example? thank you

Thank you so much!!! I finally figure it out ~~~

1 Like

This is great! but how does this save the class when the view have been changed? For instance, if it has been ‘liked’, then keep track of it so that when you come back to the same page, the icon stays same. Same way the bookmark icon works in browsers.

Thanks in advance!

You can trigger the boolean truthiness of the class with a model on the scope so that it should retain UI state as long as that model’s data is saved. For instance, if you set $scope.bookmarks = []; in an AppController or something, other child controllers can inherit from it even if you switch views.

So for the above example you gave:

<i id="like" ng-class="{'icon ion-ios7-heart': liked, 'icon ion-ios7-heart-outline': !liked}" ng-click="liked=!liked"></i>

could you please give an example on how to apply the truthiness logic, so that it retains the class when every time the page reloads or reroutes ? Couldn’t quite implement it.
Also, thank you for the response :wink:

Without knowing more about how your app works or seeing any code, I’m assuming that you’re linking some model in your app - some kind of data “thing” that has a liked attribute - whether that’s a single thing or an array/collection of things.

So in your controller:

$scope.some_model = {
    title: 'Thing One',
    liked: false,
};

and then your template would be updated to:

<i id="like" ng-class="{'icon ion-ios7-heart': some_model.liked, 'icon ion-ios7-heart-outline': !some_model.liked}" ng-click="some_model.liked=!some_model.liked"></i>

And you’d persist your model data however you want to save state. Does that make sense?

1 Like

@jough Sorry for the late response, I was trying to implement what you said. Still not able to get it right. i also tried through the directive. I must be doing it wrong. Either the whole elements from the list changes, or it does not remain selected when routed back. So here is what I’m trying to do:

The <i> tags are within the ng-repeat, so everytime the page is routed back, it checks for the stored data (local storage in this case) and if the items in the ng-repeat already exists in the local storage, the icon should be full heart, if not, then outlined heart.

The html:

<ul ng-repeat="word in words">
   <li>{{word}}</li>
  <i id="like" ng-class="{'icon ion-ios7-heart': liked, 'icon ion-ios7-heart-outline': !liked}" ng-click="liked=!liked"></i>
</ul>

The controller:

 $scope.collection = ["A", "B", "C", "D"];  //will be collected from local storage service every time
 $scope.words = ["AA", "A", "BB", ]; 

 //an then I loop through each items to compare the data from $scope.collection & $scope.word

for ....{
    if($scope.words ===  $scope.collection){
       //this decides, what icon should be displayed for each list item
      // here, just "A" should have full heart icon when rendering the DOM
  }
}

I’m not sure if this explains the problem properly. I’ll try to create codepen again. First time didn’t work well :frowning:
Thanks!

Yeah, you’re not persisting the “liked” state, so it gets reset whenever the view is redrawn.

I’ve amended your code below. If you store the words as objects with a “liked” property you won’t have to compare one array against the other to see if it’s liked or not.

1 Like

This is great! Thank you.

But I had a situation where when every time the page is reloaded, or if the same controller gets called again, the icon gets reset to the initial icon, since the liked attribute always resets to ‘false’.

So I had to manipulate the icon through Directive and Controller, so that it keeps track of what icon was activated before, even after page reload.

<i toggle-class="ion-ios7-heart-outline" ng-class="appliedClass(obj)"></i>

The ‘toggle-class’ directive sets the initial icon and ‘ng-class’ checks and then resets the icon based on whether it was liked or unliked before. Let me know if you have any other alternative/solution to your method…thank you for looking at it!

Problem solved!

can you explain how to save state for the buttons?

For more reference you can check at my code also : http://codepen.io/harked/pen/gpvdNK

2 Likes

one of the best answers i have ever incountered!

I’m still a complete n00b, but would like to learn to use something like this. I know the topic is old, but 've got one question. This solution doesn’t store anything in a database, but it’s more like a cookie? Would really want to know how this works. Is there any documentation available?

Kind regards, Vincent