spongessuck
spongessuck

Reputation: 1073

AngularJS Accessing Aliased Controller Attribute From Directive

OK this is a contrived example, but...

Say I have a controller like this:

app.controller('TestCtrl', function() {
    this.testString;
    this.otherString;
});

And I have a template like this:

<div ng-controller='TestCtrl as test'>
    <input demo type='text' ng-model='test.testString'>
    {{test.otherString}}
</div>

And then I have a directive like this:

app.directive('demo', function() {
    return {
        require:'ngModel',
        link: function(scope, elem, attrs, ctrl) {

            scope.$watch(attrs.ngModel, function(newVal) {

                /* How do I get otherString without knowing the controller alias?
                   This works but is not good practice */
                scope.test.otherString = newVal + ' is cool!';

                /* This doesn't work, but would if the property was in scope 
                   instead of the controller */
                scope[attrs.demo] = newVal + ' is cool!';
            });
        }
    }
});

How do I get otherString without knowing the controller alias? I could just break apart attrs.ngModel to get it, but is there an 'angular' way to get the property?

EDIT

While this example didn't exactly reflect the issues I was having with my real scenario, I did find out how to get the controller's property in the link function, allowing me to update the model:

        link: function(scope, elem, attrs, ctrl) {

            var otherString = scope.$eval(attrs.demo);              

            scope.$watch(attrs.ngModel, function(newVal) {
                otherString = newVal + ' is cool!';
            }
        }

Upvotes: 2

Views: 697

Answers (2)

Jeremy Elbourn
Jeremy Elbourn

Reputation: 2700

A directive should have zero knowledge of anything outside of itself. If the directive depends on an outside controller having defined some arbitrary property, things will break very easily.

Defining a "scope" property on the directive lets you expose an explicit API for binding data to the directive.

myModule.directive('demo', function() {
  return {
    scope: {
      demoString: '=demo',
    },
    link: function(scope, element, attrs) {
      // You can access demoString here, or in a directive controller.
      console.log(scope.demoString);
    }        
  };
});

And the template

<div ng-controller='TestCtrl as test'>
    <input demo="test.otherString" ng-model='test.testString'>
    {{test.otherString}}
</div>

This isn't the only way to facilitate passing data or setting up bindings to a directive, but it is the most common way and should cover the majority of use-cases.

Upvotes: 3

Rorschach120
Rorschach120

Reputation: 1210

If you are trying to be more angular-like I would just use the $scope in the controller and pass that to the directive like so:

app.directive('demo', function() {
  return {
    scope: {strings: '='},
    link: function(scope, elem, attrs, ctrl) {

        scope.$watch('strings.test', function(newVal) {

            /* How do I get otherString without knowing the controller alias? */
            scope.strings.other = newVal + ' is cool!';

        });
    }
}
});

then in the html:

   <div ng-controller='TestCtrl as test'>
      <input demo type='text' strings="strings" ng-model="strings.test" />
      {{strings.other}}
   </div>

In the controller you would assign:

$scope.strings = {
    test: '',
    other: ''
}

Upvotes: 0

Related Questions