0

Hoping some of you may help me with this problem.

I have a few navigation link on top of my application which have active and not-active state. In theory, I want to jump from one to another and if there exists a form which isn't complete/valid, I trigger validation errors and stay on the same page. What is happening in my case is form validation works fine but navigation links on top change state from non-active to active, whichever was clicked.

I have a ValidateForm function that validates and submits the form if its is valid, else it returns deferred.reject();

function ValidateForm(submitAnyway) {
    var deferred = $.Deferred();
    var form = $('form');

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


    // now check for any validation errors
    if (submitAnyway) {
        if (!$(form).valid()) {                
            deferred.reject();
        } else {
            $(form).submit();
            deferred.resolve();
        }
    } else {
        deferred.resolve();
    }

    return deferred.promise();
}

I have a click event for those top navigation links as below:

var DonutsClickEvent = function (e, arg) {
    var url = $(this).attr('data');
    var data = { param: arg };

    if (typeof url === "undefined") return false;

    $.when(window.ValidateForm(false)).then(
        function () {
            LoadPartialView_Main(url, data);                
        },
        function(){
            return false; // I'm trying to return false here to stop event from continuing 
        }
    );  
    Console.log("This statement runs before $.when completes");
    // and event continues and the clicked nav button changes 
    // its state from non-active to active, even though form doesn't validate
}

I recently added $.Deferred functionality to my code due to some events firing with messed up sequence... Before my validateForm method would return true or false and based on that i'd continue executing event if true, if false i'd stop and it was all good.

Not sure what am I doing wrong here. I'd appreciate any kinda help.

Thanks!

Johny

Johny
  • 387
  • 1
  • 7
  • 20
  • As it turns out, nothing in your `ValidateForm()` function that actually tests the validation is asynchronous. There's no reason to use promises there at all. That can just be a plain synchronous function that returns whether the form is valid or not. You seem to have made this a much harder proposition than it needs to be. – jfriend00 Mar 24 '17 at 23:21
  • Hmm.. Would you look at this question I asked earlier - what are you thoughts? http://stackoverflow.com/questions/42989527/action-method-execution-sequence I appreciate your time. – Johny Mar 24 '17 at 23:22
  • Also, I do POST the form if it is valid. That was my main concern. – Johny Mar 24 '17 at 23:23
  • Yes, you POST the form, but you didn't hook that up to the promise so the promise isn't doing anything useful. – jfriend00 Mar 25 '17 at 00:10
  • The accepted answer to that other question has a `ValidateForm()` that is hooked up to the `$.post()`. It is using a [promise anti-pattern](https://github.com/petkaantonov/bluebird/wiki/Promise-anti-patterns) though because `$.ajax()` already returns a promise so there is no need to wrap it in a deferred. I'm not entirely sure what the whole problem is here (incorporating all issues from both questions) to know exactly what to suggest. You'd have to describe exactly what you're trying to accomplish as if you were writing a specification for how it should work. – jfriend00 Mar 25 '17 at 00:14
  • @jfriend00 hmm I need to get better understanding of .promise. I'll try to explain the problem that im experiencing again. Basically you can get an idea of how the UI of my application is structured from the other post. On every top Nav click, or next button, I must submit the form, if it exists and is valid. If not valid, form.valid() triggers validation errors and return false would stop any further propagation. The way I had it setup before was working flawlessly until I noticed a strange behavior which isn't very persistence. I'll continue in the next comment... – Johny Mar 25 '17 at 00:44
  • @jfriend00 form on my 3rd tab is quite data heavy. When I hit next button it goes thru the same process: check for an existing form, if valid, then submit. Submit calls the POST action method and when post completes it GETs the view for next tab. It works like this 5/10 times but at other times GET executes before the POST, which causes next page to load with incomplete data. When I put breakpoints to debug, I see GET for the next tab executing before POST of the current tab. I hope I'm making some sense here... I'm sorry if it's complicated... – Johny Mar 25 '17 at 00:52
  • I really think you should start from scratch and describe the whole process in a new question. You're asking questions about pieces of it in individual questions, but that makes it hard for us to see the bigger picture to suggest the best overall code. If you do that, then post a comment to me here with a link to the new question and I'll look at it when I can. It will be key to show the code for ALL your asynchronous operations because all of those have to be incorporated into the solution. – jfriend00 Mar 25 '17 at 00:54
  • @jfriend00 cool, I will do that. Thanks. – Johny Mar 25 '17 at 00:55
  • @jfriend00 I created a new question with more information and included all the code i could. Please have a look. http://stackoverflow.com/questions/43011545/wait-for-form-submit-post-to-complete – Johny Mar 25 '17 at 01:31

1 Answers1

1

You can't asynchronously decide whether you want to block the default action or not. By the time you get your async result, your function has already returned and the default action has already occurred.

If you have to validate asynchronously, then you will have to always block the default action. If the validation succeeds, then you will have to manually carry out the desired action with Javascript.

So, assuming that LoadPartialView_Main() is what you want to have happen when validation succeeds, you can do something like this:

var DonutsClickEvent = function (e, arg) {
    var url = $(this).attr('data');
    var data = { param: arg };

    if (typeof url === "undefined") return false;

    window.ValidateForm(false).then(function () {
        LoadPartialView_Main(url, data);
    }, function(err){
        // probably show validation error message to the user here
    });  
    // always prevent default action
    return false;
}

Also, there's no reason to use $.when() with a single promise. You can just use window.ValidateForm(...).then(...).

jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • Thanks for the response. Yes, I had return false; outside 'then' but the problem with that is it will always prevent default action even if validation is fine. I guess I can manually handle the active / non-active state toggle instead, as you suggested. – Johny Mar 24 '17 at 21:28
  • with a single promise. You can just use window.ValidateForm(...).then(...) - Good to know, thanks! I did what you suggested, always prevent default action - I manually trigger top navigation state change when form validates and submits successfully. I just learned about using jquery Deferred, Promise etc via my previous post http://stackoverflow.com/questions/42989527/action-method-execution-sequence. Thanks for taking time and helping out. Much appreciated. – Johny Mar 24 '17 at 23:18