jquery ajax and html - javascript

Does anybody know how to execute javascript functions in an html that is loaded via ajax? I mean the html contains both plain text and javascript. In my case it seems that only the in-line javascript (eg. onclick="dosomething();return false") gets executed. The pre-defined functions which are wrapped by < script language = "javascript >are unfortunately ignored..
i have search couple articles through the site but the results are either use getScript to load a pure js or use eval. please help me out of this! Thank you very much!

File 1:
<script type="text/javascript">
function test() {
alert('i got loaded dynamically!');
}
</script>
File 2:
$.get('file1.html', function(html) {
$(document).append(html);
test(); // alerts "i got loaded dynamically!"
});
See it in action.

According to the doco, if you use $.ajax and specify a data type of "html", included script tags are evaluated when inserted in the DOM. Make sure your server is returning the correct data type, see Specifying the Data Type for AJAX requests for more info
If that doesn't help, Artem's approach also works well, providing you only make the request once. If you are making the same $.get call over and over, you'll end up with multiple copies of yourFunctionCall in the head, and Strange Things will happen :-)

Look up jquery event delegation, and the .live() method.
http://docs.jquery.com/Events/live#typefn
Event delegation is especially useful and efficient if you're working with a large piece of html that you've added dynamically.

I don't know if this fixes your problem... but if your loaded html also includes a link to jquery's code base, it can cause issues with the child-code not correctly linking with the handle to the jquery object ($).

If I understand you correctly, you receive from your AJAX call plain HTML mixed with javascript code, e.g. with tags. I'm didn't checked it, but you can try to do the following:
$.get( ajaxURL, function( data)
{
$( "head").append( $( data).find( "script"));
yourFunctionCall( );
});

Related

What's the correct way to send Javascript code along with rendered HTTP to a client?

Mid development I decided to switch to server-side rendering for a better control amongst other benefits. My web application is completely AJAX based, no url redirecting, so the idea here is a website that builds itself up
I just couldn't figure out the proper way to send javascript events/functions along with the html string, or should all the necessary javascript always be preloaded in the static files?
Let's say client clicks a pre-rendered button 'open table'
The server will make a query, build the html table and send it back, but this table also needs javascript triggers and functions to work properly, how are these sent, received and executed?
There are a couple of articles that mention to not use eval() in Javascript, is there any way around this? I don't want to have to preload unnecessary events for elements that don't yet exist
The server is Python and the Client is Javascript/JQuery
Theoretical example :
Client Base Javascript :
$("body").on("click", "#open_table", function() {
$.getJSON('/get_table', function(response){
$("#table_div").append(response.html);
eval(response.javascript()); //??
}
});
Python Server(views.py) :
def get_table(request):
data = {}
#String containing rendered html
data['html'] = get_render_table()
#String containing Javascript code?
data['javascript'] = TABLE_EVENTS_JAVASCRIPT
return HttpResponse(json.dumps(data),content_type='json')
Worth noting my question comes from an experimental/learning perspective
Update:
You can use jQuery.getScript() to lazy load JS. I think this solution is as close as you can get to run JS without using eval().
See this example:
jQuery.getScript("/path/to/script.js", function(data, textStatus, jqxhr) {
/* Code has been loaded and executed. */
console.log( data ); // Data returned
console.log( textStatus ); // Success
console.log( jqxhr.status ); // 200
console.log( "Load was performed." );
});
and "/path/to/script.js" could be a string returned from $.getJOSN response.
Also, the documentation for getScrippt() has examples on how to handle errors and cache files.
Old Answer:
Using .on() attaches events to current and future DOM elements.
You can either attache events prior to DOM insertion or attache event after DOM insertion.
So in your example you can do something like:
$("body").on("click", "#open_table", function() {
$.getJSON('/get_table', function(response){
var code = $(response.html);
code.find(".elementToFind").on("click", function (){
// Code to be executed on click event
});
$("#table_div").append(code);
}
});
I did not test the code but I think it should work.
Assuming you can't just set up an event-binding function and then call it from the main script (the JavaScript you need can't be guessed ahead of time, for example) then one really easy way is just to append the JavaScript to the bottom of the returned HTML content within script tags. When it's appended along with the HTML, the script should simply execute, with no eval() required.
I can't swear that this would work in old browsers, but it's a trick I've used a couple of times, and I've had no problems with it in Firefox, Chrome, or any of the later IE versions.
I think I see what you're asking here, from my understanding you want to send the new "page" asynchorously, and render the new javascript and html. It looks like you already got your request/response down, so i'm not gonna go and talk about sending JSON objects, and the whole "how-to" of sending html and javascript because it looks like you got that part. To do what you want and to dynamically add your javascript in, this stackoverflow question looks like it has what you need
Is there a way to create a function from a string with javascript?
So pertaining to your example, here is how it would look when you recieve the JSON string from your python script:
$("body").on("click", "#open_table", function() {
$.getJSON('/get_table', function(response){
$("#table_div").append(response.html);
/* Create function from string */
var newFunction = Function(response.javascript['param_1'], response.javascript['param_2'], response.javascript['function']);
/* Execute our new function to test it */
newFunction();
}
});
*Your actual function contents would be the string: response.javascript['function']
*Your parameter names if any would be in separate strings ex: response.javascript['param_1']
That is almost a direct copy of the "String to function" code that you can see in the linked question, just replaced it with your relevant code. This code is also assuming that your object is sent with the response.javascript object containing an array with your actual function content and parameter names. I'm sure you could change the actual name of the var too, or maybe put it in an associative array or something that you can keep track of and rename. All just suggestions, but hopefully this works for you, and helps you with your problem.
I am also doing similar work in my project where I had to load partial html using ajax calls and then this partial HTML has elements which requires events to be attached. So my solution is to create a common method to make ajax calls and keep a js method name to be executed post ajax call in html response itself. For example my server returns below html
<input type="hidden" data-act="onPartialLoad" value="createTableEvents" />
<div>.........rest of html response.....<div>
Now in common method, look for input[type='hidden'][data-act='onPartialLoad'] and for each run the method name provided in value attribute (value="createTableEvents")
Dont Use Eval() method as it is not recommended due to security
issues. Check here.
you can run js method using window["method name"]...so here is a part of code that I use.
$.ajax(options).done(function (data) {
var $target = $("#table_div");
$target.fadeOut(function () {
$target.html(data);
$target.fadeIn(function () {
try {
$('input[data-act="onPartialLoad"]', $target).each(function () {
try {
//you can pass parameters in json format from server to be passed into your js method
var params = $(this).attr('params');
if (params == undefined) {
window[$(this).val()]();
}
else {
window[$(this).val()]($.parseJSON(htmlutil.htmlDecode(params)));
}
} catch (e) {
if (console && console.log) {
console.log(e.stack);
console.log($(this).val());
}
}
});
}
catch (e) {
console.log(e.stack);
}
});
});
});
use jQuery.getScript() (as suggested by Kalimah Apps) to load the required js files first.

PHP logic to Javascript front into html tags

I am currently trying to convert a lot of backend code to front end (to lighten the load on a small system).
The code at the moment calls a PHP function to return specific information. (e.g. image locations, strings, styling)
I am converting this code to its js equivalent, the content from Mysql was converted to JSON and stored in a read only file and I am accessing that file using this code:
<script>
function jsread(tag) {
$.getJSON("/strings.json", function(result){
document.write(result[tag]['value']);
});
}
</script>
I want the function to "print" where ever it is invoked. document write writes the value to the page but stops all other loading and write only the value.
Let me be very clear on this: I DO NOT want to use anything that needs extra calls or references out side of this function, that will take months of work so no getting elements by their IDs I have already view many questions on this subject and none are what I can work with. I need something that can be applied to every situation. Other wise I will just have to read the JSON using PHP as a middle compromise.
The problem here is, document.write()'s behaviour is crazy across all the browsers, because, it directly modifies the document object and messes up with the events attached. So it is always better to avoid this function as each browser defines it differently and has a different effect on the same code, with different browsers.
Is there a way to use them without a direct reference?
Solution
The wise thing is, as I said in the comments, it is better to use one of the jQuery functions safely, which create a textNode and insert it the right way, without affecting the others:
<script>
function jsread(tag) {
$.getJSON("/strings.json", function(result){
$("body").append(result[tag]['value']);
});
}
</script>
In case, if you wanna do something like having a placeholder and doing stuff, then you can try giving something like this:
$(function () {
var data = "Dummy Data, that would probably get returned from the getJSON";
// Inside the Success function, do this:
$("span.placeholder-of-the-json").replaceWith(data);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<span class="placeholder-of-the-json">This gets replaced</span>

Random string being added onto JS var

basically I am trying to load some PHP into a DIV using JS.
Using this code:
$('#preview').load("includes/event_image_crop.php?img=" + fname);
However, its not just putting the fname string in there its adding a random string too like this &_=1369168657782
Any ideas?
Thanks
This is a feature designed to prevent caching. It should have no effect on the page (unless you need to use the _ GET variable), but if you need to disable it you should set cache: true using ajaxSetup:
$.ajaxSetup ({
cache: true
});
Of course, as Ian mentions, this will affect every Ajax call on the page, so be aware of that if you have other Ajax calls. It might be better to refactor your code and use a more configurable function than .load().
See a similar (opposite) question here: Stop jQuery .load response from being cached

using JQuery to fetch an html document and parse it into a DOM tree

So essentially I'm trying to build my own version of GitHub's tree slider. The relevant Javascript/JQuery code is:
// handles clicking a link to move through the tree
$('#slider a').click(function() {
history.pushState({ path: this.path }, '', this.href) // change the URL in the browser using HTML5 history module
$.get(this.href, function(data) {
$('#slider').slideTo(data) // handle the page transition, preventing full page reloads
})
return false
})
// binds hitting the back button in the browser to prevent full page reloads
$(window).bind('popstate', function() {
$('#slider').slideTo(location.pathname)
}
Ok, hopefully that's understandable. Now here's my interpretation of what's going on here, followed by my problem/issue:
The callback function for the GET request when navigating through the tree is the slideTo method, and an HTML string is passed in as an argument to that function. I'm assuming that slideTo is a function defined elsewhere in the script or in a custom library, as I can't find it in the JQuery documentation. So, for my purposes, I'm trying to build my own version of this function. But the argument passed into this function, "data", is just the string of HTML returned from the GET request. However, this isn't just a snippet of HTML that I can append to a div in the document, because if I perform the same GET request (e.g. by typing the url into a web browser) I would expect to see a whole webpage and not just a piece of one.
So, within this callback function that I am defining, I would need to parse the "data" argument into a DOM so that I can extract the relevant nodes and then perform the animated transition. However, this doesn't make sense to me. It generally seems like a Bad Idea. It doesn't make sense that the client would have to parse a whole string of HTML just to access part of the DOM. GitHub claims this method is faster than a full page reload. But if my interpretation is correct, the client still has to parse a full string of HTML whether navigating through the tree by clicking (and running the callback function) or by doing full page loads such as by typing the new URL in the browser. So I'm stuck with either parsing the returned HTML string into a DOM, or ideally only fetching part of an HTML document.
Is there a way to simply load the fetched document into a Javascript or JQuery DOM object so I can easily manipulate it? or even better, is there a way to fetch only an element with an arbitrary id without doing some crazy server-side stuff (which I already tried but ended up being too spaghetti code and difficult to maintain)?
I've also already tried simply parsing the data argument into a JQuery object, but that involved a roundabout solution that only seems to work half the time, using javascript methods to strip the HTML of unwanted things, like doctype declarations and head tags:
var d = document.createElement('html');
d.innerHTML = data;
body = div.getElementsByTagName("body")[0].innerHTML;
var newDOM = $(body);
// finally I have a JQuery DOM context that I can use,
// but for some reason it doesn't always seem to work quite right
How would you approach this problem? When I write this code myself and try to make it work on my own, I feel like no matter what I do, I'm doing something horribly inefficient and hacky.
Is there a way to easily return a JQuery DOM object with a GET request? or better, just return part of a document fetched with a GET request?
Just wrap it; jQuery will parse it.
$(data) // in your callback
Imagine you want to parse a <p> tag in your normal HTML web page. You probably would use something like:
var p = $('<p>');
Right? So you have to use the same approach to parse an entire HTML document and then, navigate through the DOM tree to get the specific elements you want. Therefore, you just need to say:
$.get(this.href, function(data) {
var html = $(data);
// (...) Navigating through the DOM tree
$('#slider').slideTo( HTMLportion );
});
Notice that it also works for XML documents, so if you need to download via AJAX a XML document from the server, parse the inner information and display it on the client-side, the method is exactly the same, ok?
I hope it helps you :)
P.S: Don't ever forget to put semicolons at the end of each JavaScript sentence. Probably, if you don't put them, the engine would work but it is better to be safe and write them always!

Running javascript code called by AJAX

My site uses pushState to load pages. I have one issue, I want to use javascript on one of the pages but can't because it loads everything with AJAX. So what do I do? I've been told something about "parseScript" but I can't find enough information on it.
--Example--
I load using AJAX
On my page I have this script:
<script type="text/javascript">
function go(){
alert('1');
}
</script>
GO!!!
Nothing happens.
--Edit--
If I open up Google Chrome's debugger:
"Uncaught ReferenceError: go is not defined"
And the <script> tag is no where to be found
Browsers don't seem to parse <script> element content that's added to the document via targetElement.innerHTML. That's probably what you're running into.
The best solution is to use a well-tested framework like jQuery for solving problems like this. They've already figured out how to safely and correctly inject scripts into the DOM. There's no sense re-inventing the wheel unless you absolutely can't spare the bandwidth for the library.
One way you might fix this is by separating the JavaScript from the HTML in the Ajax response, either by issuing two requests (probably slower) or by structuring your JavaScript and HTML within a JSON object (probably harder to maintain).
Here's an example:
<script>
function load_content(){
var req = new XMLHttpRequest();
req.open("GET", "ajax.json", true);
req.onreadystatechange = function (e){
if (req.readyState === 4){
if (req.status === 200){
// these three lines inject your JavaScript and
// HTML content into the DOM
var json = JSON.parse(req.responseText);
document.getElementById("target").innerHTML = json.html;
eval(json.js);
} else {
console.log("Error", req.statusText);
}
}
};
req.send(null);
}
</script>
Load more stuff
<div id="target"></div>
The document ajax.json on the server looks like this:
{
"js": "window.bar = function (){ console.log(\"bar\"); return false; }",
"html": "<p>Log a message</p>"
}
If you choose this route, you must either:
namespace your functions: MyApp.foo = function (){ ... };, or
explicitly add your functions to the global namespace: window.foo = function (){ ... };.
This is because eval executes in the current scope, so your function definitions inherit that scope and won't be globally available. In my example, I chose the latter option since it's just a trivial example, but you should be aware of why this is necessary.
Please make sure to read When is JavaScript's eval() not evil? if you decide to implement this yourself.
I think it would be helpful to have a little more detail as to how the Ajax call is made and the content is loaded. That said, a few things of note:
the syntax for javascript:void() is invalid. It should be javascript:void(0). For that matter, using javascript:void() on the href of an anchor tag is generally bad practice. Some browsers do not support it. If you must use an tag, set the href to # and add "return false;" to the click event.
you should use a button tag instead of the a tag in this case anyway.
given what you have provided, it should work (aside from the syntax error with void())
If I were to do this I would use jquery's load call.
That takes care of putting an ajax call ,and parsing tags for script/no-script elements.
IF you dont wanna use jquery, I would suggest you go online and find what the jquery load method does and implement the same as an event handler for your ajax call.

Categories