0

I am adapting a quite recent application to angular.

In this app, I have a menu on the left. When the user clicks on a category in the left menu, the center part of the application is changed. Nothing complex here.

Before angular, I used to explicitly write the tags for each element on the left menu :

<li class="menu-element" data-category="home"><a href="#"><span class="glyphicon glyphicon-home"></span>Home</a>
</li>
<li class="menu-element" data-category="news"><a href="#"><span class="glyphicon glyphicon-comment"></span>News</a>
</li>
<li class="menu-element" data-category="brands"><a href="#"><span class="glyphicon glyphicon-tower"></span>Brands</a>
</li>
<li class="menu-element" data-category="activity"><a href="#"><span class="glyphicon glyphicon-flash"></span>Activity</a>
</li>
[...]

Then add behavior with jQuery :

$(".menu-element").click(function () {
  [..]
});

Now, I rewrite it with angular. I declare the menu elements in a controller :

var ambasdrApp = angular.module('myApp', []);
myApp.controller('categoryListCtrl', function ($scope) {
  $scope.categories = [
    {'category': 'home',       icon :'home',     text: 'Home'},
    {'category': 'news',       icon :'comment',  text: 'News'},
    {'category': 'brands',     icon :'tower',    text: 'Brands'},
    {'category': 'activity',   icon :'flash',    text: 'Activity'},

  ];
});

Then I replace the HTML tags with a ng-repeat directive :

<li ng-repeat="category in categories" class="menu-element ng-scope" data-category="{{category.category}}">
   <a href="#"><span class="glyphicon glyphicon-{{category.icon}}"></span>{{category.text}}</a>
</li>

It works : the elements appear like before in the left menu.

Problem : The jQuery piece of code which adds "onClick" behavior does not work anymore. I suppose that when jQuery piece of code is executed, the menu elements do not exist yet.

  • one solution is to add an onClick="" in the ng-repeat directive. That would generate some <li onClick="[...]"> but I think that it is evil. I would prefer to isolate the js in *.js files.
  • Another solution would be to execute the JQuery piece of code after that the ng-repeat directive is executed but I do not know how I can hook this.

How would you make it work?

2 Answers 2

1

For each object in your categories, you could add a new attribute called click which defines the function:

$scope.categories = [
  {'category': 'home',       icon :'home',     text: 'Home',  click:function() {...}},
...

And then in your markup, you use the ng-click directive and do something like:

<li ng-repeat="category in categories" class="menu-element ng-scope" data-category="{{category.category}}" ng-click="category.click()"> 
Sign up to request clarification or add additional context in comments.

3 Comments

It throws a syntax error then fire ` click()` for every elements several times. error : Error: [$parse:syntax] errors.angularjs.org/1.3.12/$parse/…
@ArnaudDenoyelle Thanks for the catch - I had extraneous curly brackets in the ng-click definition. Answer has been edited to correct that. Incidentally, if all of your categories have identical click functions, you could also define that function once in your controller scope and just have every category item reference it.
It works, thanks mate! I defined $scope.onClick = function() {...} in the controller and used ng-click="onClick()" in the template. Hence,as you said, it avoids to repeat click=function(){} for each element.
0

I agree on @rchang solution in the HTML which is using ng-click.

It could be improved in the angular code itself though, as you clearly are not writing a custom function for each category, so there's no need for multiple declarations or assignments directly in the array :

var ambasdrApp = angular.module('myApp', []);
myApp.controller('categoryListCtrl', function ($scope) {

  $scope.categories = [
      ...
  ];

  $scope.yourFunction = function() {
      // your code here
  };

});

And of course ng-click in the HTML :

<li ng-repeat="category in categories" ng-click="yourFunction()" class="menu-element ng-scope" data-category="{{category.category}}">

A recommended AngularJS practice is also to attach the data to its controller to avoid confusion in large HTML which imbricate multiple controllers and directives.

So you would declare your categories and your function this way :

myApp.controller('categoryListCtrl', function () {

  this.categories = [
    ...
  ];

  this.yourFunction = function(params) {
      // your code here
  };

});

And then call them by the name of the controller :

<li ng-repeat="category in categoryListCtrl.categories" ng-click="categoryListCtrl.yourFunction()" class="menu-element ng-scope" data-category="{{category.category}}">

It may not be useful to you though, but this way of writing proves useful to avoid confusion and collision, typically :

<div ng-controller="GrandPaCtrl">
    {{ text }}
    <div ng-controller="ParentCtrl">
        {{ text }} - {{ $parent.text }}
        <div ng-controller="ChildCtrl">      
            {{ text }} - {{ $parent.text }} - {{ $parent.$parent.text }}
        </div>
    </div>
</div>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.