I have a Flask app that takes in a url, does some logic and redirects the user to another url. I'd like to just generate a static html page that basically says "please wait" while the logic is executing.
Is there a nice way to do asynchronous stuff like this in jQuery?
app = Flask(__name__)
#app.route('/stuff/morestuff/')
def stuff():
#can I load html here without a return()?
#request.args input url, calls out to api, generates new url
return redirect(url)
It doesn't work that way. When an HTTP request is made to your server, the server gets to send back one response. That can be a success, a redirect, or several other types of responses. There is rarely a reason to do what you're describing because responding with a redirect is typically a fast operation.
However, if you really want to achieve that sort of behavior, you would need to respond with a success and have the page with which you respond take care of handling the redirect using javascript. At this point, you could perform all the logic client-side using JS, or use AJAX/websockets to communicate with the server for additional information while the user is told to wait. Keep in mind this method requires the user to have JavaScript enabled, which should not be necessary for a simple redirect.
Related
I have basic express js application with following route:
router.get('/', function(req, res){
res.render('login');
});
It works fine - after logging into main page on my localhost, html from login.pug is nicely rendered on client side. However when my app runs, sometimes I want to render another pug file, when there already is html rendered on client side:
app.get('/dashboard', function(req, res){
res.render('dashboard', {user: req.query.login});
});
But when get request is send on'dashboard'path, nothing happens. As I understand, this happens because res.render just parses pug file into HTML and sends it to client as plain string (which I can inspect in browser developers tool, when I check AJAX response I see exactly rendered HTML).
Now my question is: is there a way to render HTML from res.render in client automatically? So on server side I just write res.render('template') and on client side page is re-rendered without handling the response?
I know I can clear whole DOM and append received string into document.body, I know also that I can make a POST form request and then page will be re-rendered automatically, but I want to avoid both solutions (don't ask why).
Thank you for help in advance.
When your Javascript sends an Ajax request, the response from that Ajax request is just returned back to your Javascript. That's it. The browser does not show anything. If you want to do something with that response, then it is the responsibility of your Javascript to do something with it (insert it in the page to show it, etc...).
If what you really want is that you want the browser to actually go to the /dashboard URL and then show that page, then your Javascript can just do:
window.location = '/dashboard';
This will tell the browser to fetch the contents of that URL, it will make a request to your server, your server will return the rendered HTML and the browser will display it in the page and show /dashboard as the URL in the browser bar. That should do everything you want.
So, it's totally up to your Javascript. Pick the right tool for the job. Either fetch data for your Javascript with an Ajax call and process the result in your Javascript or instruct the browser to load a new page. One or the other.
But when get request is send on'dashboard'path, nothing happens. As I understand, this happens because res.render just parses pug file into HTML and sends it to client as plain string (which I can inspect in browser developers tool, when I check AJAX response I see exactly rendered HTML).
Yes, that what Ajax requests do. They fetch content from the server and return the data back to your Javascript (and only to your Javascript).
is there a way to render HTML from res.render in client automatically?
Yes, use window.location = '/dashboard'; from your Javascript.
So on server side I just write res.render('template') and on client side page is re-rendered without handling the response?
Not from an ajax call. Ajax calls never automatically display content. Never. Ajax calls are programmatic requests that return data to your script. That's what they are. But, yes from Javascript you can cause content to be automatically displayed by setting window.location to a new URL.
What would be the "best" approach to dealing with forms which have to work without and with JavaScript enabled?
Would it be better to create different routes for each, like
AJAX request: route "API/contact" and return res.send("message")
without JavaScript: route "contact"and return a redirect with a query param of "message"
Or in one route and detect xhr and render it depending on this?
Or is there a better way of dealing with the problem of taking the user to the res.send("") when the JavaScript isn't enabled to give the user feedback on the submit?
To clarify:
I have a site which is working with AJAX requests for its forms to avoid full page loads. It lacks the fallback when JavaScript is not enabled and thus when a user clicks submit on a form, he receives the data from the post back with res.send and it replaces the whole page, instead of the desired effect which would be to just update a label with the "success/fail" message. The question then remains as above which would be the neat way of dealing with this?
Probably the best thing to do would be to check the X-Requested-With header and check that it contains XMLHttpRequest (but this might get deprecated as the new fetch API will slowly come into browser.
Based on that value, you might want to return a JSON payload, or eventually trigger a server side rendering, therefore returning an HTML page ready-to-be-consumed.
As an alternative, you can return a redirect response with a particular query string value; once the page is loaded, you will check for that value (using qs for example, or deparam in jquery and manipulate the client side accordingly.
Your server routes have nothing to do with client-side javascript. You don't need javascript to receive a "res.send" message.
I am using an $http.post call to my server and sending over some user data:
$http.post('/streamdb/create/',{user:$scope.user.username})
My server then performs a series of operations and retrieves a certain id from the DB.
I would like to have the client redirected to the page ('streams/'+id), so I have the operations terminate with a
res.redirect('/streams/'+id)
I could send over the id:
res.json({id:id})
and then respond to a .success() clause with a $location, or window.open (as seen here, or here) but that seems a little wasteful: the server already knows where to send me, why should I make an additional call?
While the server shows that the routing was done, the new page never renders, it just stays on the original page.
Thanks for any help!
Your server side code cannot redirect the browser from an ajax response. The only reason that redirecting from the server side works without ajax is you are actually sending a fresh page each time, so a redirect means simply serving a different page. Ajax requests dont get served an entire new page as a response, so you are stuck on the current one. You need to go the 'wasteful' route :) Return the id in the response body and redirect using the angular $location service like you mentioned. I recommend using a promise and performing the redirect once it resolves.
Since mostly a backend guy, I am not sure how can I achieve the following since it
requires some interaction with the browser.
So, I have a the following things so far.
A communication protocol where server is in python and client is in javascript code.
Ultimately, I want my data to reach to that javascript code.
Now, this data is being captured from browser.
As a practice.. what I am trying to do is.. have two radio buttons on my browser and a submit button
*radio A
*radio B
* Submit
Now, when the user presses submit, I somehow want to create a query "user submitted: A (or B)" and this query i am able to capture on python script.
I am at lost on how to do this.
My guess is that "submit" invokes a python script.
But what if my python server is always on .. how do i parse that response from the click of browser to this python server?
This is the way it usually works:
Client (browser) visits webpage and initiates request to server
Server (in your case, Python) handles request and writes HTML response, including the radio-button form
Client fills out form and hits Submit, triggering another request to the server
Server handles the second request and writes another response (e.g. "Purchase successful", "message posted", etc.).
Note that the second request is a brand-new request. You may want some way of linking the first request to the second one unless the second request is anonymous. Some frameworks will do that for you, but if you are making the server from the ground up you'll want some kind of session mechanism to keep track of state.
To get the client to make the second request, the simplest is to add appropriate action and method attributes to the form element in your HTML. action specifies the URL to access for the form request, and method is either GET or POST. (More advanced usage, e.g. on this site, typically uses AJAX to make the submissions instead).
How do I design a Django/Javascript application to provide for conditional Ajax responses to conventional HTTP requests?
On the server, I have a custom-built Form object. When the browser POSTS the form's data, the server checks the submitted data against existing data and rules (eg, if the form adds some entity to a database, does that entity already exist in the database?). If the data passes, the server saves, generates an ID number and adds it to the form's data, and passes the form and data back to the browser.
if request.method == 'POST':
formClass = form_code.getCustomForm()
thisForm = formClass(data=request.POST)
if thisForm.isvalid():
saveCheck = thisForm.saveData()
t = loader.get_template("CustomerForm.html")
c = Context({ 'expectedFormObj': thisForm })
(Note that my custom logic checking is in saveData() and is separate from the html validation done by isvalid().)
So far, standard Django (I hope). But if the data doesn't pass, I want to send a message to the browser. I suppose saveData() could put the message in an attribute of the form, and the template could check for that attribute, embed its data as javascript variable and include a javascript function to display the message. But passing all that form html back, just to add one message, seems inelegant (as does the standard Django form submission process, but never mind). In that case I'd like to just pass back the message.
Now I suppose I could tie a Javascript function to the html form's onsubmit event, and have that issue an XMLHttpRequest, and have the server respond to that based on the output of the saveData() call. But then the browser has two requests to the server outstanding (POST and XHR). Maybe a successful saveData() would rewrite the whole page and erase any potential for conflict. But I'd also have to get the server to sequence its response to the XHR to follow the response to the POST, and figure out how to communicate the saveData outcome to the response to the XHR. I suppose that is doable, even without the thread programming I don't know, but it seems messy.
I speculate that I might use javascript to make the browser's response conditional to something in the response to the POST request (either rewrite the whole page, or just display a message). But I suspect that the page's javascript hands control over the browser with the POST request, and that any response to the POST would just rewrite the page.
So can I design a process to pass back the whole form only if the server-side saveData() works, and a message that is displayed without rewriting the entire form if saveData() doesn't? If so, how?
Although you can arrange for your views to examine the request data to decide if the response should be an AJAXish or plain HTML, I don't really recommend it. Put AJAX request handlers in a separate URL structure, for instance all your regular html views have urls like /foo/bar and a corresponding api call for the same info would be /ajax/foo/bar.
Since most views will examine the request data, then do some processing, then create a python dictionary and pass that to the template engine, you can factor out the common parts to make this a little easier. the first few steps could be a generic sort of function that just returns the python dictionary, and then actual responses are composed by wrapping the handler functions in a template renderer or json encoder.
My usual workflow is to initially assume that the client has no javascript, (which is still a valid assumption; many mobile browsers have no JS) and implement the app as static GET and POST handlers. From there I start looking for the places where my app can benefit from a little client side scripting. For instance I'll usually redesign the forms to submit via AJAX type calls without reloading a page. These will not send their requests to the same URL/django view as the plain html form version would, since the response needs to be a simple success message in plain text or html fragment.
Similarly, getting data from the server is also redesigned to respond with a concise JSoN document to be processed into the page on the client. This also would be a separate URL/django view as the corresponding plain html for that resource.
When dealing with AJAX, I use this:
from django.utils import simplejson
...
status = simplejson.dumps({'status': "success"})
return HttpResponse(status, mimetype="application/json")
Then, AJAX (jQuery) can do what it wants based on the return value of 'status'.
I'm not sure exactly what you want with regards to forms. If you want an easier, and better form experience, I suggest checking out uni-form. Pinax has a good implementation of this in their voting app.
FYI, this isn't an answer...but it might help you think about it a different way
Here's the problem I'm running into...Google App Engine + jQuery Ajax = 405 Method Not Allowed.
So basically I get the thing to work using the outlined code, then I can't make the AJAX request :(.