Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

I tried searching for this but I didn't quite know how to phrase the idea.. Let me try and explain. I am still trying to grasp the whole scope in directives thingy..

The code below are some variations of the same directive (it is not a lot of code,, it just seems that way)

Say.. In my controller I have this

$scope.foo = {name: "John", color: "Green"};

My directive looks something like this

app.directive("miniDirective", function () {
return {
    restrict: "A",
    scope: {
        type: "=type",
        value: "@value"
    },
    template:'<div>{{content}}</div>' + 
             '<input type="text" ng-model="content">',
    link: function (scope, iElm, iAttrs) {

        switch (scope.value) {
            case "name":
                scope.content = scope.type.name; break;
            case "color":
                scope.content = scope.type.color; break;
        }
        console.log(scope.content);
    }
}

})

and I would like to use my directive like this

    <div mini-directive
        type="foo"
        value="name">
    </div>

    <br/>

    <div mini-directive
        type="foo"
        value="color">
    </div>

PROBLEM 1: If I use the above directive then scope.content does not bind back to scope foo (type attribute) value.. I kind of understand why this is,, BUT I have NO idea how to make that happen...

Then I tried doing it differently.. and that is where I got stuck,,,

app.directive("miniDirective", function () {
return {
    restrict: "A",
    scope: {
        type: "=type",
        value: "@value"
    },
    template:'<div>{{type.XXXX}}</div>' + 
             '<input type="text" ng-model="type.XXXX">',
    link: function (scope, iElm, iAttrs) {

       // I WOULD LIKE TO CHANGE xxxx based on value attribute 
       // AND keep the binding working
           scope.type.xxxx;

    }
}
})

QUESTIONS

Is there a way to convert the value from value attribute value: "@value" into something that can then be dynamically applied to scope.type.xxxx; where xxxx is either name or color? Can it be done without using "switch" as I did in the first example or "if else" or any condition that checks for existing values...

OR,,, in the case where I used switch,, is there a way to bind scope.content back to foo.name or foo.color DEPENDING on the value being passed in the attribute?

I am on my way to try and make a jsfiddle for this...

I would be very grateful for your help.

share|improve this question

1 Answer 1

up vote 2 down vote accepted

It is unnecessary to create an isolated scope if you only need to bind your template to an outer scope object's property.

You can easily create the right expression based on the directive's attributes like so:

var expression = tAttrs.type + '.' + tAttrs.value // foo.name

And then just create a template with that expression:

'<input ng-model="' + expression + '">' // <input ng-model="foo.name">

You can pass a function to the template option of a directive and build your template however you need.

here is a plunker: http://plnkr.co/edit/ekvPcyXeEPuebmC2mbHP?p=preview

Solution:

app.directive("miniDirective", function () {
  return {
      restrict: "A",
      template: function(tElm,tAttrs){
       var exp = tAttrs.type + "." + tAttrs.value;
       return '<div>{{' + exp + '}}</div>' + 
              '<input type="text" ng-model="' + exp + '">';
      }
  }
})

If you need to create an isolated scope for other reason

  • Create a two way data binding using the expression I mentioned above.
  • I use $parse for optimization.
  • I use templateUrl as you asked in the comment.

Another plunker: http://plnkr.co/edit/zG9dbnlUjjr1KTwbVe2i?p=preview

app.directive("miniDirective", function ($parse) {
  return {
      restrict: "A",
      scope:{},
      templateUrl: "mini.html",
      compile: function(tElm, tAttrs){
        var expFn = $parse(tAttrs.type + '.' + tAttrs.value);
        return function(scope,elm,attrs){

          scope.$parent.$watch(expFn, function(val){
            scope.exp = val;
          })

          scope.$watch('exp', function(val){
            expFn.assign(scope.$parent, val)
          })

        }
      }
  }
})

And the template:

<div> {{ exp }}</div>
<input type="text" ng-model="exp">
share|improve this answer
    
Man, you nailed it on the nose :) Thanks! I do have other "operations" to do within the directive ,, this was a stripped out version but none the less,, you helped me a great deal. Thank you. –  GRowing Jan 30 '14 at 0:42
    
How would you use a template file instead of the return template code in this case? –  GRowing Jan 30 '14 at 0:48
    
And for the sake of argument, what if I do need isolate scope? :)) –  GRowing Jan 30 '14 at 0:55
    
I'm working on that, next time don't omit the little details... –  Ilan Frumer Jan 30 '14 at 0:56
1  
That is fantastic advice. And I agree. I will have to start doing that regularly because I am having an increased need for ng. Thanks man. You really helped me a lot. –  GRowing Jan 30 '14 at 2:01

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.