4

I want to change the color of the icon respect to the button clicked by the user ( say there is a popover which has three buttons namely high,medium , low . if a user clicks "high" it should changes to red color. medium - orange.. low - blue.. I made a directive for popover with three buttons. but i am unable to update the css classes with respect to the button click.

html:

 <span class="tk-action-s">
 <i priority-over class="fa fa-star {{colorChanger}}" ng-class="colorChanger"></i>
 </span>

directive :

myApplication.directive('priorityOver', function ($compile) {

    var itemsTemplate = "<div class=\"btn-group\"></div><div class=\"btn-group\"><label class=\"btn btn-danger\" ng-model=\"priority\" btn-radio=\"'high'\" ng-click=\"changeColor()\" uncheckable>High</label><label class=\"btn btn-warning\" ng-model=\"priority\" btn-radio=\"'medium'\" uncheckable>Medium</label><label class=\"btn btn-primary\" ng-model=\"priority\" btn-radio=\"'low'\" uncheckable>Low</label></div>";
    var getTemplate = function () {
        var template = '';
        template = itemsTemplate;
        return template;
    }
    return {
        restrict: "AC",
        transclude: true,
        template: "<span ng-transclude></span>",
        controller: function($scope, $element, $attrs) {
        $scope.colorChanger = 'col';
     },
        link: function (scope, element, attrs) {
            scope.colorChanger = 'col' ;
            var popOverContent;
                var html = getTemplate();
                popOverContent = $compile(html)(scope);
            var options = {
                content: popOverContent,
                placement: "bottom",
                html: true,
                //title: scope.title
            };
            $(element).popover(options);
            $('body').on('click', function (e) {
                $(element).each(function () {
                    // hide any open popovers when the anywhere else in the body is clicked
                    if (!$(this).is(e.target) && $(this).has(e.target).length === 0 && $('.popover').has(e.target).length === 0) {
                        $(this).popover('hide');
                    }
                });
            });
        }
    };
});
3
  • A sidenote: you absolutely must take care to destroy things "external" to Angular when the scope is destroyed: Kill the (jQuery?) popover, remove the body click listener. Code: scope.$watch('$destroy', function(){...}). Commented Nov 20, 2014 at 11:55
  • oh thanks for the note.. i will do it in my application. Is there any other chances that i can change the css class inside a directive ??? Commented Nov 20, 2014 at 11:58
  • Some things look more complicated than they should; why are you using transclusion? What is the itemsTemplate? Why are you using both a dynamic class attribute and ng-class? Have you tried adding a CSS class in your link function like element.addClass('myclass') (the element is already jQuery, no need to wrap it)? Commented Nov 20, 2014 at 12:06

1 Answer 1

1

As said in the comment by nikos it looks quite complicated. You seems to be mixing scopes, directives and templates. You might want to have a look at the documentation.

Anyway in the mean time here is an alternative to your solution.

html:

<div ng-app="example"> 
<span class="tk-action-s">
    <button priority-over class="fa fa-star col"></button>
</span>

<script type="text/ng-template" id="priorityPopover">
    <div class="btn-group">
        <label class="btn btn-danger" btn-radio="'high'" ng-click="changePriority('high')" uncheckable>High</label>
        <label class="btn btn-warning" btn-radio="'medium'" ng-click="changePriority('medium')" uncheckable>Medium</label>
        <label class="btn btn-primary" btn-radio="'low'" ng-click="changePriority('low')" uncheckable>Low</label>
    </div>
</script>

directive:

angular.module('example', []).directive('priorityOver', function ($compile, $templateCache) {
return {
    restrict: "AC",
    link: function (scope, element, attrs) {
        scope.changePriority = function (priority) {
            $(element).removeClass("low medium high");
            $(element).addClass(priority);
        };
        $(element).popover({
            content: $compile($templateCache.get('priorityPopover').trim())(scope),
            placement: "bottom",
            html: true,
            trigger: 'focus'
        });
    }
};

});

Note how template is externalized from the directive and loaded using the $templateCache service. Also no more transclusion and we expose the behaviour of adding and removing the style from the button via the scope. Allowing us accessing the element on which the directive is applied. Comes also handy when you want to do unit testing for example.

Sign up to request clarification or add additional context in comments.

5 Comments

how the popover is closed after a button click ? Is there is any external functions to do that ???
The option { trigger: 'focus' } tell the component to deal with opening and closing the popover for you. By default button gains the focus on click and loose it when you click else where. IMHO using a button is semantically better for this task as well.
trigger option is not working for me.. is there any other external function to do that ?
Which component are you using? The fiddle uses bootstrap one. getbootstrap.com/javascript/#popovers
If you are speaking about Angular UI then popover don't support html content because of the ng-bind. You can workaround but you need to do some nasty stuff. Angular-strap seems more permissive though.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.