{"id":279,"date":"2015-02-16T22:06:04","date_gmt":"2015-02-17T02:06:04","guid":{"rendered":"http:\/\/ryepup.unwashedmeme.com\/blog\/?p=279"},"modified":"2015-02-16T22:06:04","modified_gmt":"2015-02-17T02:06:04","slug":"different-kinds-of-angularjs-directives","status":"publish","type":"post","link":"http:\/\/ryepup.unwashedmeme.com\/blog\/2015\/02\/16\/different-kinds-of-angularjs-directives\/","title":{"rendered":"Different kinds of angularjs directives"},"content":{"rendered":"<p>Angularjs directives are a powerful tool. Like many powerful tools, it can take some time to figure out how to use it, and it&#8217;s easy to create a working solution that you&#8217;ll regret later. I&#8217;ve been using angular in small projects for a few years now, and have come up with a few different ways to think about and classify simple directives.<\/p>\n<h3>Component Directive<\/h3>\n<p>A logical user-inteface element. Is the trio of directive \/ template \/ controller. Usually has an isolated scope, and is self-contained. These are like .NET user or server controls. Much of <a href=\"https:\/\/github.com\/johnpapa\/angularjs-styleguide\">john papa&#8217;s style guide<\/a> advice applies to the controller and views used in component directive.<\/p>\n<p>Use attributes to pass data in, and data gets out via double-data binding, events, or calling services.<\/p>\n<p>Component directives are not composable.<\/p>\n<p>Usage looks like <code>&lt;my-component ng-model=\"vm.thing\"\/&gt;<\/code> (or <code>&lt;div my-component&gt;<\/code> depending on IE support).<\/p>\n<h4>Example<\/h4>\n<p><script src=\"https:\/\/gist.github.com\/ryepup\/287bbebf898aed7fe4a5.js\"><\/script><\/p>\n<h3>Mixin Directive<\/h3>\n<p>Add behavior to an existing element. Doesn&#8217;t isolate scope, but may read attributes directly. Rarely has a controller, mostly is just a link function.<\/p>\n<p>Similar to bootstrap data- annotations or the approach of &#8220;unobtrusive&#8221; jquery plugins that function based on custom attributes.<\/p>\n<p>Mixin directives are meant to be composable.<\/p>\n<p>Usage looks like <code>&lt;input ng-model=\"vm.thing\" my-mixin\/&gt;<\/code>.<\/p>\n<p>I haven&#8217;t found a many cases to write these, but many of the built-in directives fall into this category: <a href=\"https:\/\/docs.angularjs.org\/api\/ng\/directive\/ngDisabled\">ngDisabled<\/a>, <a href=\"https:\/\/docs.angularjs.org\/api\/ng\/directive\/ngClass\">ngClass<\/a>, etc.<\/p>\n<h3>DOM Macro Directive<\/h3>\n<p>Adds DOM to or around and existing element. Uses transclusion when possible, direct <a href=\"https:\/\/docs.angularjs.org\/api\/ng\/function\/angular.element\">angular.element<\/a> manipulation if not. Doesn&#8217;t have a scope, but may read attributes directly in the link function. Rarely has a controller, mostly is just a link function.<\/p>\n<p>Many of the <a href=\"http:\/\/angular-ui.github.io\/bootstrap\/\">angular bootstrap<\/a> directives fall into this category; they add a bunch of HTML so you don&#8217;t have to type it again.<\/p>\n<p>DOM macro directives are composable, but you&#8217;ll likely need to mess with priority to get the results you want.<\/p>\n<h4>Example<\/h4>\n<p><script src=\"https:\/\/gist.github.com\/ryepup\/81e7a0e75820e100e1fb.js\"><\/script><\/p>\n<h3>Meta Directive<\/h3>\n<p>Directive that adds other directives. Doesn&#8217;t isolate scope, rarely has a controller, reads configuration from attributes or services. Has some complicated boilerplate. The meta directive is similar to a DOM macro directive, and helps reduce repetitive angular directives.<\/p>\n<p>Meant to be composable, which is the primary reason to use these.<\/p>\n<p>Usage looks like <code>&lt;button ng-click=\"vm.remove()\" my-remove-button\/&gt;<\/code>.<\/p>\n<p>Most macro directives could be implemented as component directives or DOM macro directives, but will less flexibility. For example, we could implement a remove button as a component, and use it like <code>&lt;my-remove-button ng-click=\"vm.remove()\"\/&gt;<\/code>.<\/p>\n<p>But then we want to disable the button sometimes. In the macro directive, we can just add <a href=\"https:\/\/docs.angularjs.org\/api\/ng\/directive\/ngDisabled\">ngDisabled<\/a>:<\/p>\n<p><code>&lt;button ng-click=\"vm.remove()\" my-remove-button ng-disabled=\"vm.canRemove\"\/&gt;<\/code><\/p>\n<p>For the component directive, we can do the same thing, but we need to teach the component about <code>ng-disabled<\/code>, and it&#8217;s template needs to render as <code>&lt;button ng-disabled \/&gt;<\/code>. This is straightforward work, but still work.<\/p>\n<p>The remove button isn&#8217;t a great example since it&#8217;s so simple, but is shows the weird boilerplate needed. Consider wanting common settings throughout your application for a more complicated directive like a <a href=\"http:\/\/angular-ui.github.io\/bootstrap\/#\/datepicker\">datepicker<\/a><\/p>\n<h4>Example<\/h4>\n<p><script src=\"https:\/\/gist.github.com\/ryepup\/dcfaa1242163e108596c.js\"><\/script><\/p>\n<h3>Other references<\/h3>\n<ul>\n<li><a href=\"http:\/\/stackoverflow.com\/a\/19228302\">Add directives from directive in AngularJS<\/a><\/li>\n<li><a href=\"http:\/\/stackoverflow.com\/a\/27605580\">wrapping inputs in directives in angular<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Angularjs directives are a powerful tool. Like many powerful tools, it can take some time to figure out how to use it, and it&#8217;s easy to create a working solution that you&#8217;ll regret later. I&#8217;ve been using angular in small projects for a few years now, and have come up with a few different ways [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[48,38],"tags":[],"class_list":["post-279","post","type-post","status-publish","format-standard","hentry","category-angularjs","category-javascript"],"_links":{"self":[{"href":"http:\/\/ryepup.unwashedmeme.com\/blog\/wp-json\/wp\/v2\/posts\/279","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/ryepup.unwashedmeme.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/ryepup.unwashedmeme.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/ryepup.unwashedmeme.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/ryepup.unwashedmeme.com\/blog\/wp-json\/wp\/v2\/comments?post=279"}],"version-history":[{"count":6,"href":"http:\/\/ryepup.unwashedmeme.com\/blog\/wp-json\/wp\/v2\/posts\/279\/revisions"}],"predecessor-version":[{"id":285,"href":"http:\/\/ryepup.unwashedmeme.com\/blog\/wp-json\/wp\/v2\/posts\/279\/revisions\/285"}],"wp:attachment":[{"href":"http:\/\/ryepup.unwashedmeme.com\/blog\/wp-json\/wp\/v2\/media?parent=279"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/ryepup.unwashedmeme.com\/blog\/wp-json\/wp\/v2\/categories?post=279"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/ryepup.unwashedmeme.com\/blog\/wp-json\/wp\/v2\/tags?post=279"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}