1

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.

1 Answer 1

2

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">
Sign up to request clarification or add additional context in comments.

7 Comments

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.
How would you use a template file instead of the return template code in this case?
And for the sake of argument, what if I do need isolate scope? :))
I will do my best to include all the details!
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.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.