我有一个简单的案例:
<div ng-controller="myController">
<tabset>
<tab>
<form name="myForm"></form>
</tab>
</tabset>
</div>
现在,在myController方法中,我想访问myForm来调用$setPristine:
$scope.myForm.$setPristine()
但我不能。 选项卡集/选项卡创建隔离/继承的范围。这只是一个示例,但是在使用多次创建隔离作用域的角度js指令时,我遇到了这个问题。
我怎样才能克服这个问题?过去我做了这样的事情(使用 ng-table 也创建新范围):
ng-init="$parent.saataaTable = this"
但它远非完美。
这是我最难理解的概念之一,我的解决方案很简单,但很难解释,所以请耐心等待。
解决方案 1:隔离作用域
当你只处理隔离作用域(scope: {...}
)或没有作用域(scope: false
)时,你很幸运,因为myForm最终会在那里。你只需要注意它。
$scope.$watch('myForm', function(val) {
if (myForm) {
// now I can call $setPristine
}
});
解决方案 2:子作用域
这是您设置scope: true
或transclude: true
时。除非您执行自定义/手动嵌入,否则您将不会在控制器的作用域上获得myForm
。
诀窍是直接从表单元素访问表单的控制器。这可以通过以下方法完成:
// at the form element
element.data('$formController');
// or at the control (input, select, etc.)
element.inheritedData('$formController');
// where 'element' is a jqLite element (form or ng-form)
这为您准备了一个新问题:我们如何知道何时以及如何获取该元素及其数据。
一个快速的答案是,您需要在控制器的示波器上设置一个虚拟$watch
来查找(在您的情况下)myForm
。处理此手表后,您将能够尝试找到表单。这是必要的,因为通常当控制器首次执行时,FormController
不会在元素的数据对象上。
查找表单的一种快速简单的方法是简单地获取所有表单。注意:如果元素中有多个表单,则必须添加一些逻辑才能找到正确的表单。在这种情况下,我们的表单是一个表单元素,它是唯一的一个。因此,定位它相当容易:
// assuming you have inject $element into your controller
$element.find('form').data('$formController');
// where $element is the root element the controller is attached to
// it is injected just like '$scope'
拥有控制器后,您可以访问正常使用的所有内容。同样重要的是要注意,一旦 FormController 位于元素上,解决方案 2 将始终有效。
我已经设置了一个 Plunk 来演示这里的代码,但请注意这是一个演示,所以并没有记住所有的最佳实践。
编辑
我发现重要的是要注意,如果您不想担心嵌套指令的作用域,您只需查看作用域上的表单名称并在那里处理事情。
$scope.$watch('myForm', function(val) {
if (angular.isDefined(val)) {
// now I have access
} else {
// see if i can `find` the form whose name is 'myForm'
// (this is easy if it is a form element and there's only one)
// then get the FormController for access
}
}
我无法使用上面的答案使其工作,但我找到了解决方法。
在表单中,我创建了一个隐藏的输入字段,其中包含一个ng-model和ng-init,将其值设置为表单。然后在控制器中的提交函数中,我可以通过这个 ng 模型访问表单控制器
因此,在HTML中,我在表单中创建了一个隐藏字段:
<input id="test" ng-model="data.myForm" ng-init="data.myForm=myForm" hidden>
在控制器中,我可以通过data.myForm获取formController。
$scope.data.myForm.$setPristine();
它可能不是很好,所以我将避免依赖formController的$pristine和$dirty属性,并找到另一种方法来检测表单是否已更改(使用对象的主副本,就像他们在文档中的示例中所做的那样)