I'm trying to create few directives which would wrap layout so I can abstract from that layout (which is one of the main goals of directives as I understand it).
So what I would like to have is something like this:
<dialog>
<dialog-title></dialog-title>
<dialog-body></dialog-body>
<dialog-footer></dialog-footer>
</dialog>
I have created 3 simple directives for this which look similar to this
app.directive('dialog', ()=>{
return {
template: '<div class="dialog" ng-transclude></div>',
replace: true,
transclude: true,
restrict: 'E',
}
})
Then I want to ensure that models defined in one directive (dialog-body) will be visible in another (dialog-footer) because I would need some form on that dialog and some nav buttons in footer that may be disabled on not depending on either that form valid or not.
<body ng-controller="MainCtrl">
<p>age: {{age}}</p>
<dialog>
<p>age: {{age}}</p>
<dialog-body>
<form name="dialogForm">
<p>age: {{age}}</p>
<input ng-model="age" minlength="3"/>
</form>
</dialog-body>
<dialog-footer>
<p>age: {{age}}</p>
</dialog-footer>
</dialog>
</body>
ng-model
in dialog-body
will create age variable in dialog-body's scope but it would not appear in other directives untill I put it in object and declare in MainCtrl
. This is how it work:
<body ng-controller="MainCtrl">
<p>age: {{user.age}}</p>
<dialog>
<p>age: {{user.age}}</p>
<dialog-body>
<form name="dialogForm">
<p>age: {{user.age}}</p>
<input ng-model="user.age" minlength="3"/>
</form>
</dialog-body>
<dialog-footer>
<p>age: {{user.age}}</p>
</dialog-footer>
</dialog>
</body>
and controller:
app.controller('MainCtrl', function($scope) {
$scope.user = {age: 1}
})
Now, I want to put a form in dialog-body
. That should create FormController on dialog-body's scope, just like ng-model
did (or here are some difference?). And I need to have access to it from dialog-footer to check form validity.
So after creating form in template i need to define formController in MainCtrl's scope and here is first question - how do I create instance of FormController? I thought that $scope.dialogForm = {$valid: true}
should work for testing purposes and here is my final template:
<body ng-controller="MainCtrl">
<p>age: {{user.age}}</p>
<p>validity: {{dialogForm.$valid}}</p>
<dialog>
<p>age: {{user.age}}</p>
<p>validity: {{dialogForm.$valid}}</p>
<dialog-body>
<form name="dialogForm">
<p>age: {{user.age}}</p>
<p>validity: {{dialogForm.$valid}}</p>
<input ng-model="user.age" minlength="3"/>
</form>
</dialog-body>
<dialog-footer>
<p>age: {{user.age}}</p>
<p>validity: {{dialogForm.$valid}}</p>
</dialog-footer>
</dialog>
</body>
Here comes main problem. When form validity changes in dialog-body
it does not reflect in other directives. Why? What am I missing here?
My main target is to have directives for most used components in application so that I will have abstraction from actual layout - can this be done in different way?
Here is the plunk
When form validity changes in dialog-body it does not reflect in other directives. Why?
In your directives transclude: true
will create a new scope and inherit from the parent scope
which in this case is the scope of MainCtrl
. From what I can tell, when you declare <form name="dialogForm">
, angular will bind a formController to the transcluded scope of dialogBody
, i.e. for dialogBody
it will do $scope.dialogForm = formController
and because it is a new scope, the other transcluded scopes will not see this change.
To fix this, you can declare a shared variable in the parent scope or use the controller as syntax which is essentially the same thing.
<body ng-controller="MainCtrl as vm">
and then bind the form to vm
<form name="vm.dialogForm">
<p>age: {{vm.user.age}}</p>
<p>validity: {{vm.dialogForm.$valid}}</p>
<input ng-model="vm.user.age" minlength="3"/>
</form>
See plunker
Why does this work? Because all the new transcluded scopes inherit the vm
from the parent scope and the formController vm.dialogForm
is bound to this common variable so all the transcluded scopes will see this change.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With