AngularJS - Directives vs Controllers

43,444

Solution 1

Here's a brief stand-alone answer, with links to official docs for further info (definition of "services" added for good measure):

http://docs.angularjs.org/guide/controller

In AngularJS, a controller is a JavaScript constructor function that is used to augment the AngularJS scope.

When a controller is attached to the DOM via the ng-controller directive, AngularJS will instantiate a new controller object, using the specified controller's constructor function. A new child scope will be available as an injectable parameter to the controller's constructor function as $scope.

http://docs.angularjs.org/guide/directive

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

http://docs.angularjs.org/guide/services

AngularJS services are substitutable objects that are wired together using dependency injection (DI). You can use services to organize and share code across your app.

Solution 2

I think you should only use controllers to wire up services, dependencies & handle business logic.

Directives should be used for DOM manipulation so its great for handling user interactions e.g. add/edit a widget. It would be an anti pattern to add that to a controller as it's not a concern of the controller and it would get bloated by other features, it's easy enough to pass values(scope) from your controller to a directive if required.

You then get the advantage of being able to place your add a widget directive in other places of your app if required, and generally makes the code base easier to follow as its following Law of Demeter

Knowing when and where to split functionality is one of the hardest things for me about Angular you will make mistakes but it gets easier with practice.

To answer the question you probably should split it into a directive(s) but it's also a matter of complexity, If your app is simple like you said you may find what you have will be okay. It may just become a case of refactoring when a requirement changes.

Solution 3

My peers and I ran into a similar situation while learning AngularJS. I've put together this simple table that should give everyone a good starting point depending on what type of functionality they are trying to implement in Angular. http://demisx.github.io/angularjs/2014/09/14/angular-what-goes-where.html

Share:
43,444

Related videos on Youtube

mohi666
Author by

mohi666

Updated on July 09, 2022

Comments

  • mohi666
    mohi666 almost 2 years

    I am trying to create my first app using AngularJS. However, I'm a bit confused if I need to use directives for my particular case.

    I have a simple Map page, where I need to show lat/lon value of selected region. At the moment I'm not using directives at all. I do everything in controller and use partials to display the results. I am not planning to reuse my map view in any other place. That's why I didn't feel I would need a directive.

    On the other hand, I read somewhere that every time you try to manipulate DOM in your controller(which I'm doing using google maps API), you should move that part to directives.

    Here's my simple controller:

    function MapViewController($scope) {
      $scope.zoom = 6;
      $scope.lat = 37;
      $scope.lon = -122;
      var mapOptions = {
        center: new google.maps.LatLng($scope.lat, $scope.lon),
        zoom: $scope.zoom,
        mapTypeId: google.maps.MapTypeId.HYBRID
      };
      $scope.map = new google.maps.Map(
          document.getElementById('map-canvas'), mapOptions);
    
      /*
       * Update zoom and other map attributes.
       */
      google.maps.event.addListener($scope.map, 'center_changed', function() {
        $scope.$apply(function () {
          $scope.zoom = $scope.map.getZoom();
          var center = $scope.map.getCenter();
          $scope.lat = center.lat();
          $scope.lon = center.lng();
          var bounds = $scope.map.getBounds();
          var northEast = bounds.getNorthEast();
          $scope.northEastLat = northEast.lat();
          $scope.northEastLon = northEast.lng();
          var southWest = bounds.getSouthWest();
          $scope.southWestLat = southWest.lat();
          $scope.southWestLon = southWest.lng();
        });
      });
    
      /*
       * Set zoom and other map attributes.
       */
      google.maps.event.addListener($scope.map, 'some event', function() {
        $scope.$apply(function () {
          ...
        });
      });
    
      /*
       * Add markers to map.
       */
      google.maps.event.addListener($scope.map, 'another event', function() {
        $scope.$apply(function () {
          ...
        });
      });
    
    }
    

    And here's my partials:

      <div id="map-controllers" class="span4">
        <form class="form-horizontal">
          <div class="control-group">
            <label class="control-label" for="inputNumber">Zoom:</label>
            <div class="controls">
              <input type="text" class="input-mini" placeholder="zoom" value="{{ zoom }}">
            </div>
          </div>
          <div class="control-group">
            <label class="control-label" for="inputNumber">Latitude:</label>
            <div class="controls">
              <input type="text" class="input-large" placeholder="Latitude" value="{{ lat }}">
            </div>
          </div>
          <div class="control-group">
            <label class="control-label" for="inputNumber">Longitude:</label>
            <div class="controls">
              <input type="text" class="input-large" placeholder="Longitude" value="{{ lon }}">
            </div>
          </div>
          <div class="control-group">
            <label class="control-label" for="inputNumber">North East Latitude:</label>
            <div class="controls">
              <input type="text" class="input-large" placeholder="Latitude" value="{{ northEastLat }}">
            </div>
          </div>
          <div class="control-group">
            <label class="control-label" for="inputNumber">North East Longitude:</label>
            <div class="controls">
              <input type="text" class="input-large" placeholder="Longitude" value="{{ northEastLon }}">
            </div>
          </div>
          <div class="control-group">
            <label class="control-label" for="inputNumber">South West Latitude:</label>
            <div class="controls">
              <input type="text" class="input-large" placeholder="Latitude" value="{{ southWestLat }}">
            </div>
          </div>
          <div class="control-group">
            <label class="control-label" for="inputNumber">South West Longitude:</label>
            <div class="controls">
              <input type="text" class="input-large" placeholder="Longitude" value="{{ southWestLon }}">
            </div>
          </div>
        </form>
      </div>
    
  • greensin
    greensin over 4 years
    Please change Angular to --> AngularJS. (You are also referencing AngularJS documentation and not Angular). - AngularJS is 1.x versions of the framework. - Angular is ^2.x versions of another framework that behaves totally different.
  • Zano
    Zano almost 4 years
    @greensin I did that now, considering that the edit should be fairly uncontroversial.