Vikas Singhal
Vikas Singhal

Reputation: 836

Passing value of a variable to angularjs directive template function

I am trying to pass a $scope's variable to a directive, but its not working. I am catching the variable in the template function:

app.directive('customdir', function () {

    return {
        restrict: 'E',

        template: function(element, attrs) {
            console.log(attrs.filterby);
            switch (attrs.filterby) {
                case 'World':
                    return '<input type="checkbox">';
            }
            return '<input type="text" />';
        }
    };
});

What I need is the value of variable filterby not the variable name itself.

Plunkr Demo

Upvotes: 12

Views: 51094

Answers (3)

Khanh TO
Khanh TO

Reputation: 48972

Template should not contain logic because template is view. Template should only contain binding directives to make the view updated based on changes of the scope (model). Something like this:

app.directive('customdir', function ($compile) {

    return {
        restrict: 'E',

        scope:{
          filterby:"="
        },

        link:function (scope, element) {
          scope.$watch("filterby",function(newValue){ //logic is out of template
              if (newValue == "World"){
                scope.showCheckBox = true;
              }
              else {
                scope.showCheckBox = false;
              }
          });
        },

        template: function(element, attrs) {
         //View should be passive and only listens to changes of model to update it accordingly.
            return '<input type="checkbox" ng-show="showCheckBox" / ><input type="text" ng-show="!showCheckBox"  />'; 
        }
    };
});

With this approach, you could even change the input at runtime and the view is updated to reflect the changes.

DEMO

If you want to make a decision on which template to use based on some configuration, you should configure it via a normal property, should not access though scope's propery. Simply like this:

app.directive('customdir', function ($compile) {

    return {
        restrict: 'E',
        scope: {
            filterby:"=" //filterby is a separate field used for data binding
        },

        template: function(element, attrs) {
            switch (attrs.type) { //view selection configuration should be obtained from the element
                case 'checkbox':
                    return '<input type="checkbox">';
            }
            return '<input type="text" />';
        }
    };
});

Configure it by passing a normal value:

<customdir type="checkbox" filterby="name"></customdir>

DEMO

Upvotes: 9

ms87
ms87

Reputation: 17492

First of all, what is a template function? It should be a link function. Second, you're overloading the link function incorrectly, order matters here, its always scope, element, attrs .Third, pass the variable in an isolate scope:

app.directive('customdir', function ($compile) {

    return {
        restrict: 'E',
        scope:{
          filterby:'='
        },

        link: function(scope,element, attrs) {
            console.log(scope.filterby);
            switch (scope.filterby) {
                case 'World':
                    return '<input type="checkbox">';
            }
            return '<input type="text" />';
        }
    };
});

or if you insist on attributes then:

 app.directive('customdir', function ($compile) {

        return {
            restrict: 'E',

            link: function(scope,element, attrs) {
                console.log(attrs.filterby);
                switch (attrs.filterby) {
                    case 'World':
                        return '<input type="checkbox">';
                }
                return '<input type="text" />';
            }
        };
    });

but in your html:

 <customdir filterby="{{name}}"></customdir>

To ensure the variables value gets evaluated first. Finally you should not be manipulating the DOM like that, in fact that link function won't render html as you'd expect. You have a static template and your link function will act as something to set variable values on the template.

Upvotes: 1

kfis
kfis

Reputation: 4729

Or like this

app.directive('customdir', function ($compile) {
  var getTemplate = function(filter) {
    switch (filter) {
      case 'World': return '<input type="checkbox" ng-model="filterby">';
      default:  return '<input type="text" ng-model="filterby" />';
    }
  }

    return {
        restrict: 'E',
        scope: {
          filterby: "="
        },
        link: function(scope, element, attrs) {
            var el = $compile(getTemplate(scope.filterby))(scope);
            element.replaceWith(el);
        }
    };
});

http://plnkr.co/edit/yPopi0mYdViElCKrQAq9?p=preview

Upvotes: 14

Related Questions