Django - Update page with ajax data - javascript

[Edited for more clarity]
My problem is more of an architecture problem, I have thoughts of many ways to do what I need to but can't figure out which one is correct/the best, so here it is.
I fetch some xml from a remote webserver using ajax, then parse it with jquery.What I want is that when the page is first rendered I have some "loading" gifs, one for each ajax request i'll be making , then when the data is fetched, it appears on the page.
The things is I want to have jquery post these data to the view to render it. ( This is for the other developers who will be using my app, who don't know much of javascript and prefer to write python/html to code the way they want the data to be displayed and make use of the django template engine for custom tags and stuff)
The question is how can I distinguish between the first loading of the page where we have no data and the second time where we have the data. I don't want to have to refresh the page at any time. I thought of having something in the template like :
{% block content %}
{% if not data %}
it's the first loading of the page,we have to fetch the data.
<p> My first item : some loading logo </p>
<script>
call a static script that gets the data then appends it to the html/post it back.
</script>
{% endif %}
{% if data %}
the data had already been fetched so we can display it, something like :
<p> My first item : {{first item}} </p>
{% endif %}
{% endblock %}
I have looked on other questions but it is usually updating with data from the database. Sorry if the question is too specific but I want to really have a good design of the problem before starting to write code and I'm a bit lost. Thank you .

Why do you want to send the parsed data back to the server just for transforming it into Html ?
Why not just use some kind of Javascript based rendering library that can do this ? Your appliation would perform faster since you don't need to execute an extra request.

Django tags and context dict are resolved when template is rendered for the first time.
AJAX is used to post/fetch data withoud page reload, so after AJAX request your page will not be reloaded - and django template renderer will have no possibility to show updated data.
But you could use jQuery get() or post() to retrieve rendered template from other django view and integrate it into current page.
This template must be rendered at request on /ajax/fetch/:
{% block content %}
{% if not data %}
it's the first loading of the page,we have to fetch the data.
<p> My first item : some loading logo </p>
<script>
call a static script that gets the data then appends it to the html/post it back.
</script>
{% else %}
the data had already been fetched so we can display it, something like :
<p> My first item : {{first item}} </p>
{% endif %}
{% endblock %}
And this is sitting on your main page:
<script [include jquery here]></script>
<script>
$(function(){
$("#get_data_please").click(function(){
$.get('/ajax/fetch/', function(data) {
// this is called on ajax success
$('#ajax_result').html(data);
});
});
});
</script>
...
Click to get data
<div id="ajax_result">
Here all will be loaded
</div>

Related

Replace a html div based on .onchange, passing in a variable

I am using Flask and wtforms to create a web page "index.html" that loads multiple forms. The selection of forms that are rendered depend on dropdown selections, and a variable "serviceid" updated from an API call. The form selection and rendering is handled in an included file "form_select.html", which requires "serviceid" value to pick the correct form. I am having trouble figuring out how to refresh the forms based on updated serviceid values without doing a full page reload.
I can use something like this with jinja2 include to render "form_select.html" and pass the "serviceid" variable so the right form is rendered:
<div id="loadform"> {% include './form_select.html' with serviceid %} </div>
This is working on first load, but I need to select a new form when the user selects a new value from a dropdown. I am running a script based on mydropdown.onchange, which first obtains the correct "serviceid" value, but now I need to rerender just the loadform div with this value.
I have tried approaches along the lines of the following - but I cant seem to figure out how to deliver this jinja2 with .innerHTML.
document.getElementById('loadform').innerHTML = `
{% with serviceid=serviceid %}
{% include './form_blocks.html' %}
{% endwith %}
`;
There is probably a better way to do this, but the examples I can find don't include passing in a variable. Can I use innerHTML for this, or is there a better way?

How to pass a javascript variable to WTForm? Python/Flask

I am creating a data entry/timing web app using Python and Flask. When the user goes to the log page, they enter in the "session ID" for their task, and the time of form submission and user ID are automatically input to the database as well.
Now I am trying to use Javascript to record when the page is loaded for a task so I have a start time and an end time. I first attempted to POST the javascript variable via AJAX to the back end, but I couldn't seem to get it to work. Now I am trying to have the javascript variable be sent alongside the session ID as part of a "HiddenField". I am not yet at the point of configuring the page load time script, I am just trying to get the Javascript to talk to WTForms to talk to my database commit. Here is my code currently:
views.py
#app.route('/logpage', methods=['GET', 'POST'])
#login_required
def logpage():
form = LogForm()
if form.validate_on_submit():
timer = request.get_data("timer")
entry = LogData(sessionid=form.sessionid.data, user_id=current_user.get_id(), starttime=form.testvar.data, endtime=datetime.utcnow())
db.session.add(entry)
db.session.commit()
return redirect(url_for('home'))
return render_template('logpage.html', form=form)
models.py
class LogForm(FlaskForm):
sessionid = StringField('sessionid', validators=[InputRequired(), Length(min=16, max=16)])
testvar = HiddenField('testvar')
logpage.html
{% extends "base.html" %}
{% import "bootstrap/wtf.html" as wtf %}
{% block title %}Active Log Page{% endblock %}
{% block head %}
<!-- Custom styles for this template -->
<link href="static/css/starter-template.css" rel="stylesheet">
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script>window.jQuery || document.write('<script src="{{ url_for('static', filename='jquery.js') }}">\x3C/script>')</script>
<script src="static/js/timer.js?version=25"></script>
{% endblock %}
{% block body %}
<div class="container">
<div class="form-group">
<form class="form-logpage", method="POST" action="/logpage", id="jsinput">
{{ form.hidden_tag() }}
{{ wtf.form_field(form.sessionid) }}
<div id="jsinput">
{{ wtf.form_field(form.testvar) }}
</div>
<button class="btn btn-lg btn-primary btn-block" type="submit">Finish Job</button>
</form>
</div>
</div>
{% endblock %}
timer.js
var myData = "dataVariable";
document.getElementById("jsinput").value = "myData";
As you can see, I tried to use document.getElementById to put the variable in logpage.html, but when I hit submit, the starttime field is empty. I've looked around the documentation for a way to put a variable in the WTForm, but I can't find anything relevant.
Before, during some other issues it's showed as null and /x and ''b but I've done a good bit of tinkering since then and the database entry is just ''.
If there is a more elegant way to record page load datetime and record simultaneously to the database with the rest of the data, I would love to hear suggestions. Previous SO post here: Python/Flask: How to tell how long a user spends on a page? (Data entry/time log app)
Here's the solution I came up with for this problem:
Add a hidden field to the form with an id.
Grab the ID in your script and assign a value to it.
In your form.py:
from flask_wtf import FlaskForm
from wtforms import SubmitField
from wtforms import HiddenField
class MyForm(FlaskForm):
my_data = HiddenField(
'my_data',
render_kw={'id':'my_data'}
)
save = SubmitField(
'Save',
render_kw={'id':'save'}
)
create and pass your form in your view and then render the save and my_data fields in your html template using {{ form.save }} and {{ form.my_data }}
Add the following to your javascript:
var saveButton = document.getElementById('save');
saveButton.addEventListener('click', function() {
document.getElementById('my_data').value = 'MY DATA IS HERE!!';
});
you can now access your data in your python view using:
from flask import request
...some code...
request.form['my_data']
It's a late answer, but hopefully useful to someone out there...

django/javascript populating table on the fly

I have a huge database with multiple tables. Essentially I want the table I have to populate on the fly based on what the user clicks from a menu that is populated from the same database. I'm new to django and don't really know how to go about doing this. Right now all the information I need is being passed to the page when it renders and because of that my page is loading extremely slowly. Basically I have a function that is called when something from the menu is clicked that loops through everything I have passed to the page to populate the table accordingly.
To give you a better picture, let's say I have a table of stores and another table of the monthly revenue in my database. The table on the webpage will display the latest 5 data points (ie, the date (month and year), the revenue, and the store name). How do I populate the table based on the selection from the menu?
My menu is populated as follows:
{% for a, storeList in stores.items %}
<div class="overview">
<div><b>{{a}}</b></div>
{% for s in storeList %}
<div id = "{{s.storename}}" onclick="changeSiteInfo(this.id);"{{s.storename}}</div>
{% endfor %}
</div>
{% endfor %}
Thanks for the help =)
You can try integrating DataTables using one of the apps descirbed here.

How to send values via ajax from django template to views?

I have a select box that calls a function on changes. The function finds the selected value from "Products" selectbox.
I want to throw that selected value to my views.py which after some operations return the list of data and Populates the Destination's selectbox.
I want to use ajax for this purpose. Please help.
My code looks like this:
<script type="text/javascript">
function select_value()
{
var e = document.getElementById("Product");
var prod = e.options[e.selectedIndex].text
console.log(prod)
}
</script>
This is what my selectbox look like:
<table>
<tr>
<td>
<select id="Product" onChange="select_value();">
{% for products in product_name_list %}
<option>{{products|safe}}</option>
{% endfor %}
</select>
</td>
<td>
<select id="dest">
{% for des in destinations_name_list %}
<option>{{des|safe}}</option>
{% endfor %}
</select>
</td>
</tr>
</table>
This is my views.py:
def selection_filter(request,prod):
destination_objs = Destination.objects.filter(product=prod)
destination_name = destination_objs.values_list('name')
destination_name_list = []
for iter_name in destination_name:
destination_name_list.append(iter_name[0].encode('utf-8'))
return render_to_response('temp/test.html',
{"destination_name_list" : destination_name_list},
)
I think the point you might be misunderstanding is that your Django template for your whole page will not be re-rendered "magically". In Django's standard model-view-template paradigm, the template is rendered just once, upon the initial request. The way you've written it, unless there's a default product selection, you're going to have an awkward empty <select> in the first render. But ignoring that...
For a problem like this, you need two views: one for rendering the whole page, and one for providing the Ajax response. There are two main options for the second view: 1) return JSON for interpretation/rendering by your script post-response or 2) return a fully rendered HTML fragment for direct insertion into your DOM. In this case, I'd just go for option 2.
I recommend looking into Jquery, as it makes Ajax and DOM manipulation super simple.
If you've got Jquery, it's as simple as adding to your script:
$.get('/destinations/' + prod)
.done(function (html) {
$(#dest).html(html);
});
(You can do the same thing without Jquery too, but it requires a bit more wrangling)
Your test.html file should contain:
{% for des in destinations_name_list %}
<option>{{des|safe}}</option>
{% endfor %}

How to dynamically access objects in a twig template with symfony2

I don't even know what title use to this question. I'm starting with web programming and I don't even know what technology should I use to do this.
I have a database with doctrine in symfony2. This database has galleries and each gallery has images (two tables OneToMany relation).
I'm passing an array of galleries to a twig template where I show them in a select, so I can choose one and add more images to the gallery, add new galleries or delete them using the submit buttons.
That is working now with this template:
<select class="listGalleries" id="listGalleries" name='id' size="10">
{% for gallery in galleries %}
<option value="{{gallery.id}}" >{{gallery.name}}</option>
{% endfor %}
</select>
That goes inside the form.
Now, what I want to do is everytime I do click in one item of the select, show, in the same webpage, all the images of the gallery selected.
I don't know which technology should I use. Can I do it with twig? Do I have to learn ajax? I guess I have to go to the database to read the data of the pictures that belongs to that gallery, but I don't know how to do it or if symfony2 offers me a better solution.
Every advice will be appreciated.
"Dynamically" can't be done in twig, since after its rendering there is no way to change the output.
You can do in two ways in my opinion:
Use twig to loop within galleries and output them, then use some javascript like bootstrap tabs to display each gallery when changing option. in bootstrap you would do this way (assuming the gallery->images relations is in $gallery->images):
<div class="tab-content">
{% for gallery in galleries %}
<div class="tab-pane active" id="gallery{{ gallery.id }}">
{% for image in gallery.images %}
<img src="{{ image.url }}" class="img-polaroid">
{% endfor %}
</div>
{% endfor %}
</div>
now using javascript like
$("select#listGalleries").change(function () {
$("select option:selected").each(function () {
$("#gallery" + $(this).attr('value')).tab('show');
});
})
Otherwise you can use ajax to return the gallery images after having selected a gallery from the and render the gallery images somewhere on the page. This could be done in two ways, render the html within symfony and just place the output in the page with javascript or return just a json (using something like this) and create the html within javascript (I personally use a lot pure).

Categories