问题
I have a simple directive which repeats a section of transcluded content twice. Like this.
link: function (scope, element, attrs, controller, transclude) {
transclude(scope.$parent, function(clone) {
element.find('[transclude-main]').replaceWith(clone);
});
transclude(scope.$parent, function(clone) {
element.find('[transclude-overflow]').replaceWith(clone);
});
});
This works mainly as intended but if the content contains a form then I end up with two forms with the same name.
More importantly my main page controller (customers) only has reference to one of the forms (customers.myForm) so if I try to reset the form or call any other form controller functions only one of the forms changes, obviously.
So, I tried to modify my code to look for forms and change the form name to something new, like this.
link: function (scope, element, attrs, controller, transclude) {
transclude(scope.$parent, function(clone) {
element.find('[transclude-main]').replaceWith(clone);
});
transclude(scope.$parent, function(clone) {
clone.find('FORM').each(function() {
$(this).attr('name', $(this).attr('name') + '2');
});
element.find('[transclude-overflow]').replaceWith(clone);
});
});
This does actually modify the HTML for me and I end up with two forms - myForm and myForm2.
The problem is that there is still only one reference to myForm in my main controller. The first one works but the second one doesn't. I can only assume that they are somehow compiled against the scope.$parent which I'm passing into the transclude function before I'm messing about with the clone? If that's the case I'm not sure how to fix it.
EDIT:
Added a plunkr here:
https://plnkr.co/edit/XE7REjJRShw43cpfJCh2
If you open a dev console you'll see that I'm using console.log to write out the contents of myForm and myForm2 which should be the two copies of the form in my second toolbar. myForm2 doesn't exist and I suspect this is because it's compiled against the parent scope before it's cloned.
回答1:
So here's a plunkr with I thinnnnk gets at what you're trying to do: https://plnkr.co/edit/8VxNPVmeLNLKyaQNReM3?p=preview
Note these lines in particular:
HTML:
<toolbar name="myForm" form-one="myForm1" form-two="myForm2">
<form name="myForm" submit="appController.submit()">
Search:<br />
<input type="text" ng-model="appController.searchText" />
</form>
</toolbar>
note that both name
attributes point at the same string "myForm"
. form-one
and form-two
are normal two way bindings that can be bound to your scope properties of choosing, in my example, myForm1
and myForm2
.
JS:
the two way binding definitions
scope: {
formOne: '=',
formTwo: '='
},
and binding the two new forms to respective scope attributes:
link: function (scope, element, attrs, controller, transclude) {
var parent = scope;
transclude(function(clone, scope) {
element.find('[transclude-main]').replaceWith(clone);
var unwatch = scope.$watch(attrs.name, function(form) {
if (form) {
parent.formOne = form;
unwatch();
}
});
});
transclude(function(clone, scope) {
element.find('[transclude-overflow]').replaceWith(clone);
var unwatch = scope.$watch(attrs.name, function(form) {
if (form) {
parent.formTwo = form;
unwatch();
}
});
});
Looking back at your code, this console console.log("myForm", $scope.myForm2)
printed undefined
because angular form
directives are not dynamic. As a result, manually finding the html element and changing the name from myForm
to myForm2
will not change the name of the form bound to scope unless the html has yet to be compiled. But the clone passed to transclude has been freshly compiled.
来源:https://stackoverflow.com/questions/38249445/transclude-function-needs-to-modify-clone-properly