简体   繁体   English

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

[英]AngularJS modal dialog form object is undefined in controller

We have a page that opens a modal dialog with a form like below. 我们有一个页面打开一个模式对话框,其形式如下所示。 However when we hit the controller that should handle the form action, the form object is undefined and I am too much of an Angular newbie to understand why... 然而,当我们点击应该处理表单操作的控制器时,表单对象是未定义的,我太过一个Angular新手了解为什么......

This is the parent page controller holds the function to open the modal dialog: 这是父页面控制器保存打开模态对话框的功能:

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;
          }
          }
        }
      );
    };

on a page like this: 在这样的页面上:

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

the invitation-dialog html looks like this: 邀请对话框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>

The controller that should handle the invitation is somewhere else: 应该处理邀请的控制器在其他地方:

  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...

    };
  }]);

So what's the correct way to get the form scope into the controller? 那么将表单范围放入控制器的正确方法是什么?

Maybe I need to inject $modal into the sendInvitationController and add the sendInvitation function to it? 也许我需要将$modal注入sendInvitationController并向其添加sendInvitation函数? But when I do that the action never enters the controller. 但是当我这样做时,动作永远不会进入控制器。 Or do I have to add the function that handles the submit action to $modal.open({ ... instead of referencing the controller? Though I'd much prefer to have the sendInvitationController in its own file and scope. 或者我是否必须将处理提交操作的函数添加到$modal.open({ ...而不是引用控制器?虽然我更喜欢在自己的文件和范围中使用sendInvitationController。

Thanks for any help! 谢谢你的帮助!

EDIT 编辑

We found several things that helped us build a workaround and might help someone answer the question itself: 我们发现了一些帮助我们构建变通方法的东西,可能有助于某人自己回答问题:

  1. the $scope.invitation object is not undefined in the sendInvitationController but holds the correct data, while $scope.invitationForm remains undefined. $scope.invitation对象在sendInvitationController未定义,但保存正确的数据,而$scope.invitationForm仍未定义。
  2. inside the send-invitation.html we can access $scope.invitationForm.$invalid and do the validation right there: <button type="button" ng-click="sendInvitation()" ng-disabled="invitationForm.$invalid">Invite</button> 在send-invitation.html中我们可以访问$scope.invitationForm.$invalid并在那里进行验证: <button type="button" ng-click="sendInvitation()" ng-disabled="invitationForm.$invalid">Invite</button>

So the question is: why does the binding of the invitationForm object to the $scope fail on submit while the form model binds correcetly? 所以,问题是:为什么的结合invitationForm对象到$scope ,而表单模型结合correcetly失败上提交?

I had the same issue and could solve it by defining the form object in the scope of the modals controller. 我有同样的问题,可以通过在模态控制器范围内定义表单对象来解决它。 To get your code working put, for example, $scope.form = {}; 为了让你的代码工作,例如, $scope.form = {}; in the beginning of your controller and change your form tag to <form name="form.invitation"> . 在控制器的开头,将表单标签更改为<form name="form.invitation"> Afterwards $scope.form.invitation.$invalid should be filled. 之后$scope.form.invitation.$invalid应该被填充。

Update Nov 2014 : starting from angular-ui-bootstrap 0.12.0 transclusion scope is merged with the controller's scope. 2014年11月更新 :从angular-ui-bootstrap开始, 0.12.0范围与控制器的范围合并。 There is no need to do anything. 没有必要做任何事情。

Before 0.12.0 : 在0.12.0之前

To put invitationForm directly in your parent controller scope you need to bypass transcluded scope this way: 要将invitationForm直接放在父控制器范围中,您需要以这种方式绕过transcluded范围:

<form name="$parent.invitationForm">

Above will automaticaly create form object in your parent controller. 上面将自动在父控制器中创建表单对象。 No need for pre-initialization stuff, long object paths or passing by event. 无需预先初始化的东西,长对象路径或通过事件传递。 Just access it with $scope.invitationForm once modal is opened. 只需在打开模态后使用$scope.invitationForm访问它。

The answer to the question of "Why?" “为什么?”这个问题的答案。 is "scoping". 是“范围”。 tl;dr you created a new scope with the modal dialog which hid the scope's form object from your controller. tl; dr你用模态对话框创建了一个新的作用域,该对话框隐藏了控制器中作用域的表单对象。

If we simplify your code, we roughly get the following: 如果我们简化您的代码,我们大致得到以下内容:

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

(This is a very simplified version which should still have all of the core components.) Now, let's look at where scopes are created and what is injected in them. (这是一个非常简化的版本, 应该仍然包含所有核心组件。)现在,让我们看一下范围的创建位置以及注入的范围。

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

Here, you can see that there is a new child scope created at the <modal-dialog> element and that is where the invitationForm object is actually added. 在这里,您可以看到在<modal-dialog>元素中创建了一个新的子作用域, 是实际添加了invitationForm对象的位置。 That is why you can't see the object in the sendInvitationController but you can see it on the buttons for ng-disabled . 这就是为什么你不能在sendInvitationController看到对象但你可以在ng-disabled的按钮上看到它。 If you want to be able to access the form construct outside of the <modal-dialog> element (eg in the sendInvitationController ) you will need to pass that in the function call: 如果您希望能够访问<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>

With the controller accepting the invitation form as a parameter to the sendInvitation function: 控制器接受邀请表作为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 identified the other solution, specifically to create an object rooted in the scope of the sendInvitationController and then attach the form directly to that object, relying on Angular's scope traversal mechanism to find the form object on the scope outside of the <modal-dialog> and attach the form object to that. @Robin确定了另一个解决方案,特别是创建一个以sendInvitationController范围为根的对象,然后将表单直接附加到该对象,依靠Angular的范围遍历机制在<modal-dialog>之外的范围内查找form对象<modal-dialog>并将表单对象附加到该表单。 Note that if you did not specify $scope.form = {} in the sendInvitationController , Angular would have created a new object for form on the scope for the <modal-dialog> and you still would not have been able to access it in the sendInvitationController . 请注意,如果您没有在sendInvitationController指定$scope.form = {} ,Angular会在<modal-dialog>的作用域上为form创建一个新对象,但您仍然无法在sendInvitationController

Hopefully this helps you or other people learning about Angular scoping. 希望这有助于您或其他人了解Angular范围。

I got mine to work like this: 我让我这样工作:

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

No form name, no $parent . 没有表格名称,没有$parent I'm using AngularUI Bootstrap version 0.12.1. 我正在使用AngularUI Bootstrap版本0.12.1。

I was tipped off to this solution by this . 我通风报信该解决方案通过

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

            })

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM