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

时间:2014-04-03 10:47:03

标签: angularjs angularjs-directive angularjs-scope angular-ui angular-ui-bootstrap

我有一个简单的案例:

<div ng-controller="myController">
  <tabset>
    <tab>
      <form name="myForm"></form>
    </tab>
  </tabset>
</div>

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

$scope.myForm.$setPristine()

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

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

ng-init="$parent.saataaTable = this"

但它远非完美。

2 个答案:

答案 0 :(得分:4)

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

解决方案1:隔离范围

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

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

解决方案2:子范围

这是您设置scope: truetransclude: 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来演示代码here,但请注意,这是一个演示,因此并非所有最佳做法都牢记在心。

修改

我发现重要的是要注意,如果您不想担心嵌套指令的范围,您只需在示波器上查看表单名称并处理其中的内容。

$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
  }
}

答案 1 :(得分:1)

我无法使用上面的答案使其工作,但我找到了解决办法。

在表单中,我创建了一个隐藏的输入字段,其中包含ng-model和ng-init,用于将其值设置为表单。然后在控制器中的提交函数中,我可以通过此ng-model

访问formController

因此,在HTML中,我在表单中创建一个隐藏字段:

<input id="test" ng-model="data.myForm" ng-init="data.myForm=myForm" hidden>

在Controller中,我可以通过data.myForm

获取formController
$scope.data.myForm.$setPristine();

它可能不是很好,所以我将避免依赖formController的$ pristine和$ dirty属性,并找到另一种方法来检测表单是否已更改(使用对象的主副本,如它们在文档中的示例中做了)