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.
Related
I have a page with headers, images, etc. I'd like to replace a "page" div with another file of HTML, JavaScript, etc using Ajax and execute JavaScript on that page after it is loaded. How do I do this and also handle < , ", and other tags in the file and pass the page some parameters?
Is the other "page" content owned by you? If so, you can have javascript methods on your main "container" page, then once you fire the method to pull the contents of the new "page" div, fire the corresponding javascript method you need, since any necessary DOM elements will have been added to the page at this time.
To do it the way you mentioned, you can follow the steps seen here to use the dynamic script pattern: Executing <script> inside <div> retrieved by AJAX
Basically, you host your javascript externally, then once the page has loaded, add the "src" tag to a script element and it will execute.
As for handling special characters, you can follow steps with jQuery's ajax call to inject HTML from the other page into your current one, such as here: How to get the html of a div on another page with jQuery ajax?
$.ajax({
url:'http://www.example.com/',
type:'GET',
success: function(data){
$('#ajaxcontent').html($(data).find('body').html());
}
});
(Instead of targeting a specific div on the external page, you would target the body or parent container div)
given an html page
<html>
...
<body>
<div class="page">
some html content...
</div>
</body>
</html>
you can replace the content of the div via the jQuery function load()
$("div.page").load("an-http-resource.html");
Use an AJAX request to get the HTML file as a response.
Replace the "page" div innerHTML with the response.
If the HTML page has a bunch of headers and such and you only want a certain portion of that HTML file, you may want to use getElementById or some other method of selecting the portion of the HTML file.
The HTML entities will appear as they normally would in a browser, if that is what you mean by handling < and " and other tags.
You can send parameters by editing the endpoint:
index.html?date=today&car=yours
I'm making a Chrome Extension that changes the DOM of a page. But I would like to give the user an option to switch between the page before the changes and the changed page.
It's a little bit like Google translate where you can change between the orginal language and the translated message.
I could not find anything in my own searches.
I know JavaScript but not JQuery yet.
Thanks for the help.
You could save the entire body in a variable, then start overwriting things. If you want to switch back load up the old body.
You could save all the original DOM content to a variable before running the content script. You can do this by using the following code at the top of your content script:
var originalDOM = document.getElementsByTagName("*");
This saves the entire DOM in an array called originalDOM. The * acts a universal tag, requesting every tag in the document. You can read more about the .getElementsByTagName() API here.
You could try:
var html = document.getElementsByTagName("html")[0];
var page = html.innerHTML;
This will give you everything between the <html> tags.
After the content script is injected, run:
var newPage = html.innerHTML;
Now, whenever you want to switch between the pages, simply run:
html.innerHTML = page; //or newPage
You can read more about the .getElementsByTagName() API here
I'm trying to fetch an HTML document object, not the text of the page, given its URL, via Javascript. The reason I need the Document object is so I can look for a given classname and take a certain action if it exists.
If the page is in the same domain (i.e. a relative path) you could load it inside a hidden iframe, and access the document from window.frames as shown here
function saveDataToVariable(data) {
var html = data;
// do something
}
$.get('any.html', saveDataToVariable);
this will give you the complete html output of a given html page... also including the html or div tags an anything else will be included and you can parse it afterwards as you need
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 remember using a plugin in the past where I could use AJax to load a page and update only part of the DOM. The AJax request returns the entire HTML page, but only a small portion of it replaces part of the currently loaded DOM.
For example, SO can use this function to fetch http://stackoverflow.com and only update #content. SO would make an AJax request to fetch http://stackoverflow.com, fetch #content from the returned string, and update #content of the DOM.
Sorry if my question is confusing. How would I do this without a plugin?
The .load() function is designed to do this. Just include a selector for an element along with the URL, like so:
$('#content').load('http://stackoverflow.com #content', optionalCallbackFunction);
That will replace the content of the element with ID content on the current page, with the contents of the element with ID content on the page returned by an AJAX request to http://stackoverflow.com, then run the function called optionalCallbackFunction. Assuming, of course, that the request was successful.
Without the AJAX, you can parse a raw string like this:
var str = "<div><h1>Page Title</h1><div id='content'>This is new.</div></div>";
var text = $("#content",$(str)).html();
$('#content').html(text);