jaruesink
jaruesink

Reputation: 1203

Passing attrs as $scope variables in Angular

I have a directive and I'm trying to get the Attrs and pass them to the $scope, but I'm not quite sure how to do that. More specifically I'm trying to set attributes in my template equal to what the name is set in my date-picker tag. I tried setting them as a variable, but obviously that didn't work. Help and further clarification is greatly appreciated. Thanks!

HTML

<date-picker id="dateendPicker" name="date_end"></date-picker>

JS

App.directive('datePicker', function(){
  return {
  scope: {
          name : '@'
         },
  restrict: 'AE',
  replace: 'true',
  template: '<div class="date"><div class="input-group"><input type="text" class="form-control" id="{{this_name}}" name="{{this_name}}" ng-model="event.{{this_name}}" required/><span class="input-group-addon"><i class="fa fa-calendar"></i></span></div></div>',
  controller: ['$scope', function($scope){
        $scope.this_name = this_name;
  }],
  link: function(scope, element, attrs){
    var this_name = attrs.name;
  }
  }
});

Upvotes: 1

Views: 342

Answers (3)

kleinph
kleinph

Reputation: 181

There are some issues with your code snippet: First you do not assign the assign the attrs to the scope but to a local variable, so it won't be available in the controller function.

You could try this:

App.directive('datePicker', function(){
    return {
        scope: {
            name : '@'
        },
        restrict: 'AE',
        replace: 'true',
        template: '<div class="date"><div class="input-group"><input type="text" class="form-control" id="{{this_name}}" name="{{this_name}}" ng-model="event.{{this_name}}" required/><span class="input-group-addon"><i class="fa fa-calendar"></i></span></div></div>',
        controller: ['$scope', function($scope){
            $scope.this_name = this_name;
        }],
        link: function(scope, element, attrs){
            scope.this_name = attrs.name;
        }
    }
});

I do not know if this really works since it is not recommended to use controller and link functions at the same time (taken from the directive guide):

Best Practice: use controller when you want to expose an API to other directives. Otherwise use link.

But according to the docs the attrs are also available as $attrs to the controller function:

App.directive('datePicker', function(){
    return {
        scope: {
            name : '@'
        },
        restrict: 'AE',
        replace: 'true',
        template: '<div class="date"><div class="input-group"><input type="text" class="form-control" id="{{this_name}}" name="{{this_name}}" ng-model="event.{{this_name}}" required/><span class="input-group-addon"><i class="fa fa-calendar"></i></span></div></div>',
        controller: ['$scope', '$attrs', function($scope, $attrs){
            $scope.this_name = $attrs.name;
        }]
    }
});

But you have already defined name in the isolate scope, so it should be availble as scope.name in the conroller or link function:

App.directive('datePicker', function(){
    return {
        scope: {
            name : '@'
        },
        restrict: 'AE',
        replace: 'true',
        template: '<div class="date"><div class="input-group"><input type="text" class="form-control" id="{{this_name}}" name="{{this_name}}" ng-model="event.{{this_name}}" required/><span class="input-group-addon"><i class="fa fa-calendar"></i></span></div></div>',
        link: function(scope, element, attrs){
            console.log(scope.name); // this is your name defined as attribute name="..." on the tag
        }
    }
});

Upvotes: 0

Serhii Holinei
Serhii Holinei

Reputation: 5864

As I could see from your snippet, you want to use name attribute as ng-model into directive. I think, you should consider using another type of isolated scope (related SO answer)

Here is my approach (jsFiddle):

app.directive('datePicker', function () {
    return {
        scope: {
            name: '=name'
        },
        restrict: 'AE',
        replace: 'true',
        template: 
            '<div class="date">' +
                '<div class="input-group">' +
                    '<input type="text" ' +
                            'class="form-control" ' +
                            'id="bad-idea-to-make-it-editable-id" ' +
                            'name="{{ name }}" ' +
                            'ng-model="name" ' +
                            'required/>' +
                    '<span class="input-group-addon">' +
                        '<i class="fa fa-calendar"></i>' +
                    '</span>' +
                '</div>' +
            '</div>'
        }
    });

So now you can edit parent scope from directive. But if you dont want this kind of communication between scopes, use @ scope, as @haimlit has mentioned.

Upvotes: 0

haimlit
haimlit

Reputation: 2582

Because of how you've defined your directive scope:

  scope: {
      name : '@'
  }

name is already a variable on your scope. If you're not doing anything special with it on your controller\link functions, you can drop them entirely, and in your template reference it with {{name}}. Just note that if you're creating scope bindings with '@', then in your html you should pass your data as an angular expression, meaning:

name="{{date_end}}"

Upvotes: 2

Related Questions