0

i'm wondering if there is a good practice solution for the following situation in AngularJs:

I have a html that is basically displaying a list of elements and a controller that is the view-model and handles certain events for that list. I use this html/controller combination on different spots within my app by using ng-include.

List.html:

<div ng-controller="listController">
<!--... display List here-->
</div>

Now I have been using events from the parent scope to fill the list controller with elements.

ListController.js

angular.module("app").controller('listController', function($scope) {
  let $scope.elements = []; 
  $scope.$on('setElementsEvent', function(event, data) {
    $scope.elements = data; 
  });
});

This has been working fine so far. But now I have the situation, that one parent controller has multiple of these Lists as children, but I want them to display distinct elements. With broadcasting events I would always set the elements for all child lists! Using a factory would pose the same problem, since all of the listControllers have the same controller function.

parent.html

<div ng-controller="parentController">
  <!--first list-->
  <div ng-include='"List.html"'></div>

  <!-- second list -->
  <div ng-include='"List.html"'></div>
</div>

Is there a way to get this done without having to write a new controller for every list I want to display?

1
  • Good practice is not to use standalone controllers at all. Use components. Commented Feb 26, 2017 at 20:24

3 Answers 3

1

Good practice is not to use standalone controllers at all. Use components, they accept arguments in the form of bindings.

Here you have an example usage:

angular
  .module('exampleApp', [])
  .run($rootScope => {
    $rootScope.productSetA = [{
        name: 'Foo'
      },
      {
        name: 'Bar'
      },
      {
        name: 'Baz'
      }
    ];

    $rootScope.productSetB = [{
        name: 'Fiz'
      },
      {
        name: 'Fooz'
      },
      {
        name: 'Fez'
      }
    ];

    $rootScope.productSetC = [{
        name: 'Booze'
      },
      {
        name: 'Beeze'
      },
      {
        name: 'Beep'
      }
    ];
  })
  .component('productList', {
    bindings: {products: '<'},
    template: '<div ng-repeat="product in $ctrl.products" ng-bind="product.name">'
  });
product-list {
  display: block;
  background-color: tomato;
  margin: 5px;
  padding: 5px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.1/angular.min.js"></script>

<div ng-app='exampleApp'>
  <product-list products='productSetA'></product-list>
  <product-list products='productSetB'></product-list>
  <product-list products='productSetC'></product-list>
</div>

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks a lot to all of you. Started digging into components, this really opens up a whole new world!
1

Best way it switch to components and set attributes or require parent controller in the child.

However if you want to go with ng-include, try ng-repeat. It creates independent scope for every iteration and set $index and variable value which are available to the child scope through $scope.$parent

so your code will look like:

<div ng-controller="parentController">
    <div ng-repeat="ctrlId in ['first', 'second']" ng-include='"List.html"'></div>
</div>

Better way is to convert your template to components https://docs.angularjs.org/tutorial/step_03

Comments

0

well one solution in my head is to set a determinant parameter for each controller, the other solution is to use a directive for each list, you can know more about directives here , and for the first solution here's an example

HTML

<div ng-controller="listController" ng-init="ctrlNo=1"><!--here you set the determinant factor for this controller-->
 <!--... display List here-->
</div>

ListController.js

angular.module("app").controller('listController', function($scope) {
  $scope.ctrlNo=0;
  let $scope.elements = []; 
  $scope.$on('setElementsEvent', function(event, data) {
   if($scope.ctrlNo===1){//Here you stop the propagation to do the specific actions for the specific controller
       $scope.elements = data; 
   }
  });
});

1 Comment

all <div ng-controller="listController" ng-init="ctrlNo=1"> are on the same scope, so all controllers will receive the same value.

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.