繁体   English   中英

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

[英]AngularJS with Ajax Form submission needing to click twice

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

  1. 用户输入电子邮件和密码进行注册
  2. 当用户单击“ Submit时,表单将发送到Controller
  3. Control使用AJAX为RESTful Server创建JSON请求,服务器也会相应地做出响应。
  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>

任何想法如何只在一个“提交”点击中完成所有这些活动?

只需执行此操作:在控制器中注入$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
    });
};

你的实际问题是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()。

暂无
暂无

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

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