this is my javascript function :
<script>
function text() {
var i = new Array();
{% for content in table %}
i[{{content.id}}]= document.getElementById('checkbox{{content.id}}').checked;
{% endfor %}
return i;
}
</script>
as you can see I have some django template code in It. how to prevent caching of my script ?
I see this but It didn't solve my problem !
I'm not sure I've understood properly, but as far as I can tell this has nothing to do with caching: it is a matter of understanding when templates are rendered vs when scripts are executed.
This script is contained in a template. That template is rendered on the server side. Therefore, the script will be generated - and sent to the browser - with the values of content as they were at that point.
If you have an Ajax function which later updates something in the HTML page, this script will not care at all, because you have done nothing to update it - again, the values in the script were hard-coded when the template was sent to the browser.
You probably don't want to do it this way at all. Instead, you should find or define a parent element that contains all the checkboxes - a div or table row, for example - and then dynamically iterate through all descendants of that element to find the value of any checkboxes. You can then call this script from your Ajax function to update the values when the content changes.
Related
I wanted to add a onClick function when I click on the link.
Basically, whenever I click on "Click" it should add the liquid code in the div.
What it is doing is, adding a liquid code yes, but just the code and not the content it should be adding with the liquid code. Here is my code:
Index
Click me!
<div id="result"></div>
<script src="http://code.jquery.com/jquery-latest.min.js"
type="text/javascript"></script>
<script>
$("#myLink").on("click", function(){
$("#result").load("liquidcode.html");
});
</script>
liquidcode.html
{% include 'cod-checker' %}
What I get after clicking on "Click Me" is this {% include 'cod-checker' %}
Liquid is rendered server-side so you will not be able to render liquid after the page loads using jquery. You can circumvent this issue by inserting whatever code resides in 'liquidcode.html' from the very beginning, but hiding it by adding a class to the div with display set to none. You can then remove that class when the user clicks on "Click".
Answering here to expand my comment, since there was a request for actual code from the question author.
My comment, which is the basis of the anser:
I would suggest making an AJAX request on click then, to an endpoint
from your server. Make that endpoint provide a parsed html version of
your liquidcode.liquid (just assuming the filename here).
On client side, jQuery-aided AJAX looks like this:
$("#myLink").on("click", function() {
$("#result").load("myAwesomeServerEndpoint", function() {
console.log('BOOM, server-parsed HTML was successfully loaded inside #result');
});
});
As for server side, I really have no clue what framework you are using. (Ruby on Rails?)
In an MVC fashion, you need to register a route called "myAwesomeServerEndpoint".
Assign a Controller to that route, say "myAwesomeServerController".
This Controller is not supposed to do much, it should just render your liquicode.liquid template.
Pseudocode for your controller (since I dont know Ruby on Rails):
return HtmlResponse(render("liquicode.liquid"));
Make sure that the response is sent as HTML and that the route is exposed to AJAX requests, and that should be it.
Again, this is not a solution but just a rough concenpt
I'm using varnish+esi to return external json content from a RESTFul API.
This technique allows me to manage request and refresh data without using webserver resources for each request.
e.g:
<head>
....
<script>
var data = <esi:include src='apiurl/data'>;
</script>
...
After include the esi varnish will return:
var data = {attr:1, attr2:'martin'};
This works fine, but if the API returns an error, this technique will generate a parse error.
var data = <html><head><script>...api js here...</script></head><body><h1 ... api html ....
I solved this problem using a hidden div to parse and catch the error:
...
<b id=esi-data style=display:none;><esi:include src='apiurl/data'></b>
<script>
try{
var data = $.parseJSON($('#esi-data').html());
}catch{ alert('manage the error here');}
....
I've also tried using a script type text/esi, but the browser renders the html inside the script tag (wtf), e.g:
<script id=esi-data type='text/esi'><esi:include src='apiurl/data'></script>
Question:
Is there any why to wrap the tag and avoid the browser parse it ?
Let me expand upon the iframe suggestion I made in my comment—it's not quite what you think!
The approach is almost exactly the same as what you're doing already, but instead of using a normal HTML element like a div, you use an iframe.
<iframe id="esi-data" src="about:blank"><esi:include src="apiurl/data"></iframe>
var $iframe = $('#esi-data');
try {
var data = $.parseJSON($iframe.html());
} catch (e) { ... }
$iframe.remove();
#esi-data { display: none; }
How is this any different from your solution? Two ways:
The data/error page are truly hidden from your visitors. An iframe has an embedded content model, meaning that any content within the <iframe>…</iframe> tags gets completely replaced in the DOM—but you can still retrieve the original content using innerHTML.
It's valid HTML5… sort-of. In HTML5, markup inside iframe elements is treated as text. Sure, you're meant to be able to parse it as a fragment, and it's meant to contain only phrasing content (and no script elements!), but it's essentially just treated as text by the validator—and by browsers.
Scripts from the error page won't run. The content gets parsed as text and replaced in the DOM with another document—no chance for any script elements to be processed.
Take a look at it in action. If you comment out the line where I remove the iframe element and inspect the DOM, you can confirm that the HTML content is being replaced with an empty document. Also note that the embedded script tag never runs.
Important: this approach could still break if the third party added an iframe element into their error page for some reason. Unlikely as this may be, you can bulletproof the approach a little more by combining your technique with this one: surround the iframe with a hidden div that you remove when you're finished parsing.
Here I go with another attempt.
Although I believe you already have the possibly best solution for this, I could only imagine that you work around it with a fairly low-performance method of calling esi:insert in a separate HTML window, then retrieve the contents as if you were using AJAX on the server. Perhaps similar to this? Then check the contents you retrieved, maybe by using json_decode and on success generate an error JSON string.
The greatest downside I see to this is that I believe this would be very consuming and most likely even delays your requests as the separate page is called as if your server yourself was a client, parsed, then sent back.
I'd honestly stick to your current solution.
this is a rather tricky problem with no real elegant solution, if not with no solution at all
I asked you if it was an HTML(5) or XHTML(5) document, because in the later case a CDATA section can be used to wrap the content, changing slightly your solution to something like this :
...
<b id='esi-data' style='display:none;'>
<![CDATA[ <esi:include src='apiurl/data'> ]]>
</b>
<script>
try{
var data = $.parseJSON($('#esi-data').html());
}catch{ alert('manage the error here');}
....
Of crouse this solution works if :
you're using XHTML5 and
the error contains no CDATA section (because CDATA section nesting is impossible).
I don't know if switching from one serialization to the other is an option, but I wanted to clarify the intent of my question. It will hopefully help you out :).
Can't you simply change your API to return JSON { "error":"error_code_or_text" } on error? You can even do something meaningful in your interface to alert user about error if you do it that way.
<script>var data = 999;</script>
<script>
data = <esi:include src='apiurl/data'>;
</script>
<script>
if(data == 999) alert("there was an error");
</script>
If there is an error and "data" is not JSON, then a javascript error will be thrown. The next script block will pick that up.
I am currently using Jquery's .load() function to insert a page fragment asynchronously. In the URL that I am loading the page fragment from, I also set a Javascript global variable value (in the script tag).
var loaded_variable = 'value1'
Is there a way I can use the .load() function to insert the page fragment AND retrieve the value of loaded_variable, something like the following code:
function loadProducts(url) {
$('#mainplace').load(url + ' #submain', function() {
current_variable = loaded_variable;
});
}
I am aware that script blocks are used when a selector expression is appended to the URL, so if the .load() function won't work, I'm open to other Jquery functions that can accomplish this.
Extra Info: The URL that I am loading from is written in HTML and Python (Web2py); the same Python variables are used to render the page fragment and set the loaded_variable value.
If you want to both fetch a fragment from a page and execute a script on it, you'll need a different approach. This is a bit hacky, but works.
$.ajax({url: 'fetch_page.html', dataType: 'text'}).done(function(html) {
var dom = $('<html />').prop('innerHTML', html);
$('body').append(dom.find('body p'));
$('head').append(dom.find('script'));
});
That fetches a p tag from our fetched pages and inserts it into the body of the parent page. It also executes any scripts in the fetched page.
If you're wondering about the prop('innerHTML... bit, that's because if I'd used jQuery's .html() method, it sanitises the input string and so we don't get the result we want.
My first thought was a document fragment, but you can't insert an HTML string into a doc frag - you have to append via DOM methods. Even then in this case it wouldn't really offer any saving over simply using an element to parse the dom (dom) as I have.
Bit hacky, as I say, but works.
I think I have a similar question. I have create a page that will hold a newsletter sign up. I want to load this page at the bottom of every blog post on my site. I don't want it in the footer because it is specific to my blog page and I want the ability to edit it without having to edit every blog post.
I created this page with the url /blog-newsletter-form which includes some code from an Email CRM.
I then added a div with a "blog-newsletter-form" class at the end of my blog posts and put the following in the page header to load the content from the first page section inside my blog posts.
$( document ).ready(function() {
$('.blog-newsletter-form').load("/blog-newsletter-signup #page .page-section:nth-of-type(1) .content");
});
This worked great except.. the load function is stripping the script from the newsletter page which is required for my newsletter form to work.
How do I load a page fragment but also keep the script for the newsletter. I tried using your sample code above and couldn't get it to work.
I have a Django website that retrieves scores of various items. I would like to make the score appear when a user clicks on a link. The problem is, how do I create this functionality when all of my Jquery code is located in the head?
For example, I have the following code in my head:
$(document).ready(function() {
var $addedElem = $('<p>New Element</p>');
$('.display').one('click', function() {
$addedElem.hide().appendTo("#container").fadeIn("slow");
});
});
Where it defines addedElem, I would like it to add the "score" that the view gives to me. So, I would normally be doing this:
{{ score }}, but how would I add this to addedElem if I do not have access to it? I am using Django's templating system, so I only have access in the innermost body elements and not the head.
Base template have access to context of its inherited templates, {{ score }} will work. You should of course handle the situation when there is no score provided.
If you want this code only for a particular page, you can define {% block head_ext %}{% endblock %} in base template and override it in child template. It's ok to call $(document).ready() more than once.
First of all I would like to say that while this is the first time i post here these boards have helped me much.
With that said, I have got a strange issue regarding AJAX and scripts.
You see, in my web application i used custome JS context menus. Now each of them menus is implemented with specific features depending on the object and if the object exists.
E.x : if we got an upper menu place holder but no upper menu the context menu will have one option which is "add menu".
But say we already have the upper menu the context menu will have different options such as "edit menu" etc...
so far so good, however, say we have an upper menu place holder and no menu and then we added the menu (still no refresh on the page) i need to generate a new context menu and inject it right? so i do just that along with the new menu i just built.
all that code goes into the SAME div where the old context menu script and upper menu place holder were so basicaly they are overwriten.
Now the menu itself is in HTML so it overrides the current code the JS however acts wierd and will show now 2 context menus the old one and the new one even though i overwrite it's code.
I need to some how get rid of the old context menu script without refreshing the page.
Any ideas?
P.S
all the JS are dynamicaly generated if that makes any difference (i dont think it does.)
Well after some head breaking i figured it out..
(the problem not the solution yet) this is the ajax function right?
$.ajax({
type: "GET",
url: "../../../Tier1/EditZone/Generate.aspx?Item=contentholder&Script=true",
dataType: "html",
success: function (data) {
$('#CPH_Body_1_content_holder').html(data);
}
});
now they function uses a page with an event handler, that event handler reutnrs the data as followed response.write(answer) it just hit me that when you use response.write it sends the code after it's been compiled and ran in our case at page Generate.aspx.
so the script will run but not in the page i intended it to run and because of that i cannot overwrite it... how silly of me.
what i think ill do it return the data as an actualy string and then and only then inject the code into the container div.
ill let you folks know if that works out.
cheers and thanks for the advice these forums rock.
No matter what anyone says, do not use EVAL. It's evil and will give you memory issues if used more than a few times on a page.
See my soluition here: trying to call js code that is passed back from ajax call
Basically, create a div with the ID of "codeHolder" and voila. You'll basically want to pass your HTML and JS back to the AJAX receiver (separated by a separator), parse it on the JS side, display the HTML and put the JS Code in your javascriptCode variable.
//Somehow, get your HTML Code and JS Code into strings
var javascriptCode="function test(){.....}";
var htmlCode="<html>....</html>";
//HTML /////////////////////////////////////////
//Locate our HTML holder Div
var wndw=document.getElementById("display");
//Update visible HTML
wndw.innerHTML = htmlCode;
//Javascript ///////////////////////////////////
//Create a JSON Object to hold the new JS Code
var JSONCode=document.createElement("script");
JSONCode.setAttribute("type","text/javascript");
//Feed the JS Code string to the JSON Object
JSONCode.text=javascriptCode;
//Locate our code holder Div
var cell=document.getElementById("codeHolder");
//Remove all previous JS Code
if ( cell.hasChildNodes() )
while ( cell.childNodes.length >= 1 )
cell.removeChild( cell.firstChild );
//Add our new JS Code
cell.appendChild(JSONCode);
//Test Call///////////////////////////////////////
test();
This code will replace all previous JS code you might have put there with the new JS Code String.
Thanks for the replies.
Dutchie - that's exactly what I did. now the thing is the HTML is properly overwritten (I didn't use append I overwrote the entire div) and yes the javascript just keeps on caching...
I tried to disable browser cache and still the problem persists i get multiple context menu per item the more I ran the ajax function...
Jan,
My AJAX function builds a div tag and script tags and places them into another container div tag in the page.
What's suppose to happen is that every time the AJAX runs the code inside the container div is overwritten and you get an updated version.
the div inside the container div is overwritten yet the script tags somehow are cached into the memory and now each time the out jQuery function calls the context menu i get multiple menus...
I don't think code is needed but I will post it tomorrow.
Any ideas?