Martyn Chamberlin
Martyn Chamberlin

Reputation: 1287

Updating an ng-repeat property in one controller based on the ng-repeat property of another controller?

I have two separate Angular controllers, one in the main content area (homeCtrl) showing a list of events, and one in the sidebar (sidebarCtrl) showing a list of tags for events.

// homeCtrl.js
$scope.events = [{
  name: "Example Event Name",
  tags: [
    {  
       "id":7,
       "name":"Imaginon",
       "following": "false"
    },
  ]
}];

In the sidebar controller I have a collection of the most frequently used tags:

// sidebarCtrl.js
$scope.tags = [  
  {  
     "id":17,
     "name":"MintMuseum",
     "following": "true"
  },
  {  
     "id":7,
     "name":"Imaginon",
     "following": "false"
  }];

I would like it so that if the user starts following a tag in the sidebar, the tag gets highlighted in both the sidebar and in the home feed. If we were just trying to highlight it in the sidebar that would be easy enough:

// sidebar.html
<div ng-repeat="tag in tags"> 
  <li ng-class="{highlighted: tag.following}" ng-click="followTag(tag)">{{ tag.name }}
</div>

But I don't know how to then highlight all instances of that tag color in the home feed. It would be super easy in jQuery by just giving each instance of tag in the document a class of tag_17 (or whatever ID that tag happened to be) but it'd be nice to avoid jQuery and use Angular's data binding paradigm if possible.

Any suggestions?

Upvotes: 0

Views: 56

Answers (1)

Tahsis Claus
Tahsis Claus

Reputation: 1929

Create a service, called highlightService for instance:

myModule.factory('highlightService', function() {

   var highlighted = [];

   var toggleHighlight = function(tag) {
      var index = highlighted.indexOf(tag);
      if(index > -1) {
         highlighted.splice(index, 1);
      }
      else{
         highlighted.push(tag);
      }
   }

    return {
        highlighted: highlighted,
        highlight: highlight
    }
});

Inject the service into your controller, then assign a local scope variable to it:

$scope.highlightService = highlightService;

Then in your html:

<div ng-repeat="tags in highlightService.highlighted">
   <div ng-click="highlightService.highlight(tag)></div>
</div>

Both controllers will contain a reference to the same object, so they will see each other's changes on that object during angular's $digest cycle, and everything will be updated appropriately.

Alternatively you could make a filter available in the service, repeat over a local array of tags with the filter from the provided service.

EDIT: Here is an example of how to do that:

myApp.controller('highlightService', [function() {
    var highlightedIDs = [];

    var isHighlighted = function(tag) {
        if(var index = highlightedIDs.indexOf(tag.id) > -1) {
            return index;
        }
        else {
            return false;
        }
    }

    var highlight = function(tag) {
        var index = isHighlighted(tag.id);
        if(index) {
            highlightedIDs.splice(index, 1);
        }
        else {
            highlightedIDs.push(tag.id);
        }
    }

    return {
        isHighlighted: isHighlighted,
        highlight: hilight
    }
}]).filter('highlighted', ['highlightService', function(highlightService) {
    return function(input) {
        if(highlightService.isHighlighted(input) {
            return input;
        }
        else {
            return false;
        }
    };
}]);

Use both the service and filter in your HTML as appropriate.

Upvotes: 2

Related Questions