AngularJS和Ajax表单提交需要点击两次的问题

3

我需要从我的HTML页面执行以下操作:

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

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

  1. 用户首次点击提交时会弹出警报窗口并显示适当的消息。

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

如果我从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=msgalert,而不是 ng-show=showme - jperezov
1
此外,为什么在Angular中调用$http函数,却使用jQuery的ajax函数?一般来说,在Angular中,您需要创建服务,并在控制器中调用它。 - jperezov
是的Jonathan,你说得对,我同意。我的错。 - AdityaHandadi
2个回答

4

只需要这样做:在控制器中注入$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会在幕后触发一个脏检查循环,然后显示你的实际消息,这就是你看到这种情况的原因。
为了解决这个问题,我们使用$timeout服务将你的自定义代码(在Angular上下文之外)包装到Angular的上下文中,以通知Angularmsgalert的值已经改变。
可选地,在你的if-else条件之后写$scope.$apply(),但有时会抛出异常,因为调用$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的内容,但由于某些原因它一直给我报错。现在我知道了消息摘要的概念,我会再次实现它。谢谢! - AdityaHandadi
很高兴能帮到你并且你理解了这个 :-) - Shashank Agrawal
当我尝试像你提到的那样实现$http时,它给了我这个错误SyntaxError: Unexpected token e at Object.parse (native) - AdityaHandadi

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接