AngularJS使用Ajax表单提交需要点击两次两次、表单、AngularJS、Ajax

2023-09-11 01:20:56 作者:有点上瘾

我需要从我的HTML页面做了以下活动:

I am needing to do the following activities from my HTML page:

在用户输入电子邮件地址和密码来注册 在表单发送到控制器的时候,用户点击提交 在控制使用AJAX来创建JSON请求到REST风格的服务器和 服务器相应地响应。 根据服务器的响应,用户应该得到警报窗口,和 消息打印下面的提交当前页面( register.html )上。 如果它是一个成功 - 注册或失败 - 无法 注册。 User enters email and password to register Form is sent to Controller when user clicks Submit Control uses AJAX to create JSON request to RESTful Server and the server responds accordingly. According to Server's response, User should get alert window, and a message printed on the current page (register.html) below "Submit". If it is a "Success - Registered " or "Failed - Could not register".

不过,目前它正在是这样的:1),2),3)按预期工作

But, currently it is working like this: 1), 2), 3) working as expected.

用户得到第一次点击提示窗口提交与相应的消息。

The user gets the alert window on first clicking Submit with the appropriate message.

用户得到印刷只在点击消息提交 AGAIN ,但再一次,这是显示警告窗口。

The user gets the message printed ONLY ON CLICKING Submit AGAIN, but once again, this is showing the alert window.

如果我删除警报('东西')从JS,我必须单击两次消息被打印在 register.html

If I remove alert('Something') from JS, I have to click twice for the message to print on the register.html

另外,我希望把它带到你的注意,点击两次,也使得服务器调用两次。它的行为就好像它已暂停服务器调用后,再打印消息我应该点击提交。

Also, I want to bring it to your attention that clicking twice is also making server call twice. It behaves as if it has paused after the server call, and then to print the message I am supposed to click on Submit.

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的我刚才提到的控制器:

Also in index.html I have mentioned the controller:

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

    <!-- Other elements -->

</html>

任何想法,我该怎么办只在一个提交,所有这些活动点击?

Any idea how can I do all these activities in just one "Submit" click?

推荐答案

只要做到这一点:注入 $超时服务,在您的控制器和包装你code如下

Just do this: Inject $timeout service in your controller and wrap your code as following:

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 code是这样的:

Also, change your HTML code like this:

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

因此​​,有消化周期的角度的概念。如果你正在做的事情的角度的范围之外(比如你正在使用jQuery AJAX来获取数据和更新 msgalert 在$范围变量),我们必须告诉角的东西在数据已经改变。

So there is a concept of digest cycle in Angular. If you are doing something outside the Angular's context (like you are using jQuery AJAX to get the data and updating the $scope variable of msgalert), we have to tell Angular that something has changed in the data.

因此​​,在你得到服务器的响应,你更新了 msgalert ,角是不知道的变化,因为它是角的范围内使新的消化周期之外角被触发,认为不会被更新。

So after you get the response from the server and you updated the msgalert, Angular is unaware of that change since it is outside of the Angular's context so new digest cycle of Angular is triggered and the view is not updated.

为什么你看到的这是,当你再次点击的形式提交按钮,然后折角的消化周期触发幕后,然后是越来越显示实际的消息。

Why you are seeing this is, when you click the submit button again in the form, then a digest cycle of Angular is triggered behind the scene and then your actual message is getting displayed.

要解决这个问题,我们包你的自定义(角范围之外)code到角的情况下使用 $超时服务,这是紧接该通知的角在 msgalert 的值更改

To fix the problem, we wrapped your custom (outside angular context) code into the Angular's context using the $timeout service which is notifying the Angular immediately that the value in msgalert has changed

另外,你可以写在 $范围。$适用()后,你的的if-else 的条件,但它有时抛出一个异常消化周期正在进行中,因为调用 $范围。$适用(),我们手动的触发角的消化周期。这就是为什么更简洁的方法是将 $超时服务。

Optionally, you can write the $scope.$apply() after your if-else condition but it throws an exception sometimes that digest cycle is already in progress because calling $scope.$apply(), we are manually triggering the Angular's digest cycle. That is why the cleaner approach is to the $timeout service.

更新

请注意,您不必使用jQuery都这样做AJAX调用。角有 $ HTTP 服务,并使用它,你不会面临这个问题都没有。你可以写你的code是这样的:

Please note that you don't have to use jQuery at all to do that AJAX call. Angular has $http service and using it you will not face that problem at all. You can write your code like this:

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