52

我们有一个页面,它打开一个带有如下表单的模式对话框。然而,当我们点击应该处理表单动作的控制器时,表单对象是未定义的,我是一个 Angular 新手,无法理解为什么......

这是父页面控制器拥有打开模态对话框的功能:

app.controller('organisationStructureController', ['$scope', ..., '$modal', function ($scope, ..., $modal) {

    $scope.openInvitationDialog = function (targetOrganisationId) {
      $modal.open({
          templateUrl: 'send-invitation.html',
          controller: 'sendInvitationController',
          resolve: {$targetOrganisationId: function () {
            return targetOrganisationId;
          }
          }
        }
      );
    };

在这样的页面上:

// inside a loop over organisations
<a ng-click="openInvitationDialog({{organisation.id}})">Invite new member</a>

邀请对话框 html 如下所示:

    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <!-- ... -->
            </div>
            <div class="modal-body">
                <form name="invitationForm">

                    <div class="form-group">
                        <label for="email" style="color:white;">Email</label>
                        <input type="email" class="form-control"  autocomplete="off" placeholder="New member email" id="email" name="email" ng-model="invitation.email" required="true"/>
                        <span class="error animated fadeIn" ng-show="invitationForm.email.$dirty && invitationForm.email.$error.required">Please enter an email address!</span>
                        <span class="error animated fadeIn" ng-show="invitationForm.email.$error.email">Invalid email</span>
                    </div>

                    <!-- ... -->

                    <div class="modal-footer">
                        <button type="button" class="btn btn-default" ng-click="cancel()">Cancel</button>
                        <button type="submit" class="btn btn-primary" ng-click="sendInvitation()">Invite</button>
                    </div>
                </form>
            </div>
        </div>
    </div>

应该处理邀请的控制器在其他地方:

  app.controller('sendInvitationController', ['$targetOrganisationId', '$scope', ...,
    function ($targetOrganisationId, $scope, ...) {

    $scope.invitation = {
      // ...
      targetOrganisation: {
        id: $targetOrganisationId
      }
    };

    $scope.sendInvitation = function () {

      // $scope.invitationForm is undefined
      if ($scope.invitationForm.$invalid) {
        return false;
      }

      // send the invitation...

    };
  }]);

那么将表单范围放入控制器的正确方法是什么?

也许我需要注入$modalsendInvitationController添加sendInvitation功能?但是当我这样做时,动作永远不会进入控制器。或者我是否必须添加处理提交操作的函数$modal.open({ ...而不是引用控制器?虽然我更喜欢将 sendInvitationController 放在自己的文件和范围中。

谢谢你的帮助!

编辑

我们发现了几件事可以帮助我们构建解决方法,并且可能会帮助某人回答问题本身:

  1. $scope.invitation对象不是未定义的,sendInvitationController但包含正确的数据,同时$scope.invitationForm保持未定义。
  2. 在 send-invitation.html 中,我们可以访问$scope.invitationForm.$invalid并在那里进行验证:<button type="button" ng-click="sendInvitation()" ng-disabled="invitationForm.$invalid">Invite</button>

所以问题是:为什么当表单模型正确绑定时invitationForm对象绑定到$scope提交失败?

4

5 回答 5

78

我有同样的问题,可以通过在模态控制器范围内定义表单对象来解决它。让你的代码工作,例如,$scope.form = {};在你的控制器的开头,并将你的表单标签更改为<form name="form.invitation">. 之后$scope.form.invitation.$invalid应该填写。

于 2013-11-12T14:02:09.223 回答
39

2014 年 11 月更新:从 angular-ui-bootstrap嵌入范围开始0.12.0与控制器的范围合并。没有必要做任何事情。

在 0.12.0 之前

invitationForm直接放入您的父控制器范围,您需要以这种方式绕过嵌入范围:

<form name="$parent.invitationForm">

以上将自动在您的父控制器中创建表单对象。不需要预初始化的东西、长的对象路径或按事件传递。只需$scope.invitationForm打开模式即可访问它。

于 2014-05-29T21:24:41.483 回答
19

“为什么?”这个问题的答案 是“范围”。tl; dr您使用模态对话框创建了一个新范围,该对话框从您的控制器中隐藏了范围的表单对象。

如果我们简化您的代码,我们大致得到以下信息:

<div ng-ctrl="organizeCtrl">
  <modal-dialog>
    <form name="invitationForm">
      <input type="email" ng-model="invitation.email" placeholder="Enter email..." />
      <input type="submit" ng-click="sendInvitation()" text="Invite!" />
      <input type="button" ng-click="cancel()" text="Cancel  :(" />
    </form>
  </modal-dialog>
</div>

(这是一个非常简化的版本,它仍然应该包含所有核心组件。)现在,让我们看看作用域是在哪里创建的以及在其中注入了什么。

<div ng-ctrl="sendInvitationController">
<!-- scope created above with "invitation" and "sendInvitation" from sendInvitationController -->
  <modal-dialog>
  <!-- scope created above for the modal dialog transclude -->
    <form name="invitationForm">
    <!-- add "invitationForm" to the modal dialog's scope -->
      <input type="email" ng-model="invitation.email" placeholder="Enter email..." />
      <input type="submit" ng-click="sendInvitation()" text="Invite!" />
      <input type="button" ng-click="cancel()" text="Cancel  :(" />
    </form>
  </modal-dialog>
</div>

在这里,您可以看到在<modal-dialog>元素处创建了一个新的子范围,就是invitationForm实际添加对象的位置。这就是为什么您在 中看不到该对象,sendInvitationController但您可以在 的按钮上看到它ng-disabled。如果您希望能够访问<modal-dialog>元素外部的表单构造(例如在 中sendInvitationController),您需要在函数调用中传递它:

<div ng-ctrl="organizeCtrl">
  <modal-dialog>
    <form name="invitationForm">
      <input type="email" ng-model="invitation.email" placeholder="Enter email..." />
      <input type="submit" ng-click="sendInvitation(invitationForm)" text="Invite!" />
      <input type="button" ng-click="cancel()" text="Cancel  :(" />
    </form>
  </modal-dialog>
</div>

控制器接受邀请表单作为sendInvitation函数的参数:

app.controller('sendInvitationController', ['$targetOrganisationId', '$scope', ...,
  function ($targetOrganisationId, $scope, ...) {
  $scope.invitation = {
    targetOrganisation: {
      id: $targetOrganisationId
    }
  };
  $scope.sendInvitation = function (form) {
    if (form.$invalid) {
      return false;
    }
    // send the invitation...
  };
}]);

@Robin 确定了另一种解决方案,专门创建一个植根于范围的对象sendInvitationController,然后将表单直接附加到该对象,依靠 Angular 的范围遍历机制form在范围之外找到对象<modal-dialog>并将表单对象附加到那。请注意,如果您没有$scope.form = {}在.sendInvitationControllerform<modal-dialog>sendInvitationController

希望这可以帮助您或其他人了解 Angular 范围。

于 2014-02-04T17:50:01.100 回答
2

我让我的工作是这样的:

$modal.open({
  templateUrl: 'send-invitation.html',
  controller: 'sendInvitationController',
  scope: $scope // <-- I added this
}

没有表格名称,没有$parent。我正在使用 AngularUI Bootstrap 0.12.1 版。

我被告知这个解决方案

于 2015-05-02T14:53:09.347 回答
0
$mdDialog.show({
                locals: {alert:"display meassage"},
                controller: DialogController,
                templateUrl: 'views/dialog.html',
                parent: angular.element(document.body),
                clickOutsideToClose:true,
                backdrop: true,
                keyboard: true,
                backdropClick: true,

            })
于 2016-01-08T11:08:12.287 回答