2

I have a directive with isolated scope as following:

 application.directive("myDirective",function(){ return { restrict: "A", scope: {myDirective:"="}, link : function(scope) { console.log("My directive: ",scope.myDirective) // works fine scope.person={name:"John",surname:"Doe"} scope.hello=function(){ console.log("Hello world!") } } } }) 

Corresponding view:

<div my-directive='{testValue:3}'> Testvalue: {{myDirective}}<br/> Hello {{person}} <button ng-click="hello()">Say hello</button> </div> 

And it seems that i cannot use any of the fields declared in the scope. In view the "myDirecive" and "person" fields are blank and the scope's "hello" function is not executed when i press the button.

It works fine when i pass scope="true" to the directive but does not work in isolated scope.

Am i missing something here or maybe there is no way to introduce variables to the isolated scope of a directive?

UPDATE

Updated question presenting why i would rather not to use a static template. The effect i am trying to achieve is to make directive that allows to upload any html form getting the form initial data via rest/json. The whole process is rather complex and application specific therefore i cannot use any available form libraries. I present below the simplified version of the use case:

The updated directive

 application.directive("myForm",function(){ return { restrict: "A", scope: {myForm:"="}, link : function(scope) { console.log("Form parameters: ",scope.myForm) // works fine scope.formData=... // Get form initial data as JSON from server scope.submitForm=function(){ // Send scope.formData via REST to the server } } } }) 

The case when i would like to use this form. Of course i would like to use this directive many times with different forms.

<form my-form='{postUrl:'/myPostUrl',getFormDataUrl:'/url/to/some/json}'> <div>Form user: {{formData.userName}} {{formData.userSurname}} <input type="text" ng-model="formData.userAge" /> <input type="text" ng-model="formData.userEmail" /> <button ng-click="submitForm()">Submit</button> </form> 

I hope this explains why i cannot use one static html template for this scenario.

Maybe someone can explain why this is working with scope="true" and with an isolated scope i cannot access any scoped variables?

2 Answers 2

1

With Angular, directives either work with a template (or templateUrl) or with transcluded content.

If you're using a template, then the template has access to the isolate scope. So, if you put {{person}} in the template it would work as expected.

If you're using transcluded content - that is, the content that is a child of the node which has the directive applied to it - then, not only would you need to set transclude: true and specify where in the template the transcluded content goes - e.g. <div ng-transclude></div> to even see the content, you would also not get the results you expect, since the transcluded content has access to the same scope variables as the parent of the directive, and not to those available in the isolate scope of the directive.

Also, you should be aware that if you pass a non-assignable object to the directive's isolate scope with "=" - like you did with my-directive="{testValue: 3", then you can't make any changes to it (and, unfortunately, even to its properties even if they are scope variables).

So, to make your specific case work, do this:

application.directive("myDirective",function(){ return { ... template: "Testvalue: {{myDirective}}<br/> " + "Hello {{person}} " + "<button ng-click="hello()">Say hello</button>"; }; }); 

and the corresponding view:

where prop is set in the View controller to: $scope.prop = {testValue: 3};

Sign up to request clarification or add additional context in comments.

6 Comments

the transcluded content is bound to the same scope as the parent of the directive , actually it's bound to a new child scope of the parent which makes it a sibling scope to the directive's isolated scope.
Yes, that's more accurate, but I meant in terms of what scope variables one would have access to, - which is of relevance to the question, not how the scope hierarchy goes.
Just think you should be more accurate because overall it's a good answer. Put a link to the docs docs.angularjs.org/guide/…
Actually i would like the "myDirective" not to use a template, it is supposed to be a simple directive that sets few values on the scope and can be used multiple times with different content each time. Therefore i cannot just specify the HTML template. Is there still a way to do this in a way that allows any html to be inside my directive?
@IlanFrumer I agree. I will fix as soon as I'm near a big screen
|
0

You can always alter the default behavior of transcluded scope ( though I don't recommend it):

application.directive("myDirective",function(){ return { tranclude: true, scope: {myDirective:"="}, link : function(scope, element, attrs, ctrl, $transclude) { $transclude(scope, function(clone) { element.empty(); element.append(clone); }); scope.person={name:"John",surname:"Doe"}; scope.hello=function(){ console.log("Hello world!"); }; } }; }); 

See the docs: https://docs.angularjs.org/api/ng/service/$compile#transclusion-functions

Also take a look at ngTranslude source code: https://github.com/angular/angular.js/blob/master/src/ng/directive/ngTransclude.js

5 Comments

fix typo in tranclude... why wouldn't you recommend this?
Because by this, you'll make all child elements isolated from the parent scope. Each time you'll need something from the outer scope you'll be stuck with either adding it to the directives scope definition or using $scope.$parent which is an anti-pattern. A good directive wouldn't take over the whole template.
Then you could just set scope: true, which seems like what the OP wants after reading his comments. It would be better if he posted a separate question and this was the answer, because the current question here doesn't explain what the objective is.
If i set scope=true is there a way of passing a configuration object to myForm template as it was shown in the example? Without scope : { myform:"="} i cannot seem to get form contifuration as an object...
with scope: true your directive prototypically inherits the parent's scope, so whatever is declared at the parent level is available to the child.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.