3

When using element directives I have seen Angular element directives used in two ways:

1. As block level components

The element is styled as display:block, is the component and its children are the component's children, so the element itself is the component.

Use of directive:

<example class="Example"></example>

The directive's html:

<header class="Example-header"></header>
<img class="Example-image">
<footer class="Example-footer"></footer>

2. As an inline wrapper of the component

The element is left as display:inline and effectively acts as an invisible wrapper for the component itself:

Use of directive:

<example></example>

The directive's html:

<div class="Example">
  <header class="Example-header"></header>
  <img class="Example-image">
  <footer class="Example-footer"></footer>
</div>

Obviously each have advantages and disadvantages for example extra markup, loss of layout context due to inline element etc, but is one the correct way? or is this another of Angular's vagaries?

Undistraction
  • 42,754
  • 56
  • 195
  • 331

2 Answers2

2

I'm surprised no one responded, but the idea behind creating custom directives is the ability to create reusable pieces of code that fulfill a specific bit of functionality on your site.

This functionality, however, doesn't care about the styles that you are going to use. You can of course conditionally change classes and styles from within Angular, but the core component when dealing with the framework is the data.

With that being said, there is no "correct way" as you bolded in your question. Develop the directive to fit your needs and style of your site.

KreepN
  • 8,528
  • 1
  • 40
  • 58
  • Your answer is definitely more concise. Its a pretty good answer even if i think none of theses way are a good way to use custom directives. – Okazari Jul 17 '15 at 14:42
  • @Okazari The real reason it supports both is because of the separation of concerns within development. That UX guy who doesn't know anything about Angular needs the ability to request that the directives themselves render as a block or even an inline element from the developer. If it didn't support such ability, people would have a cow. – KreepN Jul 17 '15 at 14:46
  • I totally agree. And that's why i also think directive should not add HTML by itself. It makes the works for UX guy a lot easier. – Okazari Jul 17 '15 at 14:47
  • I appreciate it doesn't care about the styles, but that isn't what i'm asking. I'm interested in whether it is standard to treat the element directive as a transparent wrapper of whatever html it needs to render or as the html itself. Should it *contain* the outer element or *be* the outer element? – Undistraction Jul 17 '15 at 14:49
  • @Pedr From KreepN : "there is no "correct way" as you bolded in your question." From me : "The two way you're asking about are just different. No one is better than the other it will just depend on your own HTML organisation and it will depend on the directive use.". I think you got a common answer about this. – Okazari Jul 17 '15 at 14:54
  • @Okazari Thanks. Yes. Then that is an answer in itself. – Undistraction Jul 17 '15 at 14:55
  • 2
    @Pedr Fun fact, not that it is used anymore, but the directive property `replace` used to be used to do just what you talk about in your comment. The directive would function as a wrapper based on the true or false setting of said property. http://stackoverflow.com/a/22498024/771928 . Its depreciated now, but I think the Angular authors struggled with you same question at one time about how "should it" function. – KreepN Jul 17 '15 at 14:58
  • Interesting. Thanks for the link. – Undistraction Jul 17 '15 at 16:01
1

First this is probably opinion based but i'd really like to share my point of view about this.

If you really follow angular way of doing directives none of theses are a correct way.

Directives are intended to add a behavior to an HTML element.

The less the directive add HTML the best it is as it allow you to have a better control on this element.

Lets take an exemple.

We have a data grid (let say ui-grid, it doesn't really matter)

 <ui-grid ...>
    ...
 </ui-grid>

I had a the idea to add some button to add or remove element in the grid. I first came up with this

 <ui-grid ...>
    ...
 </ui-grid>
 <button ng-click="addItem()">Add</button>
 <button ng-click="removeItem()">Remove</button>

I'm really happy with this and that's ok, but finally i need to use theses buttons in some other views. I'll have to duplicate the HTML, duplicate the JS and adapt it to the collection.

The common mistake

That's obviously not a good idea.

Instead i will do a directive. Lets say "button-list" : it produce the same html and behavior.

 <ui-grid ...>
    ...
 </ui-grid>
 <button-list></button-list>

That's pretty cool.

Now i have some need. On one view i need the add button to be blue, on an other one i don't need to have a remove button, and on a last one i want the button text to be "X" and "+" (That's was some request by a client in a true story).

I could make a big object with a list of option and etc... but this is really painful and you need to touch the directive each time you need to add a custom different little behavior.

The good way to go

Now lets just think again about what i wanted to do.

I want the button to interact with the grid... and that's pretty much all. This is how we should go building a custom directive.

We could then produce this directive this way :

 <div grid-button-container collection="mycollection">
     <ui-grid ...>
        ...
     </ui-grid>
     <button grid-add-item>Add</button>
     <button grid-remove-item>Remove</button>
 </div>

So what do we have here ? We have three different directives.

  1. grid-button-container : Its responsibility is to hold the list for the sub-directives.
  2. grid-add-item : It add a function on click that add an element to the collection of grid-button-container.
  3. grid-remove-item : It add a function on click that remove an element to the collection of grid-button-container.

Both grid-add-item and grid-remove-item will be requiring the grid-button-container to be used.

I cannot describe all the implementation of this (it would take too long) but i think this is how directives should be used. Such as almost no angular build-in directives (ng-*) add HTML and just add a behavior i think all the directives should be build in this way.

Pro :

  1. You have a full control about your HTML
  2. Directives are tiny and trivial
  3. This is really re-usable

Cons :

  1. Can be harder and longer to implement.

To make a final point, the two way you're asking about are just different. No one is better than the other it will just depend on your own HTML organisation and it will depend on the directive use.

Hope it helped.

Okazari
  • 4,597
  • 1
  • 15
  • 27
  • Thanks for the lengthy answer. I'm currently writing Sass for a large Angular project that is broken up into over 100 directives. Each is a chunk of html and its behaviours. The use of directives is very inconsistent, with some directives where the directive *is* the outermost element of the html it renders, and some where it effectively contains the outermost node and effectively acts as a kind of marker element taking no part in layout. I am not really interested in how to decompose directives as this isn't something I have any control over. – Undistraction Jul 17 '15 at 14:54