【问题标题】:AngularJS with Ajax Form submission needing to click twice带有 Ajax 表单提交的 AngularJS 需要单击两次
【发布时间】:2016-02-21 23:55:27
【问题描述】:

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

  1. 用户输入邮箱和密码进行注册
  2. 当用户点击Submit时,表单被发送到控制器
  3. Control 使用 AJAX 创建对 RESTful 服务器和 服务器做出相应的响应。
  4. 根据服务器的响应,用户应该得到警报窗口,并且 打印在当前页面 (register.html) “提交”下方的消息。 如果是“成功 - 已注册”或“失败 - 无法 注册”。

但是,目前它的工作方式如下:1)、2)、3) 按预期工作。

  1. 用户在首次单击Submit 时会收到带有相应消息的警报窗口。

  2. 用户仅在单击Submit再次时才会打印消息,但再次显示警报窗口。

如果我从 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>

知道如何只需单击“提交”即可完成所有这些活动吗?

【问题讨论】:

  • 试试ng-show=showme,而不是ng-show=msgalert
  • 另外,你为什么调用 Angular 的 $http 函数,却使用 jQuery 的 ajax 函数?一般来说,你会希望create a service 有角度并在你的控制器中调用 that
  • 是的,乔纳森,你是对的,我同意这一点。我的错。

标签: javascript jquery html angularjs ajax


【解决方案1】:

只需这样做:在您的控制器中注入 $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 中的值已更改

或者,您可以在if-else 条件之后编写$scope.$apply(),但有时它会抛出异常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
    });
};

【讨论】:

  • 太棒了!这绝对有效。我读过关于 http 的信息,但由于某种原因它给了我错误。既然知道了消息摘要的概念,我再来实现。谢谢!
  • 很高兴这有助于您理解这一点:-)
  • 当我尝试实现 $http 时,就像你提到的那样,它给了我这个错误SyntaxError: Unexpected token e at Object.parse (native)
【解决方案2】:

您的实际问题是 jquery AJAX 的使用。通常,当 angular $http 进行 AJAX 调用时,它会在找到 ajax 响应时在内部调用 scope.digest 循环。但是在这里你调用 jquery ajax,所以 angular 无法消化更改,所以绑定不起作用。

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

$scope.$apply();

如下

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()。

【讨论】:

    猜你喜欢
    • 2014-12-03
    • 2021-10-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-17
    • 2013-12-28
    相关资源
    最近更新 更多