Selecting :target on document.ready() - javascript

The following is a simple test case to demonstrate what I'm trying to do:
<html>
<head>
<title>Test</title>
</head>
<body>
<script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
<script type="text/javascript">
$(document).ready(function()
{
$(":target").css('color', 'red');
});
</script>
<ul>
<li id="one">One</li>
<li id="two">Two</li>
<li id="three">Three</li>
</ul>
</body>
</html>
The idea is to do something through jQuery/Javascript to the targetted item, when something is targetted (for example, test.html#two).
This works as I expect it to in Firefox and IE 10, but not in Chrome, Opera or Safari, which leaves me wondering if this is a bug in some browsers, if what I'm trying to do is somehow wrong, or if I've run afoul of an inadequately precise part of some specification or other.
If I change the jQuery code to do
alert($(":target").length);
it becomes apparent that Chrome, Opera and Safari can't find the :target element during document.ready(), but calling the same code later (via console or function attached to a click event) does find the elements.
When should :target become accessible to JS?

This was posted as a comment but was later removed, you can try waiting for the window load event:
$(window).on('load hashchange', function(){
$(':target').css('color', 'red');
});
This for me produced mixed results on Chrome, it worked when doing a page refresh (F5) but not when hitting enter in the address bar.
I don't know if there's any way to handle this correctly on page load using the :target selector but you could always get the hash value and use it as your selector:
$(window).on('load hashchange', function(){
var target = window.location.hash;
$(target).css('color', 'red');
});
UPDATE
I've been doing some research on the issue plus some tests and I have a couple of insights to share:
First off, we need to understand that when calling $(':target') jQuery internally makes use of querySelectorAll(':target') which means it's directly related to the CSS specification of the pseudo-class, but why isn't working inside document.ready()?
Well, I found that wrapping the code inside setTimeout(fn,0) actually makes the selector available:
$(document).ready(function(){
setTimeout(function(){
$(':target').css('color', 'red'); //THIS WORKS
},0);
});
You can read this answer for an explanation on how adding a zero-ms timeout actually makes a difference, but basically it allows the browser to complete other non-javascript related tasks (in which we would find making the actual CSS pseudo-class available for query). I believe Firefox somehow manages its internal processes differently and that's why the code works there without the need for a timeout.
Now I also discovered that jQuery's internal sizzle selector engine provides a fallback for browsers that do not support CSS :target pseudo-class, which you can use inside document.ready() without issue:
$(document).ready(function(){
$(':target()').css('color', 'red');
});
This works because instead of relying on the CSS class it is a javascript implementation that makes use of the hash property on the window.location object, internally it is defined as follows:
"target": function( elem ) {
var hash = window.location && window.location.hash;
return hash && hash.slice( 1 ) === elem.id;
}
The only think you should note is that this function will go through every element on the page if it's not passed a selector like :target(div), so I believe using the workaround I provided earlier would still be a better option than this.

Because the page is not been reloaded. You need bind it to hashchange:
$(window).on('hashchange', function(){
$(":target").css('color', 'red');
});
http://jsfiddle.net/sXsYx/
Notice that you have much more work to make it right, maybe combine it with $(document).ready

you can use css3 target selector for styling work
:target
{
color:red;
}

Since there is no specialized logic in your example (if statements or such), why don't you just do the styling in CSS? The :target pseudo-class is a CSS3 selector.
:target {
color: red;
}
Note that this will work in all modern browsers, and even some very old browsers (Chrome 1 and Firefox 1.3, for instance), but with Internet Explorer it is only supported starting from version 9.
You can also do it in both places if you wish (CSS and JavaScript), however the JavaScript would seem redundant unless you specifically need IE <= 8 compatibility.
I've noticed that you are using jQuery version 1.10.1, which retains support for IE <= 8. Is that important? If not you can also move to jQuery 2.0.2 (latest version at time of writing).

You should do like this
$("li:target")
This will select the element. This is the better way
Refer this please,
http://api.jquery.com/target-selector/
Or you should remove document ready and put the script at the end of the html document

Related

Script that works in the browser console but not when in the code

I have a very simple piece of javascript code that just should work and it only works when I run it in the browser console:
<script>
$(".hopscotch-close").click(function () {
alert("Hi");
Cookies.set("tourState", "closed")
})
</script>
Because it runs in the console I know that:
1) the ".hopscotch-close" is OK;
2) there are no errors in the code that could prevent it from running;
Also:
1) because is a "click" event I know that I haven't got a problem with the DOM being ready (and I can put everywhere - but in this case in at the bottom of the <body>;
2) I know I don't have an issue because of using the same name for a class than something else that exist;
3) The behavior is the same in Safari and Firefox, so its not a Browser issue.
I know this is tough without the full code, but if someone has experienced this maybe has na idea about what could be the problem.
From your comments I sense that the element is getting appended dynamically so instead of
$(".hopscotch-close").on('click',
you need to make use of event-delegation as
$(document).on('click','.hopscotch-close',function(){
That will do the trick.
If you are appending .hopscotch-close to any already existing static
element then instead of $(document).on('click' you can use
$('#yourStaticElementId').on('click','.hopscotch-close',function(){
which improves site performance.

IE not taking my onClick, any suggestions?

I have a pretty simple function that seems to work fine in Chrome, Firefox, and Safari, but in IE it's breaking. I'm actually trying to load this as a Windows 8 Web App, but from what I've read, that uses a more forgiving version of IE10 to output.
Say I have a <div> (or an <a> with an href...I've tried this as well) like so:
<div onClick="showSection('myTemplate.html');"></div>
This is my function:
function showSection(loca) {
$("#optionView").show();
$("#bookMenu").hide();
$("#optionView").load('settings/'+loca);
$("#settingsButton").attr("onClick","showSettingsMain();");
}
Why wouldn't this work specifically in IE?
A better option, especially since you are using jQuery, is to not use inline event handlers.
Instead, use this HTML:
<div id="main_div"></div>
And use this Javascript:
$(document).ready(function () {
$("#main_div").on("click", function () {
showSection("myTemplate.html");
});
});
This may not solve your problem with IE10, but it's considered better practice...and should work consistently with all browsers.
A few other suggestions:
Instead of using .attr to set the onclick attribute of #settingsButton, you might as well use on again:
$("#settingsButton").on("click", function () {
showSettingsMain();
});
Although I'm not exactly sure if that would have any effect on what the problem is.
Nonetheless, here's an explanation on the difference between attr and prop - .prop() vs .attr()
Also, if you need to specify exactly what URL to use, even on a per-<div> basis, you could use a data-* attribute. Say this is your HTML:
<div class="trigger-div" data-target-url="myTemplate.html"></div>
<div class="trigger-div" data-target-url="myTemplate2.html"></div>
Then you could use:
$(document).ready(function () {
$(".trigger-div").on("click", function () {
var $this = $(this);
var target_url = $this.attr("data-target-url"); // or $this.data("target-url")
showSection(target_url);
});
});
Clicking the first div will use "myTemplate.html", while clicking the second will use "myTemplate2.html".
This way, your data is embedded in your HTML, but your Javascript is unobtrusive.
You are using jQuery wrong, here:
First, bind the event to the div, you'll need to add a class or id for that:
<div id="myEvent"></div>
Then, bind the event:
$('#myEvent').on('click', showSection( 'myTemplate.html') );
And your function:
function showSection(loca) {
$("#optionView").show();
$("#bookMenu").hide();
$("#optionView").load('settings/'+loca);
}
Try that way.

Javascript hide/show toggle works both ways in Opera, but only one way in other browsers

I have a customized show/hide toggle script that I'm using along with CSS3 transitions for the effects.
The script shows the content when clicked, and hides it when the 'HideLink' link is clicked, complete with CSS3 transistions - but only in Opera.
In other browsers the script only works for showing the content, clicking the hide link doesn't work.
See this JSfiddle: http://jsfiddle.net/xte63/
These days with show / hide javascript, I prefer to use HTML5's data-* attributes.
This can already be used in non-HTML5 browsers via the getAttribute and setAttribute function.
I've quickly tried it against IE7, Chrome and Opera and it seems to work.
http://jsfiddle.net/ThJcb/
function showHide(shID) {
var exDiv = document.getElementById(shID);
if(exDiv.getAttribute("data-visible") != 'false'){
document.getElementById(shID+'-show').style.cssText = ';height:auto;opacity:1;visibility:visible;';
document.getElementById(shID).style.cssText = ';height:0;opacity:0;visibility:hidden;';
exDiv.setAttribute("data-visible" , 'false');
} else {
document.getElementById(shID+'-show').style.cssText = ';height:;opacity:0;visibility:hidden;';
document.getElementById(shID).style.cssText = ';height:auto;opacity:1;visibility: visible ;';
exDiv.setAttribute("data-visible" , 'true');
}
}
This allows you to determine the state of the div without having to check for CSS values.
EDIT: As pointed out in the comments, a typo was on the hide link (onlick instead of onclick) which made it appear the above jsfiddle worked whereas it didn't. At least not exactly as I made an error in the logic, setting the "data-visible" to false instead of true.
Here's an updated jsfiddle: http://jsfiddle.net/ThJcb/4/
(javascript snippet above updated also)

Overriding yellow autofill background

After a long struggle, I've finally found the only way to clear autofill styling in every browser:
$('input').each(function() {
var $this = $(this);
$this.after($this.clone()).remove();
});
However, I can’t just run this in the window load event; autofill applies sometime after that. Right now I’m using a 100ms delay as a workaround:
// Kill autofill styles
$(window).on({
load: function() {
setTimeout(function() {
$('.text').each(function() {
var $this = $(this);
$this.after($this.clone()).remove();
});
}, 100);
}
});
and that seems safe on even the slowest of systems, but it’s really not elegant. Is there some kind of reliable event or check I can make to see if the autofill is complete, or a cross-browser way to fully override its styles?
If you're using Chrome or Safari, you can use the input:-webkit-autofill CSS selector to get the autofilled fields.
Example detection code:
setInterval(function() {
var autofilled = document.querySelectorAll('input:-webkit-autofill');
// do something with the elements...
}, 500);
There's a bug open over at http://code.google.com/p/chromium/issues/detail?id=46543#c22 relating to this, it looks like it might (should) eventually be possible to just write over the default styling with an !important selector, which would be the most elegant solution. The code would be something like:
input {
background-color: #FFF !important;
}
For now though the bug is still open and it seems like your hackish solution is the only solution for Chrome, however a) the solution for Chrome doesn't need setTimeout and b) it seems like Firefox might respect the !important flag or some sort of CSS selector with high priority as described in Override browser form-filling and input highlighting with HTML/CSS. Does this help?
I propose you avoiding the autofill in first place, instead of trying to trick the browser
<form autocomplete="off">
More information: http://www.whatwg.org/specs/web-forms/current-work/#the-autocomplete
If you want to keep the autofill behaviour but change the styling, maybe you can do something like this (jQuery):
$(document).ready(function() {
$("input[type='text']").css('background-color', 'white');
});
$(window).load(function()
{
if ($('input:-webkit-autofill'))
{
$('input:-webkit-autofill').each(function()
{
$(this).replaceWith($(this).clone(true,true));
});
// RE-INITIALIZE VARIABLES HERE IF YOU SET JQUERY OBJECT'S TO VAR FOR FASTER PROCESSING
}
});
I noticed that the jQuery solution you posted does not copy attached events. The method I have posted works for jQuery 1.5+ and should be the preferred solution as it retains the attached events for each object. If you have a solution to loop through all initialized variables and re-initialize them then a full 100% working jQuery solution would be available, otherwise you have to re-initialize set variables as needed.
for example you do: var foo = $('#foo');
then you would have to call: foo=$('#foo');
because the original element was removed and a clone now exists in its place.

jQuery .attr not working in IE6 & IE7

The javascript code below is about half way on my php page, I can't directly modify the radio buttons with IDs q_251_789 and q_251_790 on my page unfortunately, hence why I'm using JS to add attributes to those two radio buttons:
<script><!--
$("#q_249_249").hide();
$("#q249").hide();
$("#q_251_789").attr("onClick","yesClicked();");
$("#q_251_790").attr("onClick","noClicked();");
function yesClicked()
{
$("#q_249_249").show();
$("#q249").show();
$("#addressTable").show();
};
function noClicked()
{
$("#q_249_249").hide();
$("#q249").hide();
$("#addressTable").hide();
};
//--></script>
In Chrome (dev), FF (3.6), and IE8 this all works fine.
In IE6 and IE7 the following two lines of the script do not work but are not producing any errors (According to IE dev tools -> JS debugger):
$("#q_251_789").attr("onClick","yesClicked();");
$("#q_251_790").attr("onClick","noClicked();");
Any ideas what I'm doing wrong?
Or a workaround to achieve the same goal?
Instead of setting an event handler .attr() attach the .click() handlers the unobtrusive way, like this:
$("#q_251_789").click(yesClicked);
$("#q_251_790").click(noClicked);
Or, use anonymous functions like this (the combined selectors is just a shortcut, but unrelated):
$("#q_251_789").click(function () {
$("#q_249_249, #q249, #addressTable").show();
});
$("#q_251_790").click(function () {
$("#q_249_249, #q249, #addressTable").hide();
});

Categories

Resources