Jon Tara
unread,Oct 6, 2011, 5:24:53 PM10/6/11Sign in to reply to author
Sign in to forward
You do not have permission to delete messages in this group
Sign in to report message
Either email addresses are anonymous for this group or you need the view member email addresses permission to view the original message
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.