Angular: Creating attributes in HTML Elements

Angular gives the HTML page a lot more power to build its own destiny. We can embed view only concerns directly into the HTML. This helps separate the business logic from the the display logic. Of course this has positive and negative implications. One positive I found this week was the ability to create HTML Element attributes dynamically with no JavaScript.

I needed to create an iframe with conditionally set attributes. My goal was to avoid using JavaScript and the link function. I reasoned that the attributes should be a UI (view in the MVC model) concerns. It took some research, some trial, and mostly error to figure out. What I eventually found, I feel is a good way to go about creating HTML element attributes with only minor JavaScript, and as much Angular HTML craftiness as possible.

The directive definition is simple. We create the directive, and expect certain values in the scope that will be used by the template. In the example, the template is inline to keep things together. However, in practice the template is an external html file. Maintaining the template inline is a bit crazy, and even more so with the number of quote permutations this solution requires.

.directive('myframe', function (){
        restrict: 'E',
        template: '<iframe src="http://jsfiddle.net/" 
                       ng-attr-sandbox="{{sandbox === \'none\' ? \'\' : sandbox}}" 
                       ng-attr-seamless="{{seamless !== undefined ? \'seamless\' : undefined}}">
        scope: {
            sandbox: '@',
            seamless: '@'

The directive is very simple. We restrict the directive to element replacement, and pull sandbox and seamless values from the parent scope into the directive's isolate scope. The Angular magic is in the template. The "ng-attr-something" tag tells Angular that the expression results in an attribute name of something. For example, ng-attr-sandbox tells Angular to potentially create a sandbox= attribute on the compiled html. Angular evaluates the expression in the ng-attr tag and outputs any result that is truthy. Having the expression evaluate to an empty string or undefined will tell Angular not to include that attribute.

ng-attr-seamless="{{seamless !== undefined ? \'seamless\' : undefined}}"
This clause tells Angular to output the seamless attribute and set it to equal "seamless" as long as the seamless variable on scope is not undefined.

ng-attr-sandbox="{{sandbox === \'none\' ? \'\' : sandbox}}"
The sandbox clause was a little different. I wanted sandbox='' to output as a default. Therefore, I check to see if sandbox has a literal value of "none". If the incoming html has sandbox="none" then the sandbox attribute does not appear in the compiled output. If the incoming html has any other value for sandbox, then that value gets passed through to the attribute. If the incoming html is missing a sandbox attribute entirely then sandbox='' is output.

I would be interested in hearing how others have solved this conundrum. If you, like me, are pounding your head against the keyboard looking for answers, hopefully this trick can help. A fiddle to my solution is embedded below.


Building an Angular List: Using ng-repeat

There are many things about Angular that make it an excellent framework to use, and one of my favorites is the way it's data binding simplifies the implementation of UI elements. One of the most useful elements, in my opinion, is the ng-repeat. Ng-repeat makes creating lists so simple that you will want to use them all the time.


The jQuery Radio: Custom Triggers For a Pub/Sub Model

I like jQuery. It's the first library I used that gave me the "JavaScript is Awesome" tingle. Putting aside the many arguments for and against, jQuery is still used all around the web. When building from scratch we may choose more modern frameworks. However, building from scratch is a fine luxury and the exception to the norm. Many JavaScript programmers, if not most, spend their time improving existing sites and adding additional functionality. The result is that many of us still use jQuery on a daily basis. jQuery is also a great library for JavaScript beginners to get started with. So this post will visit one of jQuery's neatest features, "trigger".


Angular and Jasmine: Injecting into the test environment

I have set my sights on improving my Angular proficiency, however I am not ready to give up on all my other tools. I have a strong preference for Jasmine, and the recent release of 2.0 further cemented that comfort zone. Jasmine 2.0 made major improvements by removing window dependency and improving async support. Using Jasmine and Jasmine-Node together allows me to write tests in the same language for both server and client. I prefer to standardize as much as possible on a project, and having one language for tests on both application tiers is valuable to me in time and effort saved.


All original content in this blog belongs to the author, and can not be reproduced, integrated, or used without explicit consent. All links to this page are welcome, but please link to the blog page itself.