bartrad has asked for the wisdom of the Perl Monks concerning the following question:

Hi, I've got a Mojo app that runs some code in the background, taking roughly 60 seconds to complete. It's a simple app that has a "get" endpoint for "/" to display a form with a submit button that does a "post" to "/" where the sub routine does the stuff taking the 60 seconds before rendering a results template.

Is there a way to show a user a loading animation for those 60 seconds (without hardcoding the duration) while the data is collected before then presenting the results screen? I've seen loaders in JS or CSS but I'm not quite sure how to invoke them, since if I include them in the result template, Mojo will do the data collection before rendering the HTML in the results template. Could someone help explain how to make it so after hitting the form submit button, a loading animation is instantly rendered, and then when the data collection is done, the results template is rendered and the user forwarded? Thanks in advance!

get '/' => sub { my $c = shift; $c->render( template => 'index' ); }; post '/' => sub { my $c = shift; my ($opt) = $c->param('option'); app->log->info("Option $opt"); my $result = do_something($opt); $c->render( template => 'result', c => $result ); };
@@ index.html.ep %layout 'default'; <form method="post" action="." enctype="multipart/form-data"> <input name="option" size="40" type="text"></input><br> <br><input type="submit" name="submit" value="submit"><br> </form>
@@ result.html.ep %layout 'default'; <div id="loader"></div> <div id="content"> <h2>Result</h2> <pre> <%= $c %> </pre> </div>

Replies are listed 'Best First'.
Re: Mojolicious waiting page
by haukex (Archbishop) on Mar 18, 2020 at 08:23 UTC

    Here's one way, with AJAX:

    Update: To clarify, this mainly shows how to do the form submission asynchronously - you can always modify this code so that it, for example, redirects to a different page when the form submission is complete, to show a "spinner" image instead of the "Submitting" message, and so on. /Update

    #!/usr/bin/env perl use Mojolicious::Lite -signatures; get '/' => sub ($c) { $c->render(template => 'index'); } => 'index'; post '/submit' => sub ($c) { $c->render_later; Mojo::IOLoop->timer(10 => sub { # simulate long process if ( $c->param('foo') =~ /foo/i ) { $c->render(json => { ok=>1, message=>"All good" }); } else { $c->render(json => { ok=>0, message=>"Bad foo value" }); } }); } => 'formsubmit'; app->start; __DATA__ @@ layouts/main.html.ep <!DOCTYPE html> <html> <head><title><%= title %></title></head> <body> %= content </body> </html> @@ index.html.ep % layout 'main', title => 'Hello, World!'; <div> %= form_for formsubmit => ( method=>'post', id=>'myform' ) => begin <div> %= label_for foo => 'Foo' %= text_field foo => ( placeholder=>"Foo", required=>'required' ) (must contain "foo") </div><div> %= label_for bar => 'Bar' %= text_field bar => ( placeholder=>"Bar" ) </div><div> %= submit_button 'Login' <span id="formmessage"></span> </div> %= end </div> <script src="" integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script> <script> $(function () { $('#myform').on('submit', function (e) { e.preventDefault(); var thedata = $('#myform').serialize(); // before disabling! $("#formmessage").text("Submitting, please wait..."); $("#myform :input").prop("disabled", true); $.ajax({ type: 'post', url: '<%= url_for 'formsubmit' %>', data: thedata, timeout: 120*1000 }) .done( function( data ) { if (data.ok) { alert("Form was submitted: "+data.message); } else { alert("Problem with submission: "+data.message); } }) .fail( function( jqXHR, textStatus, errorThrown ) { alert("Form submission error: "+textStatus +" / "+jqXHR.status+" "+errorThrown); }) .always( function () { $("#formmessage").text(""); $("#myform :input").prop("disabled", false); }); }); }); </script>
Re: Mojolicious waiting page
by Anonymous Monk on Mar 16, 2020 at 09:22 UTC
Re: Mojolicious waiting page
by Anonymous Monk on Mar 16, 2020 at 00:51 UTC
    Nearly always, the "twirlybird" that you see is nothing more than an animated GIF, revealed by the button-handler and hidden by the AJAX responder. There are thousands of these available online and some of them are quite elaborate.

      But where do you call it so it displays it before executing the main guts of the script so it displays as soon as the user hits submit?