1

Play framework 2.4.x. A button is pressed on my home page that executes some code via Ajax, and returns its results beneath the button without loading a new page. The results wait for a user to input some text in a field and press "submit". Those results Look like this:

<li class="item">
        <div>
            <h3>Email: </h3>
            <a>@email.tail.init</a>
            <h3>Name: </h3>
            <a>@name</a>
        </div>
        <div>
            <h3>Linkedin: </h3>
            <form class="linkedinForm" action="@routes.Application.createLinkedin" method="POST">
                <input type="number" class="id" name="id" value="@id" readonly>
                <input type="text" class="email" name="email" value="@email" />
                <input type="text" class="emailsecondary" name="emailsecondary" value="" />
                <input type="text" class="name" name="email" value="@name" />
                <input type="text" class="linkedin" name="linkedin" value="" />
                <input type="submit" value="submit" class="hideme"/>
            </form>
        </div>
        <div>
            <form action="@routes.Application.delete(id)" method="POST">
                <input type="submit" value="delete" />
            </form>
        </div>
    </li>

Along with some jquery that slides up a li after submission:

 $(document).ready(function(){
        $(".hideme").click(function(){
               $(this).closest('li.item').slideUp();
                });
            });

However, since a form POST goes inside an Action that must a return an Ok(...) or Redirect(...) I can't get the page to not reload or redirect. Right now my Action looks like this (which doesn't compile):

newLinkedinForm.bindFromRequest.fold(
errors => {
  Ok("didnt work" +errors)
},
linkedin => {
  addLinkedin(linkedin.id, linkedin.url, linkedin.email, linkedin.emailsecondary, linkedin.name)
    if (checkURL(linkedin.url)) {
      linkedinParse ! Linkedin(linkedin.id, linkedin.url, linkedin.email, linkedin.emailsecondary, linkedin.name)
      Ok(views.html.index)
    }else{
     Ok(views.html.index)
    }
  }
)

Is it possible to return Ok(...) without redirecting or reloading? If not how would you do a form POST while staying on the same page?

EDIT: Here is my attempt at handling form submission with jquery so far:

 $(document).ready(function(){
        $(".linkedinForm").submit(function( event ) {
            var formData = {
                'id'                : $('input[name=id]').val(),
                'name'              : $('input[name=name]').val(),
                'email'             : $('input[name=email']).val(),
                'emailsecondary'    : $('input[name=emailsecondary]').val(),
                'url'               : $('input[name=url]').val()
            };

            jsRoutes.controllers.Application.createLinkedin.ajax({
                type     :'POST',
                data     : formData

            })

            .done(function(data) { 

                console.log(data);

            });

            .fail(function(data) {

                console.log(data);
            });

            event.preventDefault();
            };
        });
plambre
  • 5,568
  • 2
  • 15
  • 30

3 Answers3

1

This is an issue with the browser's behavior on form submission, not any of Play's doing. You can get around it by changing the behavior of the form when the user clicks submit.

You will first want to attach a listener to the form's submission. You can use jQuery for this. Then, in that handler, post the data yourself and call .preventDefault() on the event. Since your javascript is now in charge of the POST, you can process the data yourself and update your page's HTML rather than reloading the page.

Zeimyth
  • 1,299
  • 12
  • 19
  • Haven't tried to implement this yet, but just off reading your response, can I still send the form information to my Akka Actor like i do with my current code? – plambre Sep 15 '15 at 18:55
  • @plambre Yes. Try a Google search for ways to send the form data manually, process it as you normally would in the Scala, and then return something sensible knowing that javascript will be handling the reply (e.g. it would probably be easier to reply with json rather than html). – Zeimyth Sep 15 '15 at 18:58
  • From my brief perusal of other people's questions, it seems like they're attaching the jquery form submission to an id of a form... my play app is generating anywhere from 0 to 300 individual forms on the same page, so they don't have a unique id (they're class="linkedinForm"). Is this going to be a problem? – plambre Sep 15 '15 at 19:27
  • You need to know what specific form got submitted so you can know where to look in the DOM for the data that was going to be posted. You could work around that by generating a unique ID for each form, attaching your submit listener to all forms at once, and then looking up the current form's ID in the event handler. – Zeimyth Sep 15 '15 at 19:42
  • ...there are probably better ways to do that though. Again, I encourage you to google around a bit. I feel like every time I go to work on forms, I need to refresh my memory on how exactly to do it. :) – Zeimyth Sep 15 '15 at 19:43
  • I just added the beginnings of some jquery to handle form submission (untested) to my original question could you check it real quick? – plambre Sep 15 '15 at 19:46
  • It looks reasonable. The truest test is just to test it, though. :) I'd suggest also logging what the server sees as well, just for extra validation. – Zeimyth Sep 15 '15 at 19:49
0

What you need is use ajax to submit a form, check this: Submitting HTML form using Jquery AJAX

In your case, you can get the form object via var form = $(this), and then start a ajax with data from the form by form.serialize()

    $.ajax({
        type: form.attr('method'),
        url: form.attr('action'),
        data: form.serialize(),
        success: function (data) {
            alert('ok');
        }
    });
Community
  • 1
  • 1
waterscar
  • 866
  • 8
  • 14
0

In order to accomplish this task, i had to use play's javascriptRouting

This question's answer helped a lot.

I'm not experienced with jquery so writing that correctly was difficult. For those that find this, here is my final jquery that worked:

 $(document).ready(function(){
        $("div#results").on("click", ".hideme", function(event) {
         var $form = $(this).closest("form");
               var id = $form.find("input[name='id']").val();
               var name = $form.find("input[name='name']").val();
               var email = $form.find("input[name='email']").val();
               var emailsecondary = $form.find("input[name='emailsecondary']").val();
               var url = $form.find("input[name='url']").val();


            $.ajax(jsRoutes.controllers.Application.createLinkedin(id, name, email, emailsecondary, url))
            .done(function(data) {
                console.log(data);
                $form.closest('li.item').slideUp()
            })
            .fail(function(data) {
                console.log(data);
            });

            });

        });

Note that my submit button was class="hideme", the div that gets filled with results from the DB was div#results and the forms were contained within li's that were class="item". So what this jquery is doing is attaching a listener to the static div that is always there:

<div id="results">

It waits for an element with class="hideme" to get clicked. When it gets clicked it grabs the data from the closest form element then sends that data to my controller via ajax. If the send is successful, it takes that form, looks for the closest li and does a .slideUp()

Hope this helps

Community
  • 1
  • 1
plambre
  • 5,568
  • 2
  • 15
  • 30