Update a variable dynamically in flask - javascript

I m working with flask and need to make a python variable appear on a HTML page & update it in real time without the need to refresh . i have searched but couldn't do it. To find a solution the simple way i have created in the python script a time variable that should be updated in the page dynamically.Here is my code:
<script>
$SCRIPT_ROOT = {{ request.script_root|tojson|safe }};
(function(){
$.getJSON(
$SCRIPT_ROOT+"/get_data",
function(data) {
$("#testt").text(data.time);
}
setInterval(arguments.callee, 1000);
);
});
</script>
<span id="testt">?</span>
import datetime
from flask.app import Flask
from flask.json import jsonify
app=Flask(__name__)
#app.route('/get_data', methods=['GET'])
def get_data():
return jsonify(time=str(datetime.datetime.now().time()))
if __name__=="__main__":
app.run(debug = True, host='0.0.0.0')
EDIT: In my solution the time only updates when i refresh the page . want it to update in real time.

You don't specify what's your problem exactly ("doesn't work" doesn't really help) so this can be a wild-guess answer at best.
First point, you define an anonymous function but never call it, so the chances it ever gets executed are strictly equal to zero. If you want that function to be executed when your dom's ready (which is the sane thing to do since it references an element of the dom that is defined after the function, you can use $(document).ready(yourfunc), ie:
$(document).ready(function(){
$.getJSON(
$SCRIPT_ROOT+"/get_data",
function(data) {
$("#testt").text(data.time);
}
setInterval(arguments.callee, 1000);
);
});
Also you certainly don't want to call window.setInterval() from the function that itself (which would then be called again an again each time the function is called), so it should rather be something like:
$(document).ready(function(){
function _update_time() {
$.getJSON(
$SCRIPT_ROOT+"/get_data",
function(data) {
$("#testt").text(data.time);
});
}
// do a first call at load time
_update_time();
// then repeat it every second
window.setInterval(_update_time, 1000);
);
});
Also, I'm not a Jinja2 expert (since it's Flask and from the look of it I assume Jinja2 templating), but this:
$SCRIPT_ROOT = {{ request.script_root|tojson|safe }};
seems uncorrect to me.
First, you want $SCRIPT_ROOT to be a string, so you have to quote it:
$SCRIPT_ROOT = "{{ request.script_root|tojson|safe }}";
Then I don't see the point of the tojson and safe filters here - safe tells the template engine to not html-escape your variable but an url seldom contains html markup, and jsonifying a simple string doesn't make sense to me.
Once again it's wild-guess at best and possibly completely wrong. If you want better answers you will have to do your homework and post some more informations, including:
the rendered html (well the relevant part that is)
any error message in your browser's inspector window / debug toolbar / however it's called in your browser.

You can update your page dinamically using a websocket.
There is a project named Socket.Io which is implemented by Flask to work with websockets.
You can read the documentation here : https://flask-socketio.readthedocs.io/en/latest/ and watch a quick example to understand the concepts here : https://www.youtube.com/watch?v=RdSrkkrj3l4

Related

Django custom template tags in javascript

I have a custom template tag that returns suppose name of a student and roll number if passed as an argument id of the student.
#register.inclusion_tag('snippet/student_name.html')
def st_name_tag(profile, disp_roll=True, disp_name=True):
#some calculations
return {'full_name':student.name,
'roll':student.roll_number,
}
The template(included) consists of some Html file which is written in a single line(to avoid unterminated string literal error from js).
I simply want to call the st_name_tag from inside the JS function.
My JS looks like:
{% load profile_tag %}
<script type = "text/javascript">
eventclick : function(st){
var div = ('<div></div>');
var st_id = st.id;
if (st.status == 'pass'){
div.append('<p>Student Name:{% st_name_tag '+st_id+' %}</p>');
}
}
So far I tried the above method along with removing the + and '' signs from st_id varaible. That hasnt helped me at all. Help Please!
You are trying to render a template based on the interaction by user. The first happens on the server (server-side as it is often referred to), and the latter happens on the user's browser.
The order that these happen is first to render the template on server, send and present in browser, then user interacts with js. Because of this fact, as I mentioned in the comment, it is not possible to affect the template rendered within javascript.
I would recommend you to use ajax in order to accomplish this. Whenever an iteraction occurs, you asynchronously make a request to the server to present you with new data.

ScriptManager.RegisterStartupScript Keeps adding script blocks multiple times

I have an update panel with a timer control set up to automatically check for some data updates every minute or so.
If it sees that the data updates, it is set to call a local script with the serialized JSON data.
ScriptManager.RegisterStartupScript(UpdateField, GetType(HiddenField), ACTION_CheckHistoryVersion, "updateData(" & data & ");", True)
where "data" might look something like
{
"someProperty":"foo",
"someOtherProperty":"bar",
"someList":[
{"prop1":"value"},
{"prop2":"value"}, ...
],
"someOtherList":[{},...,{}]
}
"data" can get quite large, and sometimes only a few items change.
The problem I am having is this. Every time I send this back to the client, it gets added as a brand new script block and the existing blocks do not get removed or replaced.
output looks something like this:
<script type="text/javascript">
updateData({
"someProperty":"foo",
"someOtherProperty":"bar",
"someList":[
{"prop1":"value"},
{"prop2":"value"}, ...
],
"someOtherList":[{},...,{}]
});
</script>
<script type="text/javascript">
updateData({
"someProperty":"foo",
"someOtherProperty":"bar",
"someList":[
{"prop1":"changed"},
{"prop2":"val"}, ...
],
"someOtherList":[{},...,{}]
});
</script>
<script type="text/javascript">
updateData({
"someProperty":"foos",
"someOtherProperty":"ball",
"someList":[
{"prop1":"changed"},
{"prop2":"val"}, ...
]
});
</script>
with a new script block being created every time there is a change in the data.
Over time the amount of data accumulating on the browser could get potentially huge if we just keep adding this and I can't imagine how most people's browser would take it, but I don't think it could be good.
Does anyone know if there is a way to just replace the code that has been sent back to the browser rather than continuously adding it like this?
I came up with a hack that seems to work in my situation.
I am using jQuery to find the script tag that I am creating and remove it after it has been called.
Here is an example:
First I generate a guid:
Dim guidText as string = GUID.NewGuid().ToString()
I create a function like the following:
function RemoveThisScript(guid){
$("script").each(function(){
var _this = $(this);
if(_this.html().indexOf(guid)>-1)
_this.remove();
});
}
Then I add the following code to my output string:
... & " RemoveThisScript('" & guidText & "');"
This causes jQuery to look through all the scripts on the page for one that has the GUID (essentially the one calling the function) and removes it from the DOM.
I would recommend to use web service with some webmethod which you will call inside window.setInterval. In success handler of your webmethod (on client side) you can just take response and do whatever you want with it. And it will not be saved in your page (well, if you will do everything wrong). Benefit is that you will minimize request size(updatepanel will pass all your viewstate data, which could be large enough) and will limit server resources usage (update panel is causing full page live cycle, suppose slightly modified, but anyway - all those page_load, page_init, etc...) and with web service you will only what you need.
Here is an article where you can see how it could be created and used on client side. Looks like good enough.

Grails - rendering div with a javascript call within a remoteSubmit

I have a situation where I want to hit a button in the GSP (actionSubmit) and update a div when I finish the call (which includes a call to a javascript function). I want to ultimate end up in the controller rendering the searchResults parameter and the div with the results (which is currently working).
Problem is, I need to (presumably) wrap my actionSubmit in a remoteForm. But how do I:
1) Run the javascript method already existent in the onClick
2) Render the page in the controller.
If I try both wrapped in a controller, I finish the remoteForm action and the javascript action "hangs" and never finishes.
Any ideas?
List.gsp
<g:actionSubmit type="button" value="Ping All" onclick="getIds('contactList');"/>
function getIds(checkList)
{
var idList = new Array();
jQuery("input[name=" + checkList + "]:checked").each
(
function() {
idList.push(jQuery(this).val());
}
);
$.ajax({
url: "pingAll",
type:"GET",
data:{ids:JSON.stringify(idList)}
});
}
controller:
def pingAll() {
String ids = params.ids
if(ids == "[]") {
render(template:'searchResults', model:[searchResults:""])
return
}
def idArray = contactService.formatIDString(ids)
idArray.each {
def contactInstance = Contact.get(Integer.parseInt(it))
emailPingService.ping(contactInstance)
}
/**
* Added this on 3/13. Commented out line was initial code.
*/
def searchResults = contactSearchService.refactorSearchResults(contactSearchService.searchResults)
render(template:'searchResults', model:[searchResults:searchResults, total:searchResults.size()])
}
You have a couple options:
1) You can avoid using the Grails remote tags (formRemote, remoteField, etc.), and I really encourage you to explore and understand how they work. The Grails remote tags are generally not very flexible. The best way to learn how they work is to just write some sample tags using the examples from the Grails online docs and then look at the rendered page in a web browser. All the tags do generally speaking are output basic html with the attributes you define in your Grails tags. Open up your favorite HTML source view (i.e. Firebug) and see what Grails outputs for the rendered HTML.
The reason I say this is because, the code you've written so far somewhat accomplishes what I've stated above, without using any GSP tags.
g:actionSubmit submits the form you are working in using the controller action you define (which you haven't here, so it runs the action named in your value attribute). However, you also have an onClick on your actionSubmit that is running an AJAX call that also submits data to your pingAll action. Without seeing the rest of your code and what else is involved in your form, you are submitting your form twice!
You can simply just not write actionSubmit, and simply do an input of type button (not submit) with an onClick. Then in your javascript function that runs, define a jQuery success option for your AJAX call
$.ajax({
url: "pingAll",
type:"GET",
data:{ids:JSON.stringify(idList)},
success:function(data) {
$('#your-updatedDiv-id-here').html(data);
}
});
2) If you want to use the GSP tags, I think you are using the wrong one. Without knowing the full extent of your usage and form data involved, it looks like g:formRemote, g:submitToRemote, and g:remoteFunction could serve your purposes. All have attributes you can define to call javascript before the remote call, as well as defining a div to update and various event handlers.

I want to request JSON inside of a WordPress page

For the last few hours I've been trying to set up this http://code.google.com/apis/books/docs/dynamic-links.html on a WordPress blog. Google's API sends back a JSON response (which is supposed to be "put" into _GBSBookInfo variable). However, that variable never is assigned so my javascript callback function explodes saying the variable doesn't exist. So far, all of my javascript is in the WordPress header.
I tried this outside of WordPress and it works fine.
This is the static page:
<script src="http://books.google.com/books?bibkeys=0307346609&jscmd=viewapi&callback=response_handler">
This is the handler:
function response_handler(data) {
var bookInfo = _GBSBookInfo["0307346609"]; // the var that doesn't exist
document.getElementById("test123").innerHTML = bookInfo.thumbnail_url;
}
Thanks for any help in advance, WordPress has been extremely frustrating by limiting so much! If I'm doing anything stupid please say so, I'm a new javascript programmer.
EDIT:
I've used firebug so far to identify the problem to be: the _GBSBookInfo variable never gets "created" or "exists". I'm not sure how javascript works at this level. Hopefully this helps.
ERRORS:
Error: _GBSBookInfo is not defined
Line: 79
Try replacing _GSBookInfo with data, like so:
function response_handler (data) {
var bookInfo = data["0307346609"];
document.getElementById("test123").innerHTML = bookInfo.thumbnail_url;
}
Based on your post, google returns this:
response_handler({
"0307346609": {
"bib_key":"0307346609",
....
"thumbnail_url":"http://bks2.books.google.com/books?somethumbnailstuff"
}
});
... so the above code should work for you.

Calling Django `reverse` in client-side Javascript

I'm using Django on Appengine. I'm using the django reverse() function everywhere, keeping everything as DRY as possible.
However, I'm having trouble applying this to my client-side javascript. There is a JS class that loads some data depending on a passed-in ID. Is there a standard way to not-hardcode the URL that this data should come from?
var rq = new Request.HTML({
'update':this.element,
}).get('/template/'+template_id+'/preview'); //The part that bothers me.
There is another method, which doesn't require exposing the entire url structure or ajax requests for resolving each url. While it's not really beautiful, it beats the others with simplicity:
var url = '{% url blog_view_post 999 %}'.replace (999, post_id);
(blog_view_post urls must not contain the magic 999 number themselves of course.)
Having just struggled with this, I came up with a slightly different solution.
In my case, I wanted an external JS script to invoke an AJAX call on a button click (after doing some other processing).
In the HTML, I used an HTML-5 custom attribute thus
<button ... id="test-button" data-ajax-target="{% url 'named-url' %}">
Then, in the javascript, simply did
$.post($("#test-button").attr("data-ajax-target"), ... );
Which meant Django's template system did all the reverse() logic for me.
The most reasonable solution seems to be passing a list of URLs in a JavaScript file, and having a JavaScript equivalent of reverse() available on the client. The only objection might be that the entire URL structure is exposed.
Here is such a function (from this question).
Good thing is to assume that all parameters from JavaScript to Django will be passed as request.GET or request.POST. You can do that in most cases, because you don't need nice formatted urls for JavaScript queries.
Then only problem is to pass url from Django to JavaScript. I have published library for that. Example code:
urls.py
def javascript_settings():
return {
'template_preview_url': reverse('template-preview'),
}
javascript
$.ajax({
type: 'POST',
url: configuration['my_rendering_app']['template_preview_url'],
data: { template: 'foo.html' },
});
Similar to Anatoly's answer, but a little more flexible. Put at the top of the page:
<script type="text/javascript">
window.myviewURL = '{% url myview foobar %}';
</script>
Then you can do something like
url = window.myviewURL.replace('foobar','my_id');
or whatever. If your url contains multiple variables just run the replace method multiple times.
I like Anatoly's idea, but I think using a specific integer is dangerous. I typically want to specify an say an object id, which are always required to be positive, so I just use negative integers as placeholders. This means adding -? to the the url definition, like so:
url(r'^events/(?P<event_id>-?\d+)/$', events.views.event_details),
Then I can get the reverse url in a template by writing
{% url 'events.views.event_details' event_id=-1 %}
And use replace in javascript to replace the placeholder -1, so that in the template I would write something like
<script type="text/javascript">
var actual_event_id = 123;
var url = "{% url 'events.views.event_details' event_id=-1 %}".replace('-1', actual_event_id);
</script>
This easily extends to multiple arguments too, and the mapping for a particular argument is visible directly in the template.
I've found a simple trick for this. If your url is a pattern like:
"xyz/(?P<stuff>.*)$"
and you want to reverse in the JS without actually providing stuff (deferring to the JS run time to provide this) - you can do the following:
Alter the view to give the parameter a default value - of none, and handle that by responding with an error if its not set:
views.py
def xzy(stuff=None):
if not stuff:
raise Http404
... < rest of the view code> ...
Alter the URL match to make the parameter optional: "xyz/(?P<stuff>.*)?$"
And in the template js code:
.ajax({
url: "{{ url views.xyz }}" + js_stuff,
... ...
})
The generated template should then have the URL without the parameter in the JS, and in the JS you can simply concatenate on the parameter(s).
Use this package: https://github.com/ierror/django-js-reverse
You'll have an object in your JS with all the urls defined in django. It's the best approach I found so far.
The only thing you need to do is add the generated js in the head of your base template and run a management command to update the generated js everytime you add a url
One of the solutions I came with is to generate urls on backend and pass them to browser somehow.
It may not be suitable in every case, but I have a table (populated with AJAX) and clicking on a row should take the user to the single entry from this table.
(I am using django-restframework and Datatables).
Each entry from AJAX has the url attached:
class MyObjectSerializer(serializers.ModelSerializer):
url = SerializerMethodField()
# other elements
def get_url(self, obj):
return reverse("get_my_object", args=(obj.id,))
on loading ajax each url is attached as data attribute to row:
var table = $('#my-table').DataTable({
createdRow: function ( row, data, index ) {
$(row).data("url", data["url"])
}
});
and on click we use this data attribute for url:
table.on( 'click', 'tbody tr', function () {
window.location.href = $(this).data("url");
} );
I always use strings as opposed to integers in configuring urls, i.e.
instead of something like
... r'^something/(?P<first_integer_parameter>\d+)/something_else/(?P<second_integer_parameter>\d+)/' ...
e.g: something/911/something_else/8/
I would replace 'd' for integers with 'w' for strings like so ...
... r'^something/(?P<first_integer_parameter>\w+)/something_else/(?P<second_integer_parameter>\w+)/' ...
Then, in javascript I can put strings as placeholders and the django template engine will not complain either:
...
var url = `{% url 'myapiname:urlname' 'xxz' 'xxy' %}?first_kwarg=${first_kwarg_value}&second_kwarg=${second_kwarg_value}`.replace('xxz',first_integer_paramater_value).replace('xxy', second_integer_parameter_value);
var x = new L.GeoJSON.AJAX(url, {
style: function(feature){
...
and the url will remain the same, i.e something/911/something_else/8/.
This way you avoid the integer parameters replacement issue as string placeholders (a,b,c,d,...z) are not expected in as parameters

Categories

Resources