I am using Ajax and hash for navigation.
Is there a way to check if the window.location.hash changed like this?
http://example.com/blah#123 to http://example.com/blah#456
It works if I check it when the document loads.
But if I have #hash based navigation it doesn't work when I press the back button on the browser (so I jump from blah#456 to blah#123).
It shows inside the address box, but I can't catch it with JavaScript.
The only way to really do this (and is how the 'reallysimplehistory' does this), is by setting an interval that keeps checking the current hash, and comparing it against what it was before, we do this and let subscribers subscribe to a changed event that we fire if the hash changes.. its not perfect but browsers really don't support this event natively.
Update to keep this answer fresh:
If you are using jQuery (which today should be somewhat foundational for most) then a nice solution is to use the abstraction that jQuery gives you by using its events system to listen to hashchange events on the window object.
$(window).on('hashchange', function() {
//.. work ..
});
The nice thing here is you can write code that doesn't need to even worry about hashchange support, however you DO need to do some magic, in form of a somewhat lesser known jQuery feature jQuery special events.
With this feature you essentially get to run some setup code for any event, the first time somebody attempts to use the event in any way (such as binding to the event).
In this setup code you can check for native browser support and if the browser doesn't natively implement this, you can setup a single timer to poll for changes, and trigger the jQuery event.
This completely unbinds your code from needing to understand this support problem, the implementation of a special event of this kind is trivial (to get a simple 98% working version), but why do that when somebody else has already.
HTML5 specifies a hashchange event. This event is now supported by all modern browsers. Support was added in the following browser versions:
Internet Explorer 8
Firefox 3.6
Chrome 5
Safari 5
Opera 10.6
Note that in case of Internet Explorer 7 and Internet Explorer 9 the if statment will give true (for "onhashchange" in windows), but the window.onhashchange will never fire, so it's better to store hash and check it after every 100 millisecond whether it's changed or not for all versions of Internet Explorer.
if (("onhashchange" in window) && !($.browser.msie)) {
window.onhashchange = function () {
alert(window.location.hash);
}
// Or $(window).bind( 'hashchange',function(e) {
// alert(window.location.hash);
// });
}
else {
var prevHash = window.location.hash;
window.setInterval(function () {
if (window.location.hash != prevHash) {
prevHash = window.location.hash;
alert(window.location.hash);
}
}, 100);
}
EDIT -
Since jQuery 1.9, $.browser.msie is not supported. Source: http://api.jquery.com/jquery.browser/
There are a lot of tricks to deal with History and window.location.hash in IE browsers:
As original question said, if you go from page a.html#b to a.html#c, and then hit the back button, the browser doesn't know that page has changed. Let me say it with an example: window.location.href will be 'a.html#c', no matter if you are in a.html#b or a.html#c.
Actually, a.html#b and a.html#c are stored in history only if elements '<a name="#b">' and '<a name="#c">' exists previously in the page.
However, if you put an iframe inside a page, navigate from a.html#b to a.html#c in that iframe and then hit the back button, iframe.contentWindow.document.location.href changes as expected.
If you use 'document.domain=something' in your code, then you can't access to iframe.contentWindow.document.open()' (and many History Managers does that)
I know this isn't a real response, but maybe IE-History notes are useful to somebody.
Firefox has had an onhashchange event since 3.6. See window.onhashchange.
I was using this in a react application to make the URL display different parameters depending what view the user was on.
I watched the hash parameter using
window.addEventListener('hashchange', doSomethingWithChangeFunction);
Then
function doSomethingWithChangeFunction () {
let urlParam = window.location.hash; // Get new hash value
// ... Do something with new hash value
};
Worked a treat, works with forward and back browser buttons and also in browser history.
You could easily implement an observer (the "watch" method) on the "hash" property of "window.location" object.
Firefox has its own implementation for watching changes of object, but if you use some other implementation (such as Watch for object properties changes in JavaScript) - for other browsers, that will do the trick.
The code will look like this:
window.location.watch(
'hash',
function(id,oldVal,newVal){
console.log("the window's hash value has changed from "+oldval+" to "+newVal);
}
);
Then you can test it:
var myHashLink = "home";
window.location = window.location + "#" + myHashLink;
And of course that will trigger your observer function.
Another great implementation is jQuery History which will use the native onhashchange event if it is supported by the browser, if not it will use an iframe or interval appropriately for the browser to ensure all the expected functionality is successfully emulated. It also provides a nice interface to bind to certain states.
Another project worth noting as well is jQuery Ajaxy which is pretty much an extension for jQuery History to add ajax to the mix. As when you start using ajax with hashes it get's quite complicated!
var page_url = 'http://www.yoursite.com/'; // full path leading up to hash;
var current_url_w_hash = page_url + window.location.hash; // now you might have something like: http://www.yoursite.com/#123
function TrackHash() {
if (document.location != page_url + current_url_w_hash) {
window.location = document.location;
}
return false;
}
var RunTabs = setInterval(TrackHash, 200);
That's it... now, anytime you hit your back or forward buttons, the page will reload as per the new hash value.
I've been using path.js for my client side routing. I've found it to be quite succinct and lightweight (it's also been published to NPM too), and makes use of hash based navigation.
path.js NPM
path.js GitHub
SHORT and SIMPLE example
Click on buttons to change hash
window.onhashchange = () => console.log(`Hash changed -> ${window.location.hash}`)
<button onclick="window.location.hash=Math.random()">hash to Math.Random</button>
<button onclick="window.location.hash='ABC'">Hash to ABC</button>
<button onclick="window.location.hash='XYZ'">Hash to XYZ</button>
I found the snippet below for creating an iframe:
I'd like to only load the textual content at http://www.host.com and make the iframe invisible using display:none
Background:
I need an effective way to parse out the favicon location. Not all site have a default location. For example <link rel="SHORTCUT ICON" href="../images/logo_small.ico" />.
Hence all I need are the textual contents. PHP has a function that does this ( file_get_contents) but I want to do it on the client side.
Here is the mdn documentation on iframe
For server-side PHP use file_get_contents.
function makeFrame() {
ifrm = document.createElement("IFRAME");
ifrm.setAttribute("src", "http://www.host.com");
ifrm.style.width = 640+"px";
ifrm.style.height = 480+"px";
document.body.appendChild(ifrm);
}
Example of Delicious Bookmarklet:
javascript:(function()
{
f='http://www.delicious.com/save?url='+encodeURIComponent(window.location.href)+
'&title='+encodeURIComponent(document.title)+'¬es='+
encodeURIComponent(''+
(window.getSelection?window.getSelection():document.getSelection?
document.getSelection():document.selection.createRange().text))+'&v=6&';
a=function()
{
if(!window.open(f+'noui=1&jump=doclose','deliciousuiv6','location=1,links=0,scrollbars=0,to
olbar=0,width=710,height=660'))
{
location.href=f+'jump=yes'
}
};
if(/Firefox/.test(navigator.userAgent))
{
setTimeout(a,0);
}
else
{
a();
}
})()
You will only have access to the link element in the iframe when both yours and the framed page are in the same domain. To cite the docs you found:
Scripts trying to access a frame's content are subject to the same-origin policy, and cannot access most of the properties in the other window object if it was loaded from a different domain.
Therefore, it will be needed to use a PHP solution. Load a given domain, use a tagsoup parser and query the dom for link[rel="SHORTCUT ICON"].
You can create a JSON API with that solution, which can be used over Ajax from the clientside js code of your application.
I think you will struggle to get the information client side if the page is located on a different server, due to cross-site scripting restrictions within the browser.
If it is all local you want to look at:
XMLHttpRequest();
and
getResponseText();
I think you are probably best using the PHP method though.
Edit:
This is a similar question I think:
XMLHttpRequest to get HTTP response from remote host
Responses there may be of further assistance.
I am trying to call a page with ajax, but from another server. This js code runs from bookmark in any page you want and I need to get some data from my server. How could I do this? or maybe connect directly to the database?
I got this code:
$j.getJSON(serverUrl+"isLogin.php?callback=?",function(data){
//really no need to do anything here, we're just posting data
//but this will output success
alert(data);
});
isLogin:
if ($_SESSION['user'] == ''){
echo json_encode(array("isLogin" => "false"));
} else {
echo json_encode(array("isLogin" => "true"));
}
How could I make this? I try allot of solutions but none works. This one said no errors, but the alert never appear
Thanks
AJAX (The XMLHttpRequest object) is limited to the same domain for security reasons.
You have a couple ways to go about this:
You can use JSONP if your API supports it. This is very similar to your current AJAX approach.
This is jQuery's documentation - http://api.jquery.com/jQuery.getJSON/
Another option is to create a local proxy. This is a little more in depth, but gives you full control.
Here's a good article - http://developer.yahoo.com/javascript/howto-proxy.html
So I'm running a crawler on my server and I'm needing to execute javascript to gain access to some of the data on my target site (target being the one I want to crawl). I had a question regarding a different approach to the problem here, but it's not needed for answering this one: [Dead]How to successfully POST to an old ASP.NET site utilizing Asynchronous Postback
My javascript is executed in the browser I call my php crawler from. The problem is that all javascript requests are targeted back at my own server rather than the target site (I get lead to links like /index.php on my own site rather than the target site).
My experience with javascript is pretty minimal and I'm not sure how I should redirect my requests to my target. Here is an example of a javascript function from the page that I'm calling:
<script type="text/javascript">
//<![CDATA[
var theForm = document.forms['aspnetForm'];
if (!theForm) {
theForm = document.aspnetForm;
}
function __doPostBack(eventTarget, eventArgument) {
if (!theForm.onsubmit || (theForm.onsubmit() != false)) {
theForm.__EVENTTARGET.value = eventTarget;
theForm.__EVENTARGUMENT.value = eventArgument;
theForm.submit();
}
}
//]]>
</script>
... and the way that I call it:
echo "<SCRIPT language='javascript'>__doPostBack('-254870369', '')</SCRIPT>";
Is there some way of aliasing the server address from my own server to the target server or doing some other kind of handy workaround that would fix this problem?
There is no need to inject javascript in the target.
You can use wireshark to study all request made by the target. Wireshark is a quite hard to master but powerful. Instead you can try the net tab of the firebug addon.
Once you know how the target send requests and receive data from their server, you can use curl to imitate the request/receiving data. You don't need any more to build crawlers.
If this not answers your question explain a little more the scenario.
I'm trying to do something that goes far over my current skills yet I believe I can do it, I would be imensely thankfull if you point me to an already developed script for this matter.
My question comes from what runs first? Javascript or php? because I need to asynchronosly include a php file into the page.
My idea is this, if user has a screen width wider then 1024, draw an extra fixed position div, if not, don't draw it. That div is supposed to take in a flash object with a clickable link.
My idea would be to:
Get resolution with javascript.
Use jQuery to send ajax json var into .php file that stores res vars into a session cookie.
Read the cookie with php, decide to include the extra .php file or not. That file should then eco the extra div with flash object.
Is this possible? Is there an easier way? Since this is to include in a Zencart personal store of mine, does it conflicts with the zencart cookie session or can a user have more then 1 type of session cookie per website? it can right?
Best Regards, any help appreciated,
Joricam
Yes, it's possible - but now in the way you're describing. PHP runs server side and Javascript runs client side, i.e. PHP is executed before any Javascripts. However, nothing says you cannot do this only with Javascript - and it would actually be trivial to solve with jQuery (as you tagged the question with it). Just let your Ajax called PHP-page return the inline HTML, and print it with jQuery instead. No need for cookies, either.
PHP runs first because the page hasn't loaded yet and javascript is run user-side, but once the page is loaded, ajax allows you to make calls to a php script and recieve a result that you can then add to the page via javascript.... so yes it's doable:)
Sessions can contain as many keys as you need them to, just name them something specific
<script language="javascript">
if (window.location.search == "") {
window.location.href = window.location + "?width=" + screen.width + "&height=" + screen.height;
}
</script>
This will redirect the page you try to access to the same page but sending parameters to the page.
Then you would be able to:
<?php
$width = $_get['width'];
$height = $_get['height'];
?>