动作方法执行顺序

时间:2017-03-24 00:48:33

标签: javascript c# jquery asp.net-mvc model-view-controller

我在这里遇到了一个非常奇怪的情况。解释起来很复杂,但我会尽我所能。

我有一个顶部有4个导航<a>按钮的用户界面 - 中间位置总是一个表单 - 而在底部我有以前的&amp;下一步按钮。

enter image description here

使用Ajax.BeginForm

在MVC中构建表单

对于顶部的每个导航链接<a>元素,我有一个JavaScript函数

var LoadTabs = function (e, arg) {  
    // This is to validate a form if one of the top links is clicked and form has incomplete fields...
    if (arg !== "prev" && arg !== "next") {
        if (!window.ValidateForm(false)) return false;
    }

    var url = $(this).attr('data'); // this contains link to a GET action method
    if (typeof url != "undefined") {
        $.ajax(url, { context: { param: arg } }).done(function (data) {                
            $('#partialViewContainer').html(data);
        });
    }
}

上面的这个函数绑定到页面加载的每个顶部链接。

$('.navLinks').on('click', LoadTabs);

我的下一个&amp;以前的按钮基本上会触发点击事件,即LoadTabs功能。

$('button').on('click', function () { 
        if (this.id === "btnMoveToNextTab") {
            if (!window.ValidateForm(true)) return false;                

            $.ajax({
                url: url,
                context: { param: 'next' },
                method: "GET",
                data: data,
                success: function(response) {
                    if (typeof response == 'object') {
                        if (response.moveAhead) {
                            MoveNext();
                        }
                    } else {
                        $('#mainView').html(response);
                    }
                    ScrollUp(0);
                }
            });
        } 

        if (this.id === "btnMoveToPreviousTab") {
            MoveBack();
        }
        return false;
    });


MoveNext() Implementation is as below:

function MoveNext() {        
    var listItem = $('#progressbarInd > .active').next('li');        

    listItem.find('.navLink').trigger('click', ['next']);
    ScrollUp(0);
}

问题是,由于某些原因,导航链接3处于活动状态并且我点击了NEXT按钮 - 而不是首先通过form.submit()发布表单 - 导航4被触发 - 因此导航4的GET运行之前表格导航3.

我的ValidateForm方法基本上只是检查表单是否存在且有效然后是Submit,否则返回false。它如下:

function ValidateForm(submit) {

    var form = $('form');

    // if form doesn't exist on the page - return true and continue
    if (typeof form[0] === "undefined") return true;

    // now check for any validation errors
    if (submit) {
        if (!$(form).valid()) {                
            return false;
        } else {
            $(form).submit();
        }
    } 
    else {
        return true;
    }

    return true;
}

我猜测form.submit确实会被触发,但由于提交需要更长的时间才能完成,因此继续使用按钮onclick事件中的下一个代码块。

我首先认为这是C#问题,因为在POST中我用一些循环保存了大量数据,并且任何代码块处理繁重我都有

var saveTask =  Task.Factory.StartNew(() => ControllerHelper.SomeMethod(db, model));
Task.WaitAll(saveTask);

WaitAll将等待并暂停执行,直到SomeMethod完成执行。我不知道如何在javascript中锁定进程并等待它完成执行。因为我认为如果我可以以某种方式锁定ValidateForm中的form.submit()直到它完成处理..通过回调方法也许...

如果有人能指引我正确的方向,我非常感谢你的帮助。如果您需要更多信息,请告诉我,我很乐意提供!

2 个答案:

答案 0 :(得分:2)

我发布这是对Alan的说明,因为它是多行代码,我无法在评论中使其可读。为了避免在有时运行异步操作时出现反模式,有时候不能使用,我可以使用:

function ValidateForm(){
    // do your logic
    if (pass) {
        return $.post("urlToPost");
    else {
        return $.Deferred().reject(xxx).promise();
    }
}

这样,你总是会回复一个承诺。在一个案例中,承诺来自$.ajax()。在另一种情况下,由于操作已经失败,您只是返回被拒绝的承诺。

答案 1 :(得分:1)

编辑关于返回承诺反模式

作为jfriend00评论原始答案回归的方式是承诺是反模式,更好的方法是:

function ValidateForm(){
    // do your logic
    if (pass) {
        return $.post("urlToPost");
    else {
        return $.Deferred().reject(xxx).promise();
    }
}

关于此的更多信息,结帐https://github.com/petkaantonov/bluebird/wiki/Promise-anti-patterns

原始答案

我会尝试描绘你的问题:

你想要的是首先运行ValidateForm,当它过去时(这样当表格发布完成时),然后执行MoveNext

问题是,MoveNextValidateForm完成之前被调用。

如果我是正确的,那么原因是因为Javascript本质上是异步编程,所以当事情发生时使用回调来触发。

所以在你的情况下,你需要使用诺言来实现它。

essentialy你需要做的是:

  1. ValiateForm返回承诺
  2. 仅在MoveNext完成后才执行ValidateForm
  3. 所以代码就像:

    function ValiateForm(){
        var dfd = jQuery.Deferred();
    
        // do your logic
        if(pass){
            $.post("urlToPost"
        } else {
            // also failed
            dfd.reject();
        }
    
        // return the promise
        return dfd.promise();
    }
    

    然后您的移动下一个按钮就像

    $('button').on('click', function () { 
            if (this.id === "btnMoveToNextTab") {
    
                $.when(window.ValidateForm(true)).then(function(){
                // after success post form
                $.ajax({
                            url: url,
                            context: { param: 'next' },
                            method: "GET",
                            data: data,
                            success: function(response) {
                                if (typeof response == 'object') {
                                    if (response.moveAhead) {
                                        MoveNext();
                                    }
                                } else {
                                    $('#mainView').html(response);
                                }
                                ScrollUp(0);
                            }
                        });
                if (this.id === "btnMoveToPreviousTab") {
                    MoveBack();
                }
            } 
            return false;
            });                
    
    
    });
    

    有关承诺结帐的更多信息

    https://api.jquery.com/deferred.promise/

    完成后运行

    https://api.jquery.com/deferred.then/