1

I am creating an application from legacy code using AngularJS.

I wonder what parts of my code should be moved into a directive.

For example, iI had thought of moving a table which is used multiple times across the application into a directive. The tables alter from headings and size.

Is it worth the effort or even a good practice to turn such things into their own directives or should I create each table in a unique way?

2 Answers 2

1

There are quite a few reasons for using a directive:

  • The classic one: it needs to access the DOM / window / document. This should be kept to a bare minimum however, as Angular can handle a lot of things via templating + 2 way data-binding.
  • You have a reusable component, or one that might be reused in future. This should be considered even if it doesn't need to access the DOM directly, as directive templates are still $compiled in the usual way, and support all the standard 2-way data bindings.
  • You have a controller or template that you would like to somehow pass options to, or call functions or update data on the parent scope, without polluting the scope chain. You can use the scope option when creating a directive for this, which can handle the 3 most used cases

    1. Binding a variable on the directive's isolated scope to the parent scope (using =). For example, I suspect the usual use of ngModel uses this so it can modify the model object as needed.

    2. Creating a function on the directive's isolated scope that then evaluates an expression in the parent scope (using &). For example, I suspect ngClick uses this to pass a callback to the directive.

    3. Binds a variable on the directive's isolated scope to an interpolated string on the parent scope specified by an attribute (using @). TBH, I'm yet to use this.

    If for some reason you then still need access the attributes of the element directly, you can use the argument that is often referred to as tAttrs / iAttrs in the compile and link functions. See the documentation for $compile

  • You would like to enforce a separation of concerns between business logic, and view logic. You could make a generic table component to show data from completely difference sources in different parts of your app. Maybe then add some sorting functionality, etc.
  • You would like to make smaller component controllers, and allow them to still communicate with each other, in a non-brittle (with respect to the DOM) way. The require option when creating a controller allows directive controllers to communicate with each other. For example, ngModel must require an optional parent ngForm, so it then registers itself with the form at linking time, so the ngForm can work out its validation state. If you want to customise or create your own form inputs, then you can require ngModel to communicate with its controller. Adding parsers or custom validation would be a typical use-case for this.
  • One that should be used very sparingly: if you want to make a variable or function accessible to all child scope/templates. For example, I recently made a responsive directive, without an isolated scope, that adds a variable to the scope, and hence all child scope, that holds the current window size + "class" (say, mobile or large screen). This changes on a debounced listener + $apply to the window resize event, so other templates only change when the window has stopped resizing.

    Another use case for this, is to add routing $state to all child scopes. The example at https://github.com/angular-ui/ui-router/wiki/Quick-Reference#note-about-using-state-within-a-template uses run and $rootScope, but a slightly more flexible approach would be to add this in a directive, so theoretically you could have a section in your app without the $state variable in the scope/template.

If any of the above would hold true if you were to refactor, then definitely consider it. I think the main jist of the above is that the components should be small, and have a clearly defined purpose, and so be fairly easy to test. If things are long, consider refactoring to directive(s). The above points are all to do with the interface. If you have common business functionality, then this would typically be in services.

1

If it is reusable and manipulates the DOM, it probably should go into a directive. That allows you to test it once, write it once, and use it multiple places. If you find yourself referencing elements directly in the controller, it's a good sign you should go to a directive because controllers shouldn't have to interact with the DOM directly at all.

The table example sounds fine - for example in our apps we might make a grid directive and reduce the amount of effort it takes to configure settings for a grid because they are managed via defaults in the direective.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.