由于角度ui tab隔离/继承范围,访问表单控制器隐藏

dra*_*fly 8 angularjs angular-ui angularjs-directive angularjs-scope angular-ui-bootstrap

我有一个简单的案例:

<div ng-controller="myController">
  <tabset>
    <tab>
      <form name="myForm"></form>
    </tab>
  </tabset>
</div>
Run Code Online (Sandbox Code Playgroud)

现在,在myController方法中,我想访问myForm来调用$ setPristine:

$scope.myForm.$setPristine()
Run Code Online (Sandbox Code Playgroud)

但是我不能.tabset/tab创建隔离/继承范围.这只是一个示例,但是当使用多次创建隔离范围的angular js指令时,我遇到了这个问题.

我该如何克服这个问题?在过去我做了类似的事情(使用ng-table也创建了新的范围):

ng-init="$parent.saataaTable = this"
Run Code Online (Sandbox Code Playgroud)

但它远非完美.

Ste*_*ker 4

这是我最难理解的概念之一,我的解决方案很简单,但有点难以解释,所以请耐心等待。

解决方案 1:隔离范围

当您只处理隔离范围 ( scope: {...}) 或不处理范围 ( scope: false) 时,您很幸运,因为 myForm 最终会在那里。你只需要留意它。

$scope.$watch('myForm', function(val) {
  if (myForm) {
    // now I can call $setPristine
  }
});
Run Code Online (Sandbox Code Playgroud)

解决方案 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)
Run Code Online (Sandbox Code Playgroud)

这为您带来了一个新问题:我们如何知道何时以及如何获取该元素及其数据。

一个简单的答案是,您需要在控制器的范围上设置一个虚拟对象$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'
Run Code Online (Sandbox Code Playgroud)

拥有控制器后,您就可以访问通常会访问的所有内容。同样重要的是要注意,一旦 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
  }
}
Run Code Online (Sandbox Code Playgroud)