2
\$\begingroup\$

I found creating radio buttons in my application a bit of a hassle in terms of having to configure the HTML to do what I wanted when the user clicks/unclicks the items etc.

I figured reducing it to a directive was the best way to simplify things.

The functionality I want is:

  • Be able to pass in a list of items that are displayed as radio button options
  • Be able to specify which item is checked by default
  • Can be displayed as a horizontal or vertical list
  • Have the option to make the buttons unselectable (i.e. clicking them again will uncheck the item)
  • The controller knows which value is checked.
  • The controller executes a function when the checked value changes
  • The controller can change which item is checked

Here is a working plunker.

Here is an example usage of the directive:

<dwj-radio-group 
    dwj-items = "items"
    dwj-changefn = "changeFn"
    dwj-unselectable = "true"
    dwj-align = "vertical"
    dwj-boundvalue = "foo"
    >
</dwj-radio-group>

Here is the directive code:

var radioDirective = app.directive('dwjRadioGroup', function($compile, $templateCache ) {

    var getTemplate = function(item){
        var template = 'ERROR'; 
        console.log(item);
        switch (item){
        case 'horizontal':
            template = $templateCache.get("radio-group-horizontal.html");
            break;
        case 'vertical':
            template = $templateCache.get("radio-group-vertical.html");
            break; 
        }

        return template; 
    };

    return {
        scope : {
            items : '=dwjItems',
            changeFn : '=dwjChangefn',
            selectedItem: "=dwjBoundvalue",
            unselectable: "=dwjUnselectable", 
            align:          "=dwjAlign"


        },

        link : function(scope, element, attrs) {

            scope.unselectable =scope.unselectable === 'true';                          //default false
            scope.align = scope.align === "vertical"? "vertical": "horizontal";         //default horizontal

            //http://onehungrymind.com/angularjs-dynamic-templates/         
            var content = getTemplate(scope.align);
            console.log(content);
            element.html(content);
            $compile(element.contents())(scope);

            scope.changeItem = function(x){
                if (scope.unselectable && x === scope.selectedItem){                    
                    scope.selectedItem = null;              
                }               
                else{                   
                    scope.selectedItem = x;                     
                }           

                scope.changeFn(scope.selectedItem);
            };
        }
    };
});

Currently, from what I can see, the directive does everything I want it to.

I'm looking for feedback on my use of the directive:

  • Are my naming conventions correct?
  • Am I using the directive scope binding correctly?
  • Is using $templateCache and $compile a good way to do this, or is there a much simpler way to do it?
  • Is there anything completely broken that I'm missing?
\$\endgroup\$
1
\$\begingroup\$
items : '=dwjItems',
changeFn : '=dwjChangefn',
selectedItem: "=dwjBoundvalue",
unselectable: "=dwjUnselectable", 
align:          "=dwjAlign"

Your indentation needs some work.

scope : {
    items : '=dwjItems',
    changeFn : '=dwjChangefn',
    selectedItem: "=dwjBoundvalue",
    unselectable: "=dwjUnselectable", 
    align:          "=dwjAlign"
},

Not sure why you need to prefix "dwj" to your directive attributes. It's not like it will collide with anything else. Besides, you're using the directive as an element. No potential DOM attribute name collisions.

scope.unselectable =scope.unselectable === 'true';                          //default false
scope.align = scope.align === "vertical"? "vertical": "horizontal";         //default horizontal

//http://onehungrymind.com/angularjs-dynamic-templates/         
var content = getTemplate(scope.align);
console.log(content);
element.html(content);
$compile(element.contents())(scope);

Not entirely sure why you need to dynamically compile the template. You can simply just define both layouts in the same template and hide one of them when the other is selected. You can use ng-if for that. A developer can come in and say "Oh, two layouts for a directive" than "Oh, I have to take care of 2 template files."

\$\endgroup\$
  • \$\begingroup\$ could you please elaborate a little bit more on the indentation issue? \$\endgroup\$ – Malachi Feb 27 '16 at 15:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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