Is it good practice to use directives to separate controller logic in angular?

I have a rather complicated controller (about 3 thousand lines of code) that the panel demonstrates. The controller contains many diagrams, grid tables, etc.

For example, I moved the table table logic to a lower directive named wmGridActionItems . Note that it uses the parent scope:

 app.directive('wmGridActionItems', ['$rootScope', '$timeout', function ($rootScope, $timeout) { return { restrict: 'E', templateUrl: 'views/grid-action-items.html', link: function (scope, elem, attrs) { // logic goes here } }; }]); 

and HTML:

 <div ui-grid="gridActionItemsOptions" ui-grid-auto-resize ui-grid-pagination ui-grid-selection ui-grid-auto-resize ui-grid-resize-columns> </div> 

So basically the controller HTML I just write: <wm-grid-action-items></wm-grid-action-items>

I am unable to use this directive elsewhere, but at least I am dividing my BIG controller into a few small directives that will help me deal with the toolbar.

Am I doing something wrong? Is this a good practice? Does Angular have other approaches to solve this problem?

EDIT

This is my $StateProvider to display the panel:

 $stateProvider .state('sidemenu.dash', { url: '/dshmngr', abstract: true, views: { 'content': { templateUrl: 'views/dashboard/dashboard_manager.html', controller: 'DashboardMngrCtrl' } } }) .state('sidemenu.dash.main', { url: '/main', views: { 'content': { templateUrl: 'views/dashboard/dashboard-main.html', controller: 'DashboardNewCtrl' } } }) .state('sidemenu.dash.drill', { url: '/drill/:type', views: { 'content': { templateUrl: 'views/dashboard/dashboard-tag-details.html', controller: 'DashboardDetailedCtrl' } } }) 

Thanks,

+6
source share
2 answers

You are aimed in the right direction. Moving a large controller to smaller components in the form of directives is the way to go, but I suggest you make a few changes.

  • Isolate the scope of the directive and define the data that the directive expects explicitly. This way you can immediately see which data directive is taking.

  • For easier verification of a pair of directives with Controller .

Based on the above two sentences, your directive should look something like this:

 app.directive('wmGridActionItems', [function () { return { controller: 'WmGridActionItemsController' restrict: 'E', templateUrl: 'views/grid-action-items.html', scope: { gridActionItemsOptions: '=gridActionItemsOptions' } link: function (scope, elem, attrs) { // DOM manpulation (if needed) goes here } }; }]); app.controller('WmGridActionItemsController', ['$cope', '$timeout', function ($cope, $timeout) { // logic goes here }]); 

Then you call the following directive, for example:

 <wm-grid-action-items grid-action-item-options="gridActionItemsOptions"> </wm-grid-action-items> 

I suggest you also read this wonderful blog post detailing the "Component Pattern".

Also note that sharing a model by explicitly specifying it when defining an isolated area is not the only way. Another alternative for sharing data may be, for example, a model as a service (see related readings ).

+3
source

The "good practice" that I would recommend to you is the principle of one responsibility .

All components (directive / controller / service) that you create MUST never do more than one. If you avoid this error, your components will be much more reusable, readable, and customizable.

Of course, this practice is not only for angular .

You respect this, I would recommend you:

  • Avoid placing all of your business code in controllers and using services (or providers) instead. Services are more efficient as they allow the use of an angular injection system.

  • Directives should contain only manipulations with the DOM.

Angular Directive / Controller / Service is a View / ViewModel / Model template . Try to remember this.

Edit: Each of your directives may have a controller. You can place directives inside another directive template, and then use the last parameter of the controllers function and the parameter of the require directive to communicate between the directives.

Example: (coffeescript). Let's say I have a container that can be inside other containers and can also contain a widget:

 angular.module('dashboard') .directive('dashboardWidget', [() -> restrict: 'E' templateUrl : '/views/dashboard/widget.html' require: ['^^dashboardContainer'] scope: 'model': '=' controller: 'DashboardWidgetController' controllerAs: 'DashboardWidget' # default => post link (children already instanciated) link: ($scope, element, attrs, ctrls) -> [parentDashboardContainerController] = ctrls # some very small code (mainly events), the real code is in the controller return ]) angular.module('dashboard') .directive('dashboardContainer', [() -> restrict: 'E' templateUrl : '/views/dashboard/container.html' require: ['?^^dashboardContainer', '?^ngController'] scope: 'model': '=' controller: 'DashboardContainerController' controllerAs: 'DashboardContainer' # default => post link (children already instanciated) link: ($scope, element, attrs, ctrls) -> [parentDashboardContainerController, ngController] = ctrls # some very small code (mainly events), the real code is in the controller return ]) 
+1
source

All Articles