I originally asked this question here, but I think I got ahead of myself and made it more complicated than it really is, so I\'m re-asking it here with a bit clearer wording.
Angular comes out of the box with an improve tag that is documented here. Basically it creates a scope in the form of a controller around the form and all of the tags within it. So you do this:
JS:
var app = angular.app('TestApp', []);
app.controller('FormCtrl', function($scope) {
$scope.submit = function() {
// Form submit logic here
console.log("Submitting the form");
console.log($scope);
}
})
This creates a scope for the form, since the form tag contains the ng-controller tag. Within the scope, testForm
is the javascript object for the form, and testForm.firstInput
is the javascript object for the first input. It looks like these objects also have some validation functionality available, see docs here.
The data on the form will be available as an object data in the FormCtrl scope, with keys "first" and "second", and you can define methods in the controller that work on that.
You can also put multiple forms using the same FormCtrl, and it seems like Angular will create new instances for each form, so you don't have to worry about forms polluting each other's data.
Now lets suppose that we have some sort of complex input or widget that is implemented in a directive. This example uses two select boxes to display all cities in a state. You have to first select a state, then it'll query for the cities in that state and populate the second select box.
app.directive('citySelect', function() {
return {
replace: true,
template: '' +
'',
controller: function($scope) {
// Omitting the logic for getCities(), but it'd go here
}
};
})
Then you can just stick it into the form tag, and it'll work. Because the directive doesn't define a scope, it'll just attach to the scope of the FormCtrl.
Paramaterizing the directives
EDIT:
So apparently this does work:
scope: {someParameter: "="},
template: ''
You simply do it without the curlies, and it'll bind. My guess is that the parent scope is binding to someParameter in the child scope, and the select is then binding to somParameter in the child scope.
So all of this below about manually compiling in the link function is not necessary.
=====
But the problem with this is that my citySelect directive has a hard coded ng-model binding, so if I created some sort of generic widget, I couldn't use more than one of it in a form. Unfortunately this does not seem to work:
scope: {someParameter: "="},
template: ''
The only way that I have gotten this to work is to build the DOM element manually in a linking function, but I'm not sure if this is advisable. I would appreciate comments from anyone about this implementation:
app.directive('citySelect', function($compile) {
return {
replace: true,
template: '',
controller: function($scope) {
// Omitting the logic for getCities(), but it'd go here
}
link: function(scope, iElem, iAttrs) {
var html = '';
iElem.replaceWith($compile(html)(scope));
}
};
})
Mixing in parameters on the form
Since separate instances of FormCtrl are created for each form, you can reuse a lot of the functionality in FormCtrl. But you can also use additional directives on a form tag to add parameters or break apart functionality. For example:
The form's scope will then combine the scope from FormCtrl and postForm, so that everything is accessible. In my experimentation, it seems like the FormCtrl takes precedence, so if something like $scope.submit() is defined in both FormCtrl and postForm, FormCtrl's will take precedence (I think), maybe this is a race condition from asynchronous loading, I don't know.
Instead of using ng-controller, I think you can also use scope:true
on the mixin directive (postForm), or perhaps more safely, scope: {}
.
讨论(0)