Currently, I am working on developing an Angular application utilizing Bootstrap.
To reduce the impact of Bootstrap on my HTML code, I have implemented two directives specifically for forms:
form-control.js
module.directive('formControl', function() {
return {
restrict : 'E',
templateUrl : 'form-control.tmpl.html',
scope: {
label: '@'
},
transclude : true
};
});
form-control.tmpl.html
<div class="form-group">
<label class="control-label col-sm-2">
{{ label }}
</label>
<div class="col-sm-10"
ng-transclude>
</div>
</div>
In addition, I have developed a set of "extensions" to these directives tailored for various form input fields. For example:
form-input-text.js
module.directive('formInputText', function() {
return {
restrict : 'E',
templateUrl : 'form-input-text.tmpl.html',
scope: {
label: '@',
value: '=ngModel'
}
};
});
form-input-text.tmpl.html
<form-control label="{{label}}">
<input type="text"
class="form-control"
ng-model="value">
</form-control>
app.html
<form-input-text label="Name"
ng-model="person.name">
</form-input-text>
A challenge arises within this setup due to multiple scopes in use:
appScope = { person : { name : "John" } };
isolateScope = {
label: "Name",
value: "John" // bound two-way with appScope.person.name
};
transcludeScope = {
__proto__: isolateScope,
label: "Name", // inherited from isolateScope
value: "John" // inherited from isolateScope
};
When altering the text in the input box, only transcludeScope
is affected:
appScope = { person : { name : "John" } };
isolateScope = {
label: "Name",
value: "John" // bound two-way with appScope.person.name
};
transcludeScope = {
__proto__: isolateScope,
label: "Name", // inherited from isolateScope
value: "Alice" // overrides value from isolateScope
};
The reason behind this behavior is that the <input>
directly links to a property of transcludeScope
. Any modifications are made to transcludeScope.value
, and do not reflect back to appScope
through isolateScope
.
I am looking to establish a bidirectional binding between appScope.person.name
and a nested property of isolateScope
, like isolateScope.model.value
.
It would be ideal if I could declare the directive as follows:
form-input-text.js
module.directive('formInputText', function() {
return {
restrict : 'E',
templateUrl : 'form-input-text.tmpl.html',
scope: {
model: {
label: '@',
value: '=ngModel'
}
}
};
});
This modification would enable the transcluded section to bind to model.value
, ensuring changes are visible to isolateScope and subsequently propagated to appScope
.
Unfortunately, it appears that Angular does not directly support this particular usage.
If anyone knows of an Angular feature that can accommodate this scenario or offer a workaround, please provide guidance.
Edit:
For the time being, I have opted to integrate the form-control
template into the form-input-text
template.
form-input-text.tmpl.html
<div class="form-group">
<label class="control-label col-sm-2">
{{ label }}
</label>
<div class="col-sm-10">
<input type="text"
class="form-control"
ng-model="value">
</div>
</div>
This approach eliminates the introduction of a child scope via ng-transclude
, but results in duplicated markup which defeats the purpose of consolidating everything into one place.