user3034151
user3034151

Reputation: 115

Angular Directive Advice

I have a data driven directive that takes a list of items and creates a list of radio buttons, although they've been skinned to look like buttons.

Everything is working fine, however, I would like to define an image URL within each item and then within ng-repeat display the image (the image would represent the button). At present the image URL is defined in the CSS which means I can only have one type of button. It needs to be more dynamic that that.

As usual any pointers would be really great.

Cheers.


CSS

        #buttonBox label {
            display: inline-block;
            cursor: pointer;
            position: relative;
            padding-left: 13px;
            margin-right: 46px;
            font-size: 13px;
        }

        #buttonBox label:before {
            content: "";
            width: 60px;
            height: 60px;
            border-radius: 8px;
            margin-right: 10px;
            display: inline-block;
            background-image: url('app/images/blue.png');
        }

        #buttonBox input[type=radio] {
            display: none;
        }

        #buttonBox input[type=radio]:checked + label:before {
            content: "";
            background-image: url('app/images/yellow.png');
        }

HTML

<da-buttons model="phone" items='phones' checked-index="0"></da-buttons>

Controller (these are the items)

$scope.phones = [ {
    text: "Android",
    group: "phoneGroup",
    value: 9
}, {
    text: "iOS",
    group: "phoneGroup",
    value: 10
}, {
    text: "Blackberry",
    group: "phoneGroup",
    value: 11
}];

Directive

var directives = angular.module('myApp.directives');

directives.directive('daButtons', function () {
    return {
        restrict: 'E',
        replace: true,
        scope: {
            model: '=',
            items: '=',
            checkedIndex: '@'
        },
        templateUrl: 'template/button-group.html',
        link: function(scope) {
            scope.onItemChange = function(item) {
                scope.model = item;
            };
        }
    };
});

Template: button-group.html

<div ng-repeat='item in items' id="buttonBox">
    <input
       type="radio"
       name="{{item.group}}"
       value="{{item.value}}"
       ng-model="model.value"
       ng-checked="$index==checkedIndex">
    <label ng-click="onItemChange(item)">{{item.text}}</label>
</div>

Upvotes: 2

Views: 115

Answers (3)

dfsq
dfsq

Reputation: 193261

The most flexible and unobtrusive approach would be to use CSS classes to define custom appearance. In controller you then define className property:

$scope.phones = [{
    text: "Android",
    group: "phoneGroup",
    value: 9
}, {
    text: "iOS",
    group: "phoneGroup",
    value: 10,
    className: 'fade-button' // <--- whatever
}, {
    text: "Blackberry",
    group: "phoneGroup",
    value: 11,
    className: 'circle-button' // <---
}];

and in template:

<div ng-repeat='item in items' id="buttonBox" class="{{item.className}}">
    ...
</div>

Now you only need to define CSS rules to style your new checkbox:

#buttonBox.fade-button label:before {
    background-image: url(some-image.png);
    background-color: red;
}
#buttonBox.fade-button input[type=radio]:checked + label:before {
    background-image: url(...);
}

Demo: http://plnkr.co/edit/YnIbCbW9jnzsZSMX8abL?p=preview

Upvotes: 0

Eugene P.
Eugene P.

Reputation: 2625

I would use inline approach. it will avoid css modification. If phones JSON is dynamic, it's even better, you don't need to do any changes to see that directive will pick up images correcly.

$scope.phones = [ {
        text: "Android",
        group: "phoneGroup",
        value: 9б
        image: 'img1'
    }, {
        text: "iOS",
        group: "phoneGroup",
        value: 10,
        image: 'img2'
    }, {
        text: "Blackberry",
        group: "phoneGroup",
        value: 11,
        image: 'img3
    }];

directive:

<div ng-repeat='item in items' id="buttonBox">
    <input
       type="radio"
       name="{{item.group}}"
       value="{{item.value}}"
       ng-model="model.value"
       ng-checked="$index==checkedIndex"
       class="set whatever class you need"
       style="background-image:url({{item.image}})>
    <label ng-click="onItemChange(item)">{{item.text}}</label>
</div>

Upvotes: 0

callmekatootie
callmekatootie

Reputation: 11228

At present the image URL is defined in the CSS which means I can only have one type of button.

You can use this to your advantage. Since the image comes from css, create different classes for each image. Such as:

.image-1 {
    background-image: url('path/to/image_1.png');
}

.image-2 {
    background-image: url('path/to/image_2.png');
}

.image-3 {
    background-image: url('path/to/image_3.png');
}

Then you can make use of the ng-class directive to decide which image to show. For example (Omitting other details of your template only for easier understanding):

<input ng-class="{determineClass(): true}[0]">

determineClass() is a scope function in your directive that will decide which of the image-* classes to apply based on your requirements.

Upvotes: 1

Related Questions