Ajax requests in Rhodes/JQuery Mobile - a simple example

1,141 views
Skip to first unread message

Jon Tara

unread,
Oct 6, 2011, 5:24:53 PM10/6/11
to rhom...@googlegroups.com
What should have been a simple task turned into a day of digging, so I thought I'd share my results to save others the hassle.

Really, this should be an everyday task for a Rhodes developer, so I'm surprised at the lack of documentation. Most Rails applications (hey, I know this isn't Rails...) are jam-packed with Ajax calls, and Rails has lots of support, including helpers that build the needed Javascript for you painlessly. I hope to see Rhodes move in that direction, and I'll be happy to contribute anything I come up with in that regard.

My goal: submit a form to the controller via Ajax, with no page refresh.  Just get the data to the controller. That's it.

I should note I am working on iOS. This should work for at least Android as well, I know it will not on Blackberry, because JQuery isn't supported there.

There's really no Rhodes documentation on this currently. The one example that keeps getting cited (DatePicker) doesn't use JQuery. Information on this forum is sparse and mostly old and confusing. The Jquery Mobile documentation is terrible (pretty, but terrible). As for JQuery itself, I found the JQuery Pocket Reference (REALLY cheap on Kindle) really useful. It's a lot more than you'd expect in a "pocket reference." Terminology can be confusing, because JQuery Mobile normally uses Ajax behind-the-scenes for what appear to be "normal" page loads, and so a lot of the terminology seems "inside out". For example, you need to "disable" Ajax to use Ajax to submit a form!

So, on to the example... This is a simple, single-field form. I could have done it without a form at all, really. But I wanted to know how to handle a form. In this example, I want the controller to send a message to a chat server. So, the form has a single field with the message text. As a practical matter, there would normally be at least another hidden field with some sort of context (like, who to send the message to) but this is a simple example of how to get the data from the form to the controller, so a single field will suffice.

    <form data-ajax="false" onsubmit="send_message(); return false;">
      <!-- <input type="hidden" name="id" value="<%= @room_id %>"/> -->
      <textarea type="text" class="message-entry" name="message-text"></textarea>
      <input type="submit" value="Send" data-icon="arrow-r" data-iconpos="right" data-inline="true" data-theme="b"></input>
    </form>

There are two things of note here:

1. data-ajax="false". This tells JQuery Mobile NOT to use Ajax to load the result of the form submission into the DOM as a page.

2. return false; in the onsubmit Javascript string. This tells Javascript to stop any further processing of the form submission. (Note that this is most often used in Javascript form validation.)

If either of these is omitted, then you will get an unwanted page refresh.

Next, a Javascript function to do the actual submission. I put this inline in the page, prior to the form. (It could go before or after, or in the header for that matter. You just need to get the function defined. I put it inline because it is specific to this page. But you could use parameters and load a similar function in the header using layout.erb. This is just to show the most simple example. And, of course, you'd want to remove the two alert calls: I just put those in to illustrate what is going on.

  <script type="text/javascript">
    function send_message() {
      var s = $("form", $.mobile.activePage).serialize();
      alert(s);
      $.post('<%= url_for(:action => :send_message) %>', s, alert);
    }
  </script>

Of course, this whole thing could be jammed into the onsubmit Javascript code string, if you wanted it to be more Rails-like. ;) I prefer readable code.

$.mobile.activePage returns the active page in the DOM (remember, JQM puts multiple pages in the DOM!).

$("form", $.mobile.activePage) returns the first form found in the active page. If you have more than one form, you would need to further refine the selector, "form", probably by qualifying with a class name. There's a great discussion of JQuery selectors in the book I mentioned. If you leave out the second parameter, things become much more difficult, because you are searching ALL of the DOM content, not just the current page.

serialize() produces a URL-encoded string of field names and values. This is what you need to send to the controller.

$.post() is the simplest way in JQuery to post to a URL. A lot simpler (but less flexible) than $.ajax(). First parameter is the url, second is the data string to send, and third is an optional function to call with the server response.  I've passed "alert" so that we can see what is sent back. In production, you'd just remove this, or use the function to clear the form, change the UI somehow to indicate "done", etc.

Note that currently in Rhodes, you will see a result of "<div></div>". I believe this is a bug. But we're just going to throw that away.

Finally, in your controller:

  def send_message
    app_info "send_message, @params: #{@params.inspect}"
  end

Here, I'm just logging @params, to show that the form parameters arrived safely in the controller. You'd probably want to do something more with them.

Gurdipe

unread,
Oct 7, 2011, 11:36:35 AM10/7/11
to rhom...@googlegroups.com
brill post

Jurgen B.

unread,
Oct 10, 2011, 6:11:39 AM10/10/11
to rhomobile
Bookmarked. Very helpful post :)

Gurdipe Dosanjh

unread,
Oct 18, 2011, 10:22:07 AM10/18/11
to rhom...@googlegroups.com
would your solution work for any blackberry?

Kind Regards

Gurdipe

On 10 October 2011 11:11, Jurgen B. <jpc.b...@gmail.com> wrote:
Bookmarked. Very helpful post :)

--
You received this message because you are subscribed to the Google Groups "rhomobile" group.
To post to this group, send email to rhom...@googlegroups.com.
To unsubscribe from this group, send email to rhomobile+...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/rhomobile?hl=en.


Gurdipe

unread,
Oct 18, 2011, 10:25:55 AM10/18/11
to rhom...@googlegroups.com
would i be able to use this solution to add the JQuery Calendar UI widget to any version of blackberry

kind regards

gurdipe

HDogger

unread,
Apr 25, 2012, 2:49:33 AM4/25/12
to rhom...@googlegroups.com
Having a really difficult time to intercept a Form post with the latest build of RhoMobile (downloaded yesterday).
I have followed all your suggestions in your message dated October 6, 2011.
But I think I have found a bug in RhoMobile with form submission.
Here's some code that DOES work to intercept the form submission:
<form data-ajax="false" method="POST" class="drawForm" action="<%= url_for :action => :create %>" onsubmit="alert('submitted'); return false;">
...
</form>



But this code DOES NOT work to intercept the form submission:
<form data-ajax="false" method="POST" class="drawForm" action="<%= url_for :action => :create %>" onsubmit="onNewMemberSubmit(); return false;">

...
</form>
<script type="text/javascript">
function onNewMemberSubmit(){
  alert
('submitted');  // never gets hit
 
return false;
}
</script>


And I really need to make a whole function to do the work, instead of putting it inline with the form tag in the onsubmit attribute.

Another thing I noticed, is that I can't use the normal method of attaching an event handler to the submit event with jQuery, like so:
$('div.ui-page-active form.drawForm').submit(function(e){
  e
.preventDefault();
  alert
('submitted');  // never gets hit
});

This submit handler seems never to be called.  I even followed the instructions here about not using ID's, but instead using class and the app's active div.

Please help, I'm new to RhoStudio and this has been a very frustrating start.
Thanks,
Hugh

HDogger

unread,
Apr 25, 2012, 2:57:24 AM4/25/12
to rhom...@googlegroups.com
Hello, I think I found a bug in the Form submit in RhoMobile.

I can intercept a form submission like this:
<form data-ajax="false" method="POST" class="drawForm" action="<%= url_for :action => :create %>" onsubmit="alert('submitted'); return false;">
...
</form>


But not like this:
<form data-ajax="false" method="POST" class="drawForm" action="<%= url_for :action => :create %>" onsubmit="onNewMemberSubmit(); return false;">
...
</form>
<script type="text/javascript">
function onNewMemberSubmit(){

  alert
('submitted');  // never called
 
return false;
}
</script>


Also, I can't intercept a form submission with jQuery like this:
<script type="text/javascript">
$
('div.ui-page-active form.drawForm').submit(function(e){
  alert
('submitted');  // never called
 
return false;
});
</script>


This is my first time using RhoStudio and I am having a tough time doing some very simple things.
Your help is appreciated.
Hugh



On Thursday, October 6, 2011 3:24:53 PM UTC-6, Jon Tara wrote:

Mark Zweedijk

unread,
Apr 25, 2012, 3:49:09 AM4/25/12
to rhom...@googlegroups.com
Change your submit button to:
<input type="button" onclick="validateForm()" value="Create"/>

And your form-node:
<form class="create_form" method="POST" action="<%= url_for :action => :create %>">

<script type="text/javascript">
function validateForm()
{
$('div.ui-page-active form.create_form').submit(); 
}

Op woensdag 25 april 2012 08:57:24 UTC+2 schreef HDogger het volgende:

HDogger

unread,
Apr 25, 2012, 3:06:28 PM4/25/12
to rhom...@googlegroups.com
Hi Mark, thanks for taking a moment to reply.
I have been a Web Developer for 17 years and I used to do what you are suggesting, to work with Forms.  The main drawback with the approach, is that Forms can be submitted by other means, than the Submit button.  Chiefly, that is the Enter key on the keyboard or mobile device.  Such a Form submit will bypass the logic in your proposed solution, which is wired directly to the Submit button's onclick handler.

The correct way is to handle the form's onsubmit event. The modern way to do that is with jquery's $('form').submit().  It is important because we get to separate design from logic, to keep the Form tag clean of any Js code.

Thank you again for your time in composing your response. If anybody else has an idea, I would enjoy hearing from you.
H Dog

Egghead

unread,
Aug 13, 2015, 10:50:17 PM8/13/15
to rhomobile
Jon, what if I wanted the contents of the textarea to show up below the Send button without a page refresh? Would I need a callback method in the controller?

I kept the form in index.erb with an empty index method in controller to render it. Then in send_message method, I capture the params sent by the JS function into a variable, and then try to display it below the Send button of index.erb by calling WebView.navigate back to index.erb. When I input some text in the text area the first time the form loads and click on Send, the params are sent allright, but the inputted text does not show up below the Send button. However, it shows up on inputting again ( and subsequently), but if I'm not mistaken, there's also some flickering of the page.

I suspect I need a callback method and then call WebView.navigate from there. Please correct me if I'm wrong. Just needed to understand more how callbacks prevent page refreshes.
Reply all
Reply to author
Forward
0 new messages