I have pretty complicated controller (about 3K rows of code) that demonstrates dashboard. Controller contains a lot of charts, grid tables, and so on.
For example I moved grid table logic to undermentioned directive named wmGridActionItems
. Notice, it uses 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 in main controller HTML i just write: <wm-grid-action-items></wm-grid-action-items>
I don't manage to use this directive in other places but at least I divide my BIG controller to several little directives that should help me to handle dashboard.
I do something wrong? Is it good practice? Has Angular other approaches to solve this issue?
EDIT
This is my $StateProvider
for dashboard view:
$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,
AngularJS ng-controller Directive The ng-controller directive adds a controller to your application. In the controller you can write code, and make functions and variables, which will be parts of an object, available inside the current HTML element. In AngularJS this object is called a scope.
Directives are classes that add additional behavior to elements in your Angular applications. Use Angular's built-in directives to manage forms, lists, styles, and what users see.
A controller is usually used to contain and maintain the logic for your view, which gets bound to your view via $scope. A directive is something that you might use repeatedly and is called in your view directly through the directive name which you can pass in as an attribute.
Answer:The link option is just a shortcut to setting up a post-link function. controller: The directive controller can be passed to another directive linking/compiling phase. It can be injected into other directices as a mean to use in inter-directive communication.
In Angular, there are three types of directives those are component directive, attribute directive and structural directive. A component directive is a simple class which is decorated with the @component decorator. In Angular, once typescript class has been decorated with a @component decorator, it will become a Component class.
If you are scared from Angular CLI output showed above or if you’re curious how that code-splitting actually happens then this post is for you. Code splitting allows you to split your code into various bundles which can then be loaded on demand. If used correctly, can have a major impact on load time. Why should I care? Why should I care?
In Angular, once typescript class has been decorated with a @component decorator, it will become a Component class. It is mainly used to specify the HTML templates. Attribute directives are a way of changing the appearance or behavior of a component or a native DOM element. It is used to change the attributes of the existing HTML element.
Directives are very similar to controllers in many ways. Here is a simple example of a directive that follows the same logic as the Angular controller that we discussed before. We have a controller here for the directive that handles the business logic, thus eliminating the need to add garbage to the $scope variable.
You are aiming at the right direction. Breaking a large controller into more smaller components in the form of directives is the way to go but I would suggest you to introduce few changes.
Isolate the scope of directive and define the data that directive expects explicitly. That way one can instantly see what data directive accepts.
For easier testing pair the directive with Controller
.
Based on the above two suggestions, 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
}]);
You would then call above directive like:
<wm-grid-action-items grid-action-item-options="gridActionItemsOptions">
</wm-grid-action-items>
I suggest you to also read this great blog post which explains "Component Pattern" in details.
Also note that sharing a model by explicitly specifying it when defining an isolated scope is not the only way. Another alternative for sharing a data would for example be a Model as a service (please see related reading).
The "good practice" that I would recommend to you is the single responsibility principle.
Every components (directive/controller/service) that you build MUST never do more than one thing. If you avoid this error, your components will be way more reusable, readable and maintanable.
Of course, that practice is not only for angular.
One you respect that, I would recommend you to :
Avoid to put all your business code in controllers, and to use instead services (or providers). Services are way more powerfull as they allow to use the angular dependency injection system.
Directives should contain only DOM manipulation.
Angular Directive/Controller/Service is kind of a View/ViewModel/Model pattern. Try to keep that in mind.
Edit: Every of your directives can have a controller. You can put directives inside an other directive template and then use the last parameter of the link function (controllers
) and the directive require
parameter for the communication between directives.
Example: (coffeescript) Let's say i have a container that can be inside others containers itself and may contain also 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
])
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With