AngularJS与Ajax表单提交需要单击两次

时间:2015-11-19 17:37:48

标签: javascript jquery html angularjs ajax

我需要从HTML页面执行以下活动:

  1. 用户输入电子邮件和密码进行注册
  2. 当用户点击Submit
  3. 时,表单会发送给Controller
  4. Control使用AJAX为RESTful Server创建JSON请求 服务器做出相应的响应。
  5. 根据服务器的响应,用户应该获得警报窗口,并且a 消息打印在当前页面(register.html)下面"提交"。 如果是成功 - 已注册"或者"失败 - 不能 寄存器"
  6. 但是,目前它的工作方式如下:1),2),3)按预期工作。

    1. 用户首先点击Submit并使用相应的消息获取提醒窗口。

    2. 用户仅在点击Submit 重新时才会显示消息,但再一次显示警告窗口。

    3. 如果我从JS中删除alert('Something'),我必须点击两次才能在register.html上打印消息

      此外,我想提醒您注意,单击两次也会使服务器调用两次。它的行为就好像它在服务器调用后暂停,然后打印我应该点击提交的消息。

      register.html

      <div class='container'>
          <div class='col-md-12'>
              <div class='fill' ng-controller="registerController">
                  <form name="userForm" ng-submit="submitForm(userForm.$valid,user)" novalidate>
                      <!-- ALL FORM ELEMENTS HERE -->
                      <button type="submit" class="btn btn-primary" ng-disabled="userForm.$invalid" ng-click="showme=true">
                          Submit
                      </button>
                      <div class="wrapper">
                          <h3 ng-show="showme"><em>{{msgalert}}</em></h3>
                      </div>
                  </form>
              </div>
          </div>
      </div>
      

      我的JS控制器看起来像这个stackoverflow_q3.js

      // create angular controller
      var register = angular.module('Main-app');
      register.controller('registerController', function ($scope, $http, $location) {
      
          // function to submit the form after all validation has occurred            
          $scope.submitForm = function (isValid, user) {
              console.log('Stackoverflow JS func caled');
              var regData = {
                  "email": user.email,
                  "password": user.password1
              };
      
              var jsonData = JSON.stringify(regData);
              var request = $.ajax({
                  url: 'myurl',
                  type: 'POST',
                  data: jsonData,
                  headers: {
                      'Accept': 'application/json',
                      'Content-Type': 'application/json'
                  },
                  dataType: 'json',
                  complete: function (response) {
                      console.log(response.responseText);
                      if (response.responseText == 'success') {
                          console.log('Registration Success');
                          alert('Success');
                          $scope.msgalert = 'Registration Success, Proceed to Login and Continue';
                      } else if (response.responseText == 'fail') {
                          alert('registration failed');
                          $scope.msgalert = 'Registration Failed, Please try again';
                      }
                  }
              });
          };
      });
      

      同样在index.html我提到了控制器:

      <!-- HTML -->
      <!DOCTYPE html>
      <html ng-app="Main-app">
      <!--  Controllers  -->
      <script src="js/controllers/stackoverflow_q3.js" type="text/javascript"></script>
      
          <!-- Other elements -->
      
      </html>
      

      任何想法我怎样才能在一个&#34;提交&#34;点击?

2 个答案:

答案 0 :(得分:5)

只需执行此操作:在控制器中注入$timeout服务并将代码包装如下:

complete: function(response) {
    console.log(response.responseText);
    $timeout(function() {
        if (response.responseText == 'success') {
            console.log('Registration Success');
            alert('Success');
            $scope.msgalert = 'Registration Success, Proceed to Login and Continue';

        } else if (response.responseText == 'fail') {
            alert('registration failed');
            $scope.msgalert = 'Registration Failed, Please try again';
        }
    });
}

另外,请更改您的HTML代码:

<h3 ng-show="msgalert"><em>{{msgalert}}</em></h3>

因此Angular中有一个摘要周期的概念。如果你正在Angular的上下文之外做一些事情(就像你使用jQuery AJAX来获取数据并更新msgalert的$ scope变量),我们必须告诉Angular数据中的某些内容发生了变化。

因此,当您从服务器获得响应并更新msgalert后,Angular不知道该更改,因为它超出了Angular的上下文,因此触发了Angular的新摘要周期并且视图未更新

为什么你会看到这一点,当你在表单中再次点击提交按钮时,会在场景后面触发Angular的摘要周期,然后显示你的实际信息。

为了解决这个问题,我们使用$timeout服务将您的自定义(外部角度上下文)代码包装到Angular的上下文中,该服务立即通知Angular msgalert中的值已更改

或者,您可以在$scope.$apply()条件之后写if-else,但有时会digest cycle is already in progress抛出异常因为调用$scope.$apply(),我们会手动触发Angular的摘要周期。这就是为什么更清洁的方法是$timeout服务。

<强>更新

请注意,您根本不必使用jQuery来执行该AJAX调用。 Angular有$http服务并使用它你根本不会遇到这个问题。您可以像这样编写代码:

$scope.submitForm = function (isValid, user) {
    var regData = {
        email: user.email,
        password: user.password1
    };

    $http({
        method: "POST",
        url: "myurl",
        data: regData,          // You don't need to stringify it and no need to set any headers
    }).then(function (response) {
        // Success callback
        console.log(response.responseText);
        if (response.responseText == 'success') {
            $scope.msgalert = 'Registration Success, Proceed to Login and Continue';
        } else if (response.responseText == 'fail') {
            $scope.msgalert = 'Registration Failed, Please try again';
        }
    }, function() {
        // Error callback
    });
};

答案 1 :(得分:2)

您的实际问题是jquery AJAX用法。当使用angular $ http进行AJAX调用时,Normaly会在发现ajax响应时在内部调用scope.digest循环。但是你在这里调用jquery ajax,因此angular无法消化更改,因此绑定无效。

在完成方法完成之后尝试以下操作。

<强> $ $范围应用();

如下

complete: function(response) {
              console.log(response.responseText);
              if(response.responseText == 'success'){
                console.log('Registration Success');
                   alert('Success');
                   $scope.msgalert='Registration Success, Proceed to Login and Continue';

              }
              else if(response.responseText == 'fail'){
                alert('registration failed');
                $scope.msgalert='Registration Failed, Please try again';

              }
              $scope.$apply();
 }

但最好使用$ http ,因为它在内部调用$ scope。$ apply()。