包含指令和形式

Transclusion directives and form

我正在尝试创建一些指令来包装布局,以便我可以从该布局中抽象出来(据我所知,这是指令的主要目标之一)。

所以我想要的是这样的:

<dialog>
  <dialog-title></dialog-title>
  <dialog-body></dialog-body>
  <dialog-footer></dialog-footer>
</dialog>

我为此创建了 3 个简单的指令,看起来与此类似

app.directive('dialog', ()=>{
  return {
    template: '<div class="dialog" ng-transclude></div>',
    replace: true,
    transclude: true,
    restrict: 'E',
  }
})

然后我想确保在一个指令(对话框正文)中定义的模型在另一个指令(对话框页脚)中可见,因为我需要在该对话框上使用某种形式,并在页脚中需要一些可能被禁用的导航按钮不取决于该表格是否有效。

  <body ng-controller="MainCtrl">
    <p>age: {{age}}</p>
    <dialog>
      <p>age: {{age}}</p>
      <dialog-body>
        <form name="dialogForm">
          <p>age: {{age}}</p>
          <input ng-model="age" minlength="3"/>
        </form>
      </dialog-body>
      <dialog-footer>
        <p>age: {{age}}</p>
      </dialog-footer>
    </dialog>
  </body>

ng-model in dialog-body 将在对话框主体的范围内创建年龄变量,但它不会出现在其他指令中,直到我将其放入对象并在 MainCtrl 中声明。它是这样工作的:

  <body ng-controller="MainCtrl">
    <p>age: {{user.age}}</p>
    <dialog>
      <p>age: {{user.age}}</p>
      <dialog-body>
        <form name="dialogForm">
          <p>age: {{user.age}}</p>
          <input ng-model="user.age" minlength="3"/>
        </form>
      </dialog-body>
      <dialog-footer>
        <p>age: {{user.age}}</p>
      </dialog-footer>
    </dialog>
  </body>

和控制器:

app.controller('MainCtrl', function($scope) {
  $scope.user = {age: 1}
})

现在,我想在 dialog-body 中放置一个表格。这应该在对话框主体的范围内创建 FormController,就像 ng-model 所做的那样(或者这里有一些区别?)。我需要从对话框页脚访问它以检查表单有效性。

所以在模板中创建表单后,我需要在 MainCtrl 的范围内定义 formController,这是第一个问题 - 如何创建 FormController 的实例?我认为 $scope.dialogForm = {$valid: true} 应该用于测试目的,这是我的最终模板:

  <body ng-controller="MainCtrl">
    <p>age: {{user.age}}</p>
    <p>validity: {{dialogForm.$valid}}</p>
    <dialog>
      <p>age: {{user.age}}</p>
      <p>validity: {{dialogForm.$valid}}</p>
      <dialog-body>
        <form name="dialogForm">
          <p>age: {{user.age}}</p>
          <p>validity: {{dialogForm.$valid}}</p>
          <input ng-model="user.age" minlength="3"/>
        </form>
      </dialog-body>
      <dialog-footer>
        <p>age: {{user.age}}</p>
        <p>validity: {{dialogForm.$valid}}</p>
      </dialog-footer>
    </dialog>
  </body>

主要问题来了。当 dialog-body 中的表单有效性发生变化时,它不会反映在其他指令中。为什么?我在这里错过了什么?

我的主要目标是为应用程序中最常用的组件提供指令,以便我从实际布局中抽象出来 - 这可以用不同的方式完成吗?

这是plunk

When form validity changes in dialog-body it does not reflect in other directives. Why?

在您的指令中 transclude: true 将创建一个新范围并从父级 scope 继承,在本例中是 MainCtrl 的范围。据我所知,当你声明 <form name="dialogForm"> 时,angular 会将 formController 绑定到 dialogBody 的嵌入范围,即对于 dialogBody 它将执行 $scope.dialogForm = formController并且因为它是一个新范围,其他嵌入的范围将不会看到此更改。

要解决此问题,您可以在父作用域中声明共享变量或使用本质上相同的 controller as 语法。

<body ng-controller="MainCtrl as vm">

然后将表单绑定到vm

    <form name="vm.dialogForm">
      <p>age: {{vm.user.age}}</p>
      <p>validity: {{vm.dialogForm.$valid}}</p>
      <input ng-model="vm.user.age" minlength="3"/>
    </form>

plunker

为什么这行得通?因为所有新的嵌入范围都从父范围继承 vm 并且 formController vm.dialogForm 绑定到这个公共变量所以所有嵌入的范围都会看到这个变化。