Vishal Seth
Vishal Seth

Reputation: 5048

angular directive attributes not evaluated

I've tried the answer mentioned here but no luck (I'm using angularjs 1.3). My problem is two part

1) Complex attributes are not being passed as objects despite using '=' (see code below) in scope

2) the function that should evaluate to provide one-way binding is also being passed as string instead

sample use,

<button type="button" class="btn btn-success" ng-click="RestEditCtrl.saveRestaurantDetails();">
    <smart-btn-label btn-state="RestEditCtrl.ajaxState(RestEditCtrl.restaurant.id)"
        when-normal="{label: 'Save', icon: 'glyphicon-floppy-disk' }"
        when-active="{label: 'Saving...', icon: 'glyphicon-refresh glyphicon-spin-animate'}"
        when-success="{label: 'Saved!',   icon: 'glyphicon glyphicon-floppy-saved'}"
        when-error="{label: 'Try saving again',  icon: 'glyphicon glyphicon-exclamation-sign'}"></smart-btn-label>
</button>

directive code,

angular.module("app")
    .directive('smartBtnLabel', function () {
        return {
            restrict: 'E',           
            scope: {
                btnState: '&', // not working, @ evaluates but that defeats my purpose
                whenActive: '=', //  not evaluating any which way, it always comes as string
                whenError: '=',
                whenSuccess: '=',
                whenNormal: '='
            },
            link: function (scope, elem, attrs) {
                console.log(attrs);
                var curState = "normal",
                    curLabel = attrs.whenNormal ? attrs.whenNormal.label : "",
                    curIcon = attrs.whenNormal ? attrs.whenNormal.icon : "";

                if (attrs.btnState) curState = attrs.btnState;

                if(curState == "active"){
                    curLabel = attrs.whenActive  ? attrs.whenActive.label : "";
                    curIcon = attrs.whenActive ? attrs.whenActive.icon : ""
                } else if(curState == "success"){
                    curLabel = attrs.whenSuccess ? attrs.whenSuccess.label : "";
                    curIcon = attrs.whenSuccess ? attrs.whenSuccess.icon : ""
                } else if(curState == "error"){
                    curLabel = attrs.whenError  ? attrs.whenError.label : "";
                    curIcon = attrs.whenError  ? attrs.whenError.icon : ""
                }

                scope.curLabel = curLabel;
                scope.curIcon = curIcon;
            },
            template: '<span aria-hidden="true" ng-show="curIcon" class="glyphicon {{curIcon}}" ></span>' +
                      '<span ng-show="curLabel">&nbsp;{{curLabel}}</span>'
        };
    });

What am I doing wrong here? :-(


Solution

Thanks to PSL, here is what I ended up with:

angular.module("app")
    .directive('smartBtnLabel', function () {
        return {
            restrict: 'E',           
            scope: {
                btnState: '&', 
                whenActive: '&',
                whenError: '&',
                whenSuccess: '&',
                whenNormal: '&'
            },
            controller: ['$scope', function($scope){
                var vm = this;
                vm.props = {icon: "", label: ""};

                var _setProperties = function () {
                    var _btnState = "normal";

                    if ($scope.btnState) _btnState = $scope.btnState();

                    if (_btnState == "active" && $scope.whenActive) vm.props = $scope.whenActive();
                    else if (_btnState == "success" && $scope.whenSuccess) vm.props = $scope.whenSuccess();
                    else if (_btnState == "error" && $scope.whenError) vm.props = $scope.whenError();
                    else if ($scope.whenNormal) vm.props = $scope.whenNormal();
                };

                if($scope.btnState){
                    $scope.$watch($scope.btnState, function () {
                        _setProperties();
                    });
                }

                _setProperties();
            }],
            controllerAs : "smartBtnLabelCtrl",            
            template: '<span aria-hidden="true" ng-show="smartBtnLabelCtrl.props.icon" class="glyphicon {{smartBtnLabelCtrl.props.icon}}" ></span>' +
                      '<span ng-show="smartBtnLabelCtrl.props.label">&nbsp;{{smartBtnLabelCtrl.props.label}}</span>'
        };
    });

Upvotes: 3

Views: 2619

Answers (1)

PSL
PSL

Reputation: 123739

1) Complex attributes are not being passed as objects despite using '=' (see code below) in scope

That is because you are getting them as attrs.whenNormal which is a string (JSON). You instead just need to access it from scope, i.e scope.whenNormal. It would just be same as scope.$eval(attrs.whenNormal) or JSON.parse(attrs.whenNormal)//provided your JSON is valid. But the 2 way binding here doesn't make much sense though.

2) the function that should evaluate to provide one-way binding is also being passed as string instead.

That is because when you use function binding they get evaluated as getter with bound values (you specified bound value as RestEditCtrl.restaurant.id). Inorder to access the value, provided the function ajaxState returns something, you need to do curState = scope.btnState(); instead of curState = attrs.btnState, basically evaluate the getter to get the value.

Plnkr

Upvotes: 5

Related Questions