Writing scripts for your websites or web apps is often a simple process, you write your script, concatenate the file into your main scripts file and it gets pushed into the DOM. Not much to it, but when it comes to AngularJS, they believe in something slightly different…
No DOM manipulation should be carried out inside a Controller, the Controller is where most of your magic happens, a communications channel between your Model data and the browser. It can be tempting to simply whack in an existing script in there (as it’ll work just fine), but this goes against Angular’s principles.
So here’s how to migrate one of your existing scripts or plugins across into a tightly coded AngularJS directive, this also makes code readability and reuse ultra-efficient, as Directives take the strain of repetitive code out the window.
Defining a Directive:
Directives are really easy to use once you’ve set them up. For purposes of this demonstration I’m going to migrate FluidVids across into an AngularJS Directive.
Here’s the existing code for the script, annotated below to show what each part does.
First you need to know how to restructure your code, instead of using a small API to apply your script to each of the elements in your selector/plugin. Remember to apply your changes to the single scoped element only, as Directives are for reused components and therefore can be repeated a lot, so they refer to themselves instead of as a NodeList of elements to loop through.
I’ll talk through the above for those interested in what the workings are. A Directive returns an Object, which all of the configuration sit inside for that specific Directive. I’ve used restrict with the value of ‘EA’, this means either an Element or Attribute. I then use replace to replace the markup in the DOM so that it renders nice and valid. I’m using a scope here as the third property which you can grab as your element name. Using [email protected] means I’m just using this as a string, which you’ll see I’ve used inside my small template which gets injected in the DOM with the custom video src. I’m also using ng-src here which Angular recommend for better browser consistency when dynamically creating src attributes (mainly for legacy browsers, ofc). I then create a small link function which defines any DOM manipulation past the template that needs doing. You can also bind click events any anything else here too.
Release Candidate errors with cross-domain media
Whilst porting FluidVids over to AngularJS, it was really easy testing until I hit the Release Candidate (version 1.2.0-rc.2). They’ve actually done this to help you out, but you actually need to whitelist external domains that you’ll be retrieving media from. I got this error whilst changing from version 1.0.8 to 1.2.0-rc.2:
Turns out, after a quick Google search I needed to whitelist the domains I use inside AngularJS, a somewhat protectively smart move (even though slightly irritating error) by the team. After some searching I found somebody had commented the following which whitelists all domains for quick and ease use:
Custom Elements or Attributes (E or A, or both!)
If you’re advocating HTML5 Web Components and developing for HTML5 browsers only, then you might as well start creating your own elements inline with the HTML5 Web Components spec.
As an attribute:
Depending on your team and setups, it might be easier using one method or the other. They’re not too indifferent, but I feel Web Components offer oddly better semantics - despite their loose markup that let the developer decide.
Web Components introduces custom attributes too, use - but don’t abuse :)