AngularJS模态对话框表单对象在控制器中未定义

Posted

技术标签:

【中文标题】AngularJS模态对话框表单对象在控制器中未定义【英文标题】:AngularJS modal dialog form object is undefined in controller 【发布时间】:2013-10-19 05:26:21 【问题描述】:

我们有一个页面,它打开一个带有如下表单的模式对话框。然而,当我们点击应该处理表单动作的控制器时,表单对象是未定义的,我是一个 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...

    ;
  ]);

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

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

感谢您的帮助!

编辑

我们发现了一些有助于我们构建解决方法并可能帮助某人回答问题本身的东西:

    $scope.invitation 对象在 sendInvitationController 中未定义,但包含正确的数据,而 $scope.invitationForm 仍未定义。 在 send-invitation.html 中,我们可以访问 $scope.invitationForm.$invalid 并在那里进行验证:&lt;button type="button" ng-click="sendInvitation()" ng-disabled="invitationForm.$invalid"&gt;Invite&lt;/button&gt;

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

【问题讨论】:

我有类似的问题 - 问题是 $modal 在以这种方式创建模式时创建了两个范围 - 一个用于模式窗口目的,另一个是你的。尝试将点放在您的 ng-form 表达式中 - $scope.data = 然后 ng-form="data.invitationForm" 为什么不使用 $dialog 和 opt backdropClick: false, 感谢您的回答。 @4avanger:如果有两个不同的范围,为什么添加一些点符号会有所帮助?我试过了,但它只是导致数据未定义而不是邀请表。 @Maxim:我们正在使用 $modal。不知道$dialog是什么,可能是一样的吧? backdropCLick: false 是做什么的? @Pete 你能把你的代码(实际上,重现问题所需的一小部分)放在plnkr.co 中。我知道您的问题是什么,并且我在您的代码 sn-p 中看到了其他几个问题,但是如果没有实时代码示例,这有点难以解释。 从来没有用过 plunkr,但我可以试试。如果你能在周一回来看看就好了,因为我将在不到一个小时的时间内下班,因为接下来的周末很忙,但我不会不认为我会在那个时候让我的代码在 plunkr 上运行.. 【参考方案1】:

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

【讨论】:

这也对我有用。我意识到这是模态的范围问题,但是有没有更优雅/类似 Angular 的方式来处理这个问题? @ErikOlson $parent 范围是理想的,检查我的答案 这是 owsm 好友 :) 谢谢 :)。你能解释一下这里有什么问题吗:) 再次感谢【参考方案2】:

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

0.12.0之前

要将invitationForm 直接放在您的父控制器作用域中,您需要以这种方式绕过嵌入作用域:

<form name="$parent.invitationForm">

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

【讨论】:

目前唯一可行的解​​决方案(Angular 1.3)请投票! 我很高兴能吻你!你用这个超级简单的解决方案让我很开心! 再一次!非常感谢!! 在 angular 1.2.x 中效果很好 ui.bootstrap 0.12.0 带来了修复,不再需要使用$parent.【参考方案3】:

“为什么?”问题的答案是“范围”。 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>

在这里,您可以看到在&lt;modal-dialog&gt; 元素处创建了一个新的子作用域,而 是实际添加invitationForm 对象的位置。这就是为什么您在sendInvitationController 中看不到该对象,但您可以在ng-disabled 的按钮上看到它。如果您希望能够访问&lt;modal-dialog&gt; 元素之外的表单构造(例如在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 对象在&lt;modal-dialog&gt; 之外并将表单对象附加到该对象。请注意,如果您没有在sendInvitationController 中指定$scope.form = ,Angular 将在&lt;modal-dialog&gt; 的范围内为form 创建一个新对象,您仍然无法在@987654339 中访问它@。

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

【讨论】:

很好的解释!谢谢! 确实很好的解释!容易理解:) 这个解释在基于提交按钮点击的情况下很有用,需要在父范围内进行一些 DOM 修改。【参考方案4】:

我的工作是这样的:

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

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

this 向我提示了这个解决方案。

【讨论】:

【参考方案5】:
$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,

            )

【讨论】:

以上是关于AngularJS模态对话框表单对象在控制器中未定义的主要内容,如果未能解决你的问题,请参考以下文章

带有 AngularJs 的 Ionic 框架:模态是不是可以与启动模态的视图具有相同的控制器?

AngularJS进阶(三十一)AngularJS项目开发技巧之获取模态对话框中的组件ID

从 angularjs 模态对话服务返回数据

在模态对话框中显示部分视图结果

带有 Jquery 模态形式的 asp.net MVC

您可以在 jquery 模态对话框中提交表单吗