Javascript syntax error in Django Template when variable value is missing - javascript

I have a Django template with an AJAX menu (where clicking on different menu items reloads a part of the page). Each menu click invokes a Django view function through AJAX and returns some data to be shown on the page.
I am loading all the JS required for all the menu items in the main page only (as I learnt that it is not a good idea for AJAX to return JS in a <div> and then use eval() to execute it). Since I am loading all the JS on the menu's main page only, the data obviously isn't there for other menu options at start since it will come later when the corresponding view is invoked (when the menu option is clicked)
Because of that, code like the one below gives a syntax error on the console since JS is parsed the very first time only.
<script> var data = {{se_data|safe}}; </script>
Now I am not able to use the data returned from the view, even after I click the menu options, since the JS parsing failed in the first place. I tried using if to execute the code only when the corresponding menu option is selected but that too does not work since the parser just parses everything.
I have been trying different methods to get around the issue but cant seem to find an efficient way to solve this. An alternative could be to have the view function return all the data at first only, but I fear that the menu options and the data returned may grow over time, hence delaying the initial load of the main menu page.
This is the ajax menu's click function:
$(".ent-menu li a").click(function(e) {
e.preventDefault(); // prevent from going to the page mentioned in href
// get the href
var href = $(this).attr("href");
$("#data_container").load(href, function() {
load_data(); //this function uses the data variable defined earlier
});
});
Error I see in the console when loading the menu's main page:
Uncaught SyntaxError: Unexpected token ; at line 1110
data = ;
since the data is not available yet.

As discussed, you should use JSON to send the data from Python to JS; use JSON.parse() to deserialize the data for use in your JS.

Related

Accessing gridview row data CONSISTENTLY from javascript

I have an asp.net webpage that contains a gridview with SQL data bound to it using the DataSourceID property. I want to be able to launch JavaScript from various user events (like button clicks and row clicks in a second gridview) and use JavaScript to read the gv1 data and perform some simple actions. My problem is, some of my JavaScript calls see the data in the gridview, but many times all I see in the gridview is a header (no rows of data!).
For example, if I put a call to JavaScript inside Page_Load() using
ScriptManager.RegisterStartupScript(Me, Page.GetType, "Script", "jsPageLoadFirst();", True)
then I always see the gridview data on the initial page load, and also on some postbacks. On other postbacks however the gridview has been stripped and all I see is the gridview header (rows are undefined).
Similarly, if I setup a call to JavaScript in the html body as
<body id="mybody" onload="JavaScript:myJSsub();">
the JavaScript sub never sees the gridview data; only the header, but no rows. I THOUGHT that the client onload event only occurred after the page was fully loaded (including all data binding!) but apparently not! Note that I always see the gridview data showing on the webpage, even right before I click a button to invoke JavaScript, so it's a mystery to me as to why the gridview data sometimes gets stripped!
I've been pulling my hair out for days trying to figure this one out. Can anyone tell me what I'm doing wrong, and how I can make sure the gridview row data is always available to my JavaScript subs, no matter where (or how) I launch them?
Thanks!
-tom
10/7 update: Here's a little bit more info, plus a possible work around I've come up with today using a hidden field. First, I'm primarily accessing the gridview data in JavaScript using calls to document.getElementById("gv1"). So to start things off, since all the gridview data is available to the JavaScript sub I fire from the first server PageLoad event, I tried saving the gridview data in both a global variable "gvar1" and also in a hidden field on my page "hf1". Here is what my JavaScript looks like:
function jsPageLoadFirst() {
// Save gv1 to a global variable
gvar1 = document.getElementById("gv1");
// *** Also save gv1's html to a hidden field
document.getElementById("hf1").value = document.getElementById("gv1").innerHTML;
}
Now in the JavaScript sub I trigger from the onload() event of the body, I check the values of all three. I always find that 1) document.getElementById("gv1") shows only the gridview header (but no rows), 2) gvar1 is undefined and 3) hf1 looks fine - all row data is present. Similarly when firing javascript from server Postback pageloads, sometimes document.getElementById("gv1") shows all the gridview data, but sometimes it only shows the gridview header but no row data. Can someone explain to me why document.getElementById("gv1") does not always show the row data? I think if I understood this, I could see my way clear to get the rest of my code working. Thanks!!!

create onClick content after the click in the html

I am writing a django template and I am working woth lot of data. I have all the data in the django object with me in template. I want to create tables on button click so i have used
$(document).ready(function()
{
$(document).on("click", ".open-infoDialog", function ({{users}}) {});
});
I am creating tables inside the above function
But whatever is there in the function is already created before the click of the button. Is there a way i can create the code in the html after the button click.
The problem is happening as there is large amount of data it takes ages to see the page.
The answer is no, not within the template. Your template variables are filled in on the server. By the time the browser gets it, everything is filled in.
If you want to get hold of some data only after the user clicks, you will need to make a special view which returns the extra data you want (either as json or however you like). Then in your click handler you can do an ajax request to that view.
Think of this problem in terms of where the data is located and when it travels.
1) You would like to first load a page into the users browser, which does not contain any of this large data.. it only contains a button for the user to press to get the large data. The way this happens is, the browser connects to the server/url, django looks at urls.py and decides what view to execute. The view then, using the template, generates the html which diplays the button.. which travels back to the browser and is displayed.
That is the end of the request and your first template and first view have done their job and exited.
2) Then, only if the user presses a button, you want to load the data up into the existing page. This is ANOTHER REQUEST. When the button is pressed, the click handler must execute code which makes another connection to the server, a different url, different view, different template.. since you are returning different data. Then in your javascript you take this new html and load it into the part of the existing page that you would like...
It's classic AJAX, it is two different requests but instead of loading a whole new page you're only loading part of it. Since you are not clear on how this works just yet the easiest way to do this is to just write two totally separate Django views each with their own template, own url etc. Then you can test each one separately. One returns the page with the button and the javascript but no data. The other returns just the part of the page that would normally contain the data. Then once you have got that working, write the jQuery/javascript code which loads the data.
For example, in your first template:
<script>
$(document).ready(function()
{
$(document).on("click", "#loadusers", function () {
$( "#user_select" ).load( "/myapp/loadusers/" );
});
});
</script>
<form>
<input type="button" id="loadusers" value="Load User Choices">
<select id="user_select" name="user"></select>
</form>
In your loadusers template:
{% foreach user in users %}
<option value="{{user.pk}}">{{user}}</option>
{% endfor %}
This would result in the first view rendering a page which contains an empty select. If you then click the button it will load the options from the second view.
Try the following code:
$(document).ready(function()
{
var template = {{users}}; // Storing the template in a variable
$(document).on("click", ".open-infoDialog",
function (l_template) {
return function() {
// This function will be called on click.
// Do the stuff here. using l_template
};
}(template)
});
The template will contain your data. Here, We are returning a function instead of value.
That returned function will be called on click callback.
You can use l_template in the returned function.

jQuery event triggering multiple times because of multiple javascript inclusions/requires

I have a problem here and it's making me mad. I maintain a legacy php system. It's badly organized, no frameworks are used and a lot of other problems, for example, at least 5 different query versions are used in different parts of the system.
So my problem right now is this, I have a search form, when a button is clicked it shows a list of items, lets call this a list of "A" objects. In each A item, there is an expand /toggle button to show the B items that belong to A (this is done using ajax, by setting a specific div's html to the ajax response). Then each B also has an expand/toggle button to show the C items that belong to B.
What is happening: I click to search, all A are shown. I click on the expand to show the B items of one A object, they are shown. I click B to hide it, it hides and then show again. If I click it one more time, it hides, shows and hide. So it is like every ajax request is including the javascript code and running it.
I think this is pretty much an organization problem, I am not knowing how to include/require and insert the js correctly. I've been trying to solve this issue since yesterday and I think I've seen the code so many times that I can't think out of the box.
So here's some of the organization (I changed the names because there are some business rules):
SearchResults.php -> Declares a class that has static methods to print out HTML of each item A, B and C and some other helper methods. To make stuff "work", it has a require "js.php"; otherwise the A expand button does not work because it does not exist at the time the js is executed and no function is bound.
search.php -> the HTML form with all the search options, nothing important.
js.php -> the javascript stuff, why is it in a ".php"? I can't even remember, but I think it is because with the php I can require/include:
<script type="text/javascript" src="../util/js/jquery/1.8.1/jquery.min.js"></script>
<script>
var jQ = jQuery.noConflict(true);
jQ(document).ready(function() {
jQ(".loadBfromA").click( function(e) {
if (div.style.display == 'none')
alert("was hidden, now is showing");
//call ajax_B.php
//response is put into the div using .html(data)
else
alert("was showing, now is hidden");
...
ajax_B.php -> the ajax that access the database and echoes html code that will be put into the A items div. Here I have to require SearchResults.php, because I call some methods of the class.
Why is it including the jQ(document).ready being executed multiple times? How can I fix it? Is there any way I can reorganize the code?
Is the ajax_B.php, when requiring SearchResults.php, including the js again because SearchResults.php requires js.php? Does this gets echoed and then put into the div?
I can't make a fiddle of this because there is ajax included.
Edit:
I have tried unbind("click").bind("click", ()) and it didn't work.
It looks like the event is being bound multiple times on jQ(".loadBfromA")
I know this is not the cleanest solution out there, but you could rewrite the actual binding:
jQ(".loadBfromA").bind('click.loadbfroma', function(e) {
// Do your code
$(this).unbind('click.loadbfroma');
});
That way you can at least be sure that only one event is bound at all times, no matter how many times the code snippet is being included. I know this doesn't really help you with the underlying issue but it's a start.

How do I store local javascript results from an ajax call to be shown later?

I have an ajax query that returns an array . . I only show the first 20 items in the array right now but i have now added a link for "Show All" after I displayed those first results.
When the user clicks Show All i want to display all of the items in the array.(either inline or in a dialog (but that implementation shouldn't matter)
I want to avoid having to go back to the server to get the full list since I already retrieved the full list from the first ajax call . . where is the best way to locally store this array to be accessed later.
Save the array in a variable, or possibly attached as a data element to something on the DOM. Then, when your "Show All" event fires, read from that array and rebuild your display.
<div id="myArrayDisplay">
</div>
<script>
$(function () {
$.getJSON("backendCode.php", function (jsonData) { // assumes your array arrives as a response from a JSON-based Ajax request to some server code
$("#myArrayDisplay").data("arrayObj", jsonData);
});
});
</script>
Obviously I'm not showing how you would display the contents of the array in the above code, just how I would store it.
I think the easy way you can do is to put the full list data into a hidden input textfield
I don't know about the best way, but the simplest is using a global variable.
Define it here:
$(document).ready(function(){
$.myArray = [];
})
And use it like so:
function myFunction(){
alert($.myArray[0]);
}
More info about $(document).ready.
On the other hand, you could create two separate fields, one with the initial info and one with the rest, making the second one invisible. When the user clicks "Show more" you can show the hidden one.
More information about .show().

dropdown menu populated from a database in a client side page

I want to populate the data from a database using client side programming either HTML or javascript. I looked online and got lot of sites giving examples on server side i.e. JSP,ASP or PHP for creating the dropdown menu. I know the simple syntax for creating the HTML dropdown menu and in other languages. But I don't know how to populate that HTML dropdown menu values from the database. Any technique which either gets the data from the JSP page which fetches the data from the database and on selecting a single item triggers a query to JSP page which again fetches data from the database can work for me.
Problem: I want to access the database fields from a html page. The dropdown list of html page should be populate from the database and on selecting a specific value it should get data specific to that option.
Any ideas or links to the sources I should look at.
Just so you can get a general idea of the mechanism: How about an Ajax-call triggered by an event listener like this (could also use click event or whatever):
After the html-document is loaded, add an event listener to the watched element (here onchange) and call a function when the event is triggered:
$(document).ready(function() {
$('#watchedElement').change(callAjaxFunction());
});
Function for Ajax-call:
In the data variable you can send information to the server to decide there which options to send back. Easiest way (though quick and dirty) would be to return (like "echo" in php) the option values in plain text/html and replace the old option-elements with this. I prefer the JSON-ways described in the link from your question's comment, since you have a lot more control on the data but for a first impression you could try if the mechanism works for you in general:
function callAjaxFunction() {
$.ajax({
type: "POST",
url: url,
data: { "selectedValue": $('#watchedElement').val() }
success: function(data) {
$("#idOfSelectElement").html(data);
}
dataType: "HTML"
});
}
Just for testing purposes without any evaluation of the value sent to the server you could send back two dummy options like this (example is php file for simplicity and you even could use an html-file that only contains the text itself):
<?php
echo "<option value='test1'>Test1</option>" .
"<option value="test2">Test2</option>";
?>
Still it's probably better to go the JSON way and add element by element, which makes dbugging and stuff way easier later on.

Categories

Resources