form submit jQuery mobile - coldfusion

I've gotten it into my head that mobile applications don't like form submits the same way html does, so I thought I'd better have a sanity check on Stackoverflow.
For example, instead of having <input type="submit"...>, it looks like I should now use <a data-role="button"...>
Q: Can I continue to use <input type="submit"...> for mobile applications?
The reason why I ask is because the action page has some logic, such as:
<cfif structKeyExists(form,"Save")>

jQuery Mobile, at least as of this writing, by default submits forms via AJAX using the method specified on the form being submitted. POST submissions will still be posted to the server in the background, so ColdFusion will still see the form variables that are passed in as usual. When a response is generated, jQuery Mobile will take the response and transition the view over to whatever HTML was returned. In my own testing you can continue to use a normal submit button as well. If you want a standard submission rather than an AJAX submission, add data-ajax="false" to the form tag.

If you want to programatically submit a form, set the data-ajax attribute for the form to false and then set an event handler for the submit event for the form:
<form data-ajax=false></form>
$(function () {
$('form').bind('submit', function (event) {
event.preventDefault();
$.post('path/to/server.file', $(this).serialize(), function (data) {
alert('Server Response: ' + data);
});
});
});

Related

Django form submission without reloading page

I have a django register form .On the event of an invalid form submission, page is reloading.I need to stay on that same page if the data entered is invalid.
Is there any way to get this done without ajax ?
If not, how to do this with ajax
Well if you want to validate the data before submitting then you can just use plain javascript to validate the values and update your html displaying output as shown below.
Consider this below form.
<form>
<input id="target" type="text" value="">
</form>
<div id="other">
Trigger the handler
</div>
Use below script
<script>
$("#target").keyup(function () {
console.log(this.value);
});
</script>
In above script once you get the value you can write the logic to valid the same and update you result in html accordingly.
NOTE: Main point here is the event handler as you type anything it calls the function.
Obviously this may not be the best way to achieve this but consider this as demonstration.

CFWheels: Display form errors on redirectto instead of renderpage

I have a form which I am validating using CFWheels model validation and form helpers.
My code for index() Action/View in controller:
public function index()
{
title = "Home";
forms = model("forms");
allforms = model("forms").findAll(order="id ASC");
}
#startFormTag(controller="form", action="init_form")#
<select class="form-control">
<option value="">Please select Form</option>
<cfloop query="allforms">
<option value="#allforms.id#">#allforms.name#</option>
</cfloop>
</select>
<input type="text" name="forms[name]" value="#forms.name#">
#errorMessageOn(objectName="forms", property="name")#
<button type="submit">Submit</button>
#endFormTag()#
This form is submitted to init_form() action and the code is :
public function init_form()
{
title = "Home";
forms = get_forms(params.forms);
if(isPost())
{
if(forms.hasErrors())
{
// don't want to retype allforms here ! but index page needs it
allforms = model(tables.forms).findAll(order="id ASC");
renderPage(action="index");
//redirectTo(action="index");
}
}
}
As you can see from the above code I am validating the value of form field and if any errors it is send to the original index page. My problem is that since I am rendering page, I also have to retype the other variables that page need such as "allforms" in this case for the drop down.
Is there a way not to type such variables? And if instead of renderPage() I use redirectTo(), then the errors don't show? Why is that?
Just to be clear, I want to send/redirect the page to original form and display error messages but I don't want to type other variables that are required to render that page? Is there are way.
Please let me know if you need more clarification.
This may seem a little off topic, but my guess is that this is an issue with the form being rendered using one controller (new) and processed using another (create) or in the case of updating, render using edit handle form using update.
I would argue, IMHO, etc... that the way that cfWheels routes are done leaves some room for improvement. You see in many of the various framework's routing components you can designate a different controller function for POST than your would use for GET. With cfWheels, all calls are handled based on the url, so a GET and a POST would be handled by the same controller if you use the same url (like when a form action is left blank).
This is the interaction as cfwheels does it:
While it is possible to change the way it does it, the documentation and tutorials you'll find seem to prefer this way of doing it.
TL; DR;
The workaround that is available, is to have the form be render (GET:new,edit) and processing (POST:create,update) handled by the same controller function (route). Within the function...
check if the user submitted using POST
if it is POST, run a private function (i.e. handle_create()) that handles the form
within the handle_create() function you can set up all your error checking and create the errors
if the function has no errors, create (or update) the model and optionally redirect to a success page
otherwise return an object/array of errors
make the result error object/array available to view
handle the form creation
In the view, if the errors are present, show them in the form or up top somewhere. Make sure that the form action either points to self or is empty. Giving the submit button a name and value can also help in determining whether a form was submitted.
This "pattern" works pretty well without sessions.
Otherwise you can use the Flash, as that is what it was created for, but you do need to have Sessions working. their use is described here: http://docs.cfwheels.org/docs/using-the-flash and here:http://docs.cfwheels.org/v1.4/docs/flashmessages
but it really is as easy as adding this to your controller
flashInsert(error="This is an error message.");
and this to your view
<cfif flashKeyExists("error")>
<p class="errorMessage">
#flash("error")#
</p>
</cfif>

403s resubmitting a form after login

I get a 403 under the following repro steps:
While logged out, try to submit a Django form that generates a validation error
Log in or signup for a valid account
Using the browser, go BACK to the page with the validation error
Resubmit the form
Results: 403 error. This is most likely expected behavior, however I'm looking for a more graceful way to handle this. Is there a good way to catch this and resubmit the form as the logged in user?
I have seen this question asked in the context of many frameworks, and the only elegant solution is JavaScript.
With JavaScript, you could store the input values in localStorage. Then on successful form submit event, clear those values. If the form is loaded with those values existing in localStorage (the form submission returned 403, and the user went back to the form page), then automatically populate the form with the values.
Its not really that complex to implement, just more work. I believe there are JS libraries based on this idea...
Give all your form elements a classname. In the example I will use store-data. This can be set in forms.Widget.attrs if you define your form in django, or just with the class attribute on input elements if you write your own html.
On submit, add an item named formData to localStorage. formData is a JS object mapping form field element ids with the classname from above to the element values.
If the form is submitted and processed as valid, on the redirect page remove formData from localStorage with localStorage.removeItem().
When loading the form page (this would be where the user went back to the form after a 403), if formData exists in localStorage then load the values into the form fields.
Here is an example form with this implemented:
<form name="myForm" action="{% url 'myapp:form_submit' %}" onsubmit="return storeData()">
<label>Name: </label>
<input type="text" class="store-data" id="inputName" />
<label>Description: </label>
<textarea class="store-data" id="textareaDescription"></textarea>
<input type="submit" />
</form>
<script>
function storeData() {
var elements = document.getElementsByClassName("store-data");
var formData = {};
// store element ids and values in formData obj
for (var i = 0; i < elements.length; i++) {
formData[elements[i].id] = elements[i].value;
}
// store formData to localStorage as string
localStorage.setItem('formData', JSON.stringify(formData));
}
// if the localStorage item has already been set, then the user tried to submit and failed
if (localStorage.getItem('formData')) {
formData = JSON.parse(localStorage.getItem('formData'))
// set all the form elements to the values that were stored when the user tried to submit
for (var key in formData) {
document.getElementById(key).value = formData[key];
}
}
</script>
And on the redirected success page, be sure to remove the formData item. Otherwise, any time the user goes back to the form the values will be loaded into the fields. (I suppose this may be a desired behavior, but I doubt it.)
<script>
localStorage.removeItem('formData');
</script>
Well, yes, it's expected behaviour. When you login, new csrf_token is generated. And when you navigate back to page with validation error, it still contains old csrf_token in <input type="hidden" name="csrfmiddlewaretoken" value="old_token" />. So you submit form with invalid csrf_token and get 403 error.
I can suggest two options for you (none of them I like)
Disable new csrf_token generation on login. Just place request.META['CSRF_COOKIE_USED'] = False after login(request, user) in your loggin view.
Disable csrf protection via decorator for your single view, or globally by removing csrf middleware from your settings.py.

Getting checkbox value in flask

I'm trying to poll the state of checkboxes (this is done in JS every three seconds). This solution returns "None" (see code below); Both printouts (with 'args' and with 'form') return "None". I'm expecting True/False, depending on the checkbox's boolean state.
index.html:
{% extends "layout.html" %}
{% block content %}
<div id="results" class="container">{{data_load|safe}}</div>
<input id='testName' type='checkbox' value='Yes' name='testName'>
{% endblock %}
and the relevant flask app snippet:
#app.route('/', methods = ['GET', 'POST'])
def index():
return render_template('index.html', data_load=timertry())
#app.route('/_timertry', methods = ['GET', 'POST'])
def timertry():
print request.args.get('testName')
print request.form.get('testName')
return "some html going into 'results' div.."
The JavaScript polling function (adapted from here):
$(document).ready(function() {
$.ajaxSetup({cache : false});
setInterval(function() {
$('#results').load('/_timertry?' + document.location );
}, 3000); // milliseconds!
});
This should be simple enough, but none of the SO solutions I looked into (e.g., using jquery, adapting the flask/ajax example, etc.) worked.
EDIT: following mark's suggestion (including the javascript) and adding
print request.values in index.html returns (seen on the console in Aptana):
CombinedMultiDict([ImmutableMultiDict([]), ImmutableMultiDict([])])
Clearly, the request seems empty. The post request is logged (when checkbox is pressed) as:
127.0.0.1 - - [03/Oct/2013 00:11:44] "POST /index HTTP/1.1" 200 -
Any ideas here?
Your javascript does the following every three seconds...
$('#results').load('/_timertry?' + document.location);
In other words, you are using the jQuery load() function. The documentation for that function states that this will, in essence, call an HTTP get request to the URL you provide as the parameter (something like /_timertry?http://www.example.org. In other words, a GET request will be called to /timertry?http://www.example.org, which will be handled by Flask's timertry method.
When you have an HTTP form, and you click the "Submit" button, the browser does some magic to push all of the values to the server in the request. When you just do a simple AJAX request, none of that happens for you. Instead, you need to explicitly state what you want to be passed as data to the server (although there are plugins to help you with "post the values of an HTML form using AJAX").
So, because at no point did you do anything in your Javascript to retrieve the value of checkbox to include it into the AJAX request, the AJAX request has no values specifying that the checkbox was checked. You would need to have jQuery check if the box is checked...
var isChecked = $('#testName').is(':checked');
# Now do something with isChecked...
From what I can tell, however, you are sort of misusing HTTP: the load function will make a GET request, and you probably want something to happen as a request of the request. You probably want to make it do a POST request instead (see here and here). Also, you mentioned that you're looking for something to post when a value is changed. Putting this together, you can do something like this...
// Ensure that the function is called when the DOM is ready...
$(function() {
// Register an event that should be fired when the checkbox value is changed
$('#testName').change(function() {
var data = { isChecked : $(this).is(':checked') };
$.post('/', data);
});
})
In this case, we have an event that is called when a checkbox is checked, and that event causes us to make a POST request to the server.
I'm going to answer this question which was found in the comments of the question
"which becomes a question of how to submit a form without a 'submit' button.."
So it is very possible to submit a value when a user clicks on the button
{% block content %}
<form id="target" action="YourViewName">
<div id="results" class="container">{{ data_load|safe }}</div>
<input id='testName' type='checkbox' value='Yes' name='testName'>
</form>
{% endblock %}
$( "#results" ).click(function() {
$( "#target" ).submit();
});
If you want to stay on the same page, however, you're going to need to use an ajax call to pass the data back rather then use a standard submit, however This tutorial covers that topic fairly well. but a basic change to send the data back would look like
$( "#results" ).click(function() {
var request = $.ajax({
type: "POST",
url: "/YourViewName",
data: {'input_value':$('#testName').val()},
dataType: "html"
}).done(function(msg) {
// I don''t know what you want to do with a return value...
// or if you even want a return value
}
});
and the flask would look like
#app.route("/YourViewName")
def example():
list_name = request.args.get("input_value")
#if you don't want to change the web page just give a blank return
return ""

Displaying a temporary page while processing a GET request

I have a view that can take several seconds to process a GET request and render the results. I'd like to put up a temporary page that says "Processing..." while the view is doing its stuff. How can I do this?
UPDATE
I don't have any control over the link to my page. It is a link to me a third party has on their page. When they click it I run some stuff and display the results. I don't want them to have to click anything on the pages I display.
Ideally, I would like the following:
A user clicks a link to my website that is on a 3rd party website
My websites displays a "processing request" message - the user doesn't have to click anything, just wait.
After a few seconds the results are displayed.
All the user had to do was click a link once and wait for the results.
Some example code would be greatly appreciated as I am quite new to things like jQuery - if that's what I need.
Use jQuery to display the message while waiting for the view to return the result.
Place a hidden div-tag in the page containing the processing message/image.
If you submit the GET request by clicking a button you put an onclick event on the button to display the div-tag. When the view is done processing, the page will be reloaded and the target page will be displayed.
If the view is called using AJAX you can place the show/hide of the div in the ajaxStart and ajaxComplete events.
EDIT: OK since the page will be called from by a 3rd party it will complicate things a bit. I would suggest that you load the page without the data and once the page is loaded you do an AJAX GET request to retrieve the data.
You could do as follows:
Add a hidden div-tag to the page with the Progress message/image.
<div id="progress">Please wait while the page is loading.</div>
Then add the ajax GET call to the page:
$(document).ready(function () {
//Attach the ajaxStart and ajaxComplete event to the div
$('#progress').ajaxStart(function() {
$(this).show();
});
$('#progress').ajaxComplete(function() {
$(this).hide();
});
//Perform the AJAX get
$.get('/your_view/', function(data) {
//Do whatever you want with the data here
});
});
The above code has not been tested but it will give you an idea.
UPDATE
I would suggest that you return a JSON object or similar from your view:
companies = Company.objects.filter(name__istartswith=companyname)
results = [{'value': company.name, 'id':company.id} for company in companies ]
json = simplejson.dumps(results)
return HttpResponse(json, mimetype='application/json')
You can also use the getJSON() method instead of get() in jQuery.
very simple example:
<script>
showProcessingMessage = function() {
$("body").append('<div id="style_me_as_message">processing request</div>');
}
$("body").on('click', "a.slow", showProcessingMessage);
</script>
<a class="slow" href="/slow-response-page/">show slow page</a>