Josh
Josh

Reputation: 1474

Understanding angular controllers Vs directives

I'm fairly new to angularjs. Im trying to understand why it's better to use this directive, compared to just using the controller. Both examples output the same value.

Directive Example:

angular.module('docsSimpleDirective', [])
.controller('Controller', ['$scope', function($scope) {
  $scope.customer = {
    name: 'Naomi',
    address: '1600 Amphitheatre'
  };
}])
.directive('myCustomer', function() {
  return {
    template: 'Name: {{customer.name}} Address: {{customer.address}}'
  };
});

Markup:

<div ng-controller="Controller">
  <div my-customer></div>
</div>

Controller Example:

angular.module('docsSimpleDirective', [])
    .controller('Controller', ['$scope', function($scope) {
      $scope.customer = {
        name: 'Naomi',
        address: '1600 Amphitheatre'
      };
    }])

Markup:

<div ng-controller="Controller">
   Name: {{customer.name}} Address: {{customer.address}}     
 </div>

Maybe I just don't fully understand directives either.

Upvotes: 3

Views: 1011

Answers (4)

Shaishab Roy
Shaishab Roy

Reputation: 16805

Controller:

A Controller is used to augment the Angular Scope.

When a Controller is attached to the DOM via the ng-controller directive, Angular will instantiate a new Controller object, using the specified Controller's constructor function.

controllers use to:

  1. Set up the initial state of the $scope object.

  2. Add behavior to the $scope object.

Do not use controllers to:

  1. Manipulate DOM — Controllers should contain only business logic.

  2. Format input — Use angular form controls instead.

  3. Filter output — Use angular filters instead.

  4. Share code or state across controllers — Use angular services instead.

Directives:

At a high level, directives are markers on a DOM element (such as an attribute, element name, comment or CSS class) that tell AngularJS's HTML compiler ($compile) to attach a specified behavior to that DOM element or even transform the DOM element and its children.

Angular comes with a set of these directives built-in, like ngBind, ngModel, and ngClass.

you can create your own directives for Angular to use.

Generally directives are used to:

  1. inject or wrapping existing thing.
  2. Reuse same things in different palce
  3. can inject in DOM element as attribute, element, comment or class

so if you need to reuse the same dom or logic in different place then you should use directive instead of controller.

Also you can access parent controller object from inner directive

Like:

<div data-ng-controller="mainController">
   <p>hello world</p>
   <some-directive></some-directive> // inject directive as element
</div>

Upvotes: 1

tomastrajan
tomastrajan

Reputation: 1726

There are multiple possible ways of how to bind functionality to template, some are better than others.

  1. BAD - use ng-controller attribute directly in html template to bind controller function to it

  2. BETTER - use ngRoute or ui-router to specify routes/states or your application and there you can specify controller and template per route/ state

  3. BEST - use directive definiton object where you can again specify both controller and template to bind them together and then use directive inside of templates and routes.

The third example is than flexible in such a way that you can use directive just in any other template like <div my-directive></div> but also in any router as a inline template like: template: '<div my-directive></div>'

The third approach is the best because it's going in direction of components which are the future (because of React, Angular 2.0 and Webcomponents). I wrote a blog post and created a sample github repository ilustrating these concepts.

Upvotes: 2

Pjetr
Pjetr

Reputation: 1382

At work, we use a simple exercise to see if we need a directive or not. If a certain snippet is used more than once, we turn it into a directive.

A directive also gives a chance to add less clutter to your templates.

angular.module('DocsSimpleDirective', [])
    .controller('DocsController', [function() {
        this.customer = {
            name: 'Naomi',
            address: '1600 Amphitheatre'
        };
    }])
    .directive('myCustomer', function() {
        return {
            scope: true
            restrict: 'EA',
            controller: 'DocsController',
            controllerAs: 'docsCtrls',
            templateUrl: 'assets/template/my-customer.directive.html'
        };
    })
;

would allow your template to be defined as:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Angular test</title>
</head>
<body ng-app="DocsSimpleDirective">
    <my-customer></my-customer>
</body>
</html>

and your directive as:

<article>
    <strong>{{ docsCtrls.customer.name }}</strong><br>
    {{ docsCtrls.customer.address }}
</article>

Personally, I try to refrain from using $scope to bind data to. If somebody else starts to read your code, a magical customer, defined in some controller somewhere on the scope is a lot harder to identify than a variable on a certain controller.

Isolating your $scope can be useful (by defining scope: true) to use a a default value. If you need to stop isolating your directives, it should be something you thought about, not because it's the default value.
When you don't isolate a scope it inherits all values that are defined in the $parentScope this is useful when nesting directives, where all directives should know which parent they originate from. This has a very distinct danger, you could manipulate data in the parentscope that shouldn't be manipulated.

https://docs.angularjs.org/api/ng/type/$rootScope.Scope

Upvotes: 5

Sudharsan S
Sudharsan S

Reputation: 15393

Other thing you need to set scope:true

.directive('myCustomer', function() {
  return {
    scope:true,
    template: 'Name: {{customer.name}} Address: {{customer.address}}'
  };
});

REFER THIS DOC

Upvotes: 2

Related Questions