prevent default behaviour of a 'hashchange' event - javascript

I am using the jQuery $(window).on('hashchange') method to hide irrelevant sections except the one that the URI-hash points to. It works beautifully, back button and everything. Except for the fact that I can't seem to prevent the default behaviour of the browsers, that is to scroll down to the section with the matching id.
Here is my function.
var AddHashNav = function (hashmatch, container) {
$(window).on('hashchange', function (e) {
if ( !window.location.hash ) {
// empty hash, show only the default header
change_preview(container, container + ' > header');
return false;
}
// Don't do anything to hash links who's ids don't match
else if ( window.location.hash.match(hashmatch) ) {
change_preview(container, window.location.hash);
return false;
}
});
}
var changePreview = function (container, preview) {
$(container + ' >').addClass('hidden');
$(preview).removeClass('hidden');
}
And the caller is simply
$(document).ready(function () {
// applay AddHashNav to all sections who's id ends in 'preview'
AddHashNav(/preview?/, '.hash-nav-container');
});
I've tried both e.preventDefault(); and return false; and neither seem to work.
Note that I'm trying to prevent the behaviour of the hashChange event, not the click event, here it seems not to be possible, but I'm sure at least somebody has managed to figure out how to do this.

I fixed it by running the change_preview() on the first call of the AddHashNav constructor, and therefor hiding the sections on the $(document).load() call.
var AddHashNav = function (hashmatch, container) {
// hide all sections except header on load
change_preview()
$(window).on('hashchange', function (e) {
if ( !window.location.hash ) {
// empty hash, show only the default header
change_preview(container, container + ' > header');
return false;
}
// Don't do anything to hash links who's ids don't match
else if ( window.location.hash.match(hashmatch) ) {
change_preview(container, window.location.hash);
return false;
}
});
}
It is not the most beautiful solution. I'm not sure why it works (I assume it is because the sections have no position in the window object, and hence can't be scrolled into), but it works for now.

Related

IE click event span not triggered

I'm having this webpage
http://pocolocoadventures.be/reizen/
And it should filter (with isotope.js) the travelboxes on the page.It does in safari, chrome, firefox, opera, .. but in IE, the filter doesn't work. Even worse, JS doesn't react at all at a click event on te span.
This is the piece of js
// Travel Isotope
var container = $('#travel-wrap');
container.isotope({
animationEngine : 'best-available',
itemSelector: '.travel-box ',
animationOptions : {
duration : 200,
queue : false
},
});
$(".filters span").click(function(){
var elfilters = $(this).parents().eq(1);
if( (elfilters.attr("id") == "alleReizen") && elfilters.hasClass("non-active") )
{
$(".label").each(function(){
inActive( $(this) );
});
setActive(elfilters);
}
else{
//set label alleReizen inactive
inActive( $("#alleReizen") );
if( elfilters.hasClass("non-active") ){
setActive(elfilters);
}
else{
inActive(elfilters);
}
}
checkFilter();
var filters=[];
$(".search.filters").children().each(function(){
var filter = $(this).children().children().attr("data-filter");
if( $(this).hasClass("non-active") ){
filters = jQuery.grep(filters, function(value){
return value != filter;
});
}
else{
if(jQuery.inArray(filter,filters) == -1){
filters.push(filter);
}
}
});
filters = filters.join("");
filterItems(filters);
});
function filterItems(filters){
console.log("filter items with filters:" + filters);
container.isotope({
filter : filters,
}, function noResultsCheck(){
var numItems = $('.travel-box:not(.isotope-hidden)').length;
if (numItems == 0) {
$("#no-results").fadeIn();
$("#no-results").css("display", "block");
}
else{
$("#no-results").fadeOut();
$("#no-results").css("display", "none");
}
});
}
function setActive(el){
el.removeClass("non-active");
var span = el.find('i');
span.removeClass("fa-check-circle-o").addClass("fa-ban");
}
function inActive(el){
el.addClass("non-active");
var span = el.find('i');
span.removeClass("fa-ban").addClass("fa-check-circle-o")
}
function checkFilter(){
var filterdivs = $('.filters span').parent().parent();
if( filterdivs.not('.non-active').length == 0 ){
setActive( $("#alleReizen") );
}
var filterLabels = $(".filters .label");
if( filterLabels.not('.non-active').length == 0){
setActive( $("#alleReizen") );
}
}
function noResultsCheck() {
var numItems = $('.item:not(.isotope-hidden)').length;
if (numItems == 0) {
//do something here, like turn on a div, or insert a msg with jQuery's .html() function
alert("There are no results");
}
}
Probably something small and stupid; but I can't find it..
Thanks in advance!
On your website you've build the buttons like this:
<button>
<span>
</span>
</button>
Now the button element is designed to be a button. It differs from the input button. In the latter you'd set the caption using value. In the button element you set it as a text node. The button element can contain elements like a span. The spec isn't very clear about whether or not you should have event handlers on the children of the button element. It's a browser developers interpretation of allowing it or not.
This problem has been posted here before (a few times)
span inside button, is not clickable in ff
Missing click event for <span> inside <button> element on firefox
It seems that Firefox is allowing it, based upon your findings. IE isn't. So to be on the safe side: use the button the way it was intended.
Wrap the button inside a span (not really logical)
Put the click handler on the button.
$(".filters button").click(...);
played around in the console a bit, and this seemed to work well.
$(".filters").on('click', 'span', function(){
// foo here
console.log('foo');
});
Maybe the filters are manipulated by one of your js files after page load?
.on will allow you to select a container which listens on changes that happen inside it, passing the element you want the actual action to work on.
If it's ok for you, I'd suggest to use the <button> element, instead of the <span>.
Let me know if that works for you.

apply a jQuery effect in ASP based on validation result

I have a webform with a control panel (#pnlStepOne). The panel includes two textfields "txtFname" and "txtLname". I have a validator setup for each textfield. I have tested the form and all works as desired.
My questions is how do I add a jQuery effect to the panel onclick event only if one (or both) of the textfields ("txtFname" and "txtLname") don't validate. (this effect would "shake" the panel).
And I would like to add another jQuery effect to "flip" the control panel and switch the current one (#pnlStepOne) for another one (#pnlStepTwo) if both fields are validated by the asp:RequiredFieldValidators.
Just a sample code that I will tweak once I have the right If condition.
$(document).ready(function () {
$("#btnStepOne").click(function (event) {
if (**this is the condition that I am missing**)
{
$('#pnlStepOne').css({
background: 'red',
});
}
});
});
You can modify your code to be like this:
$(document).ready(function () {
$("#btnStepOne").click(function (event) {
var fvFname = document.getElementById('client-id-of-your-fvFname-validator');
var fvLname = document.getElementById('client-id-of-your-fvLname-validator');
ValidatorValidate(fvFname);
ValidatorValidate(fvLname);
if (!fvFname.isvalid || !fvLname.isvalid) {
$('#pnlStepOne').css({
background: 'red',
});
}
});
});
Have a rad of my answer to a similar question here:
Enable/Disable asp:validators using jquery
Which has the MSDN link here: http://msdn.microsoft.com/en-us/library/aa479045.aspx
In one of my projects I use a prettifyValidation function, so you could have something like:
$(document).ready(function () {
$("#btnStepOne").click(function (event) {
prettifyValidation();
});
});
function prettifyValidation() {
var allValid = true;
if (typeof Page_Validators != 'undefined') {
// Loop through from high to low to capture the base level of error
for (i = Page_Validators.length; i >= 0; i--) {
if (Page_Validators[i] != null) {
if (!Page_Validators[i].isvalid) { // The Control is NOT Valid
$("#" + Page_Validators[i].controltovalidate).removeClass("makeMeGreen").addClass("makeMeRed");
allValid = false;
} else { // Control is valid
$("#" + Page_Validators[i].controltovalidate).removeClass("makeMeRed").addClass("makeMeGreen");
};
};
};
};
}
This will loop through all controls on the page that have an ASP.NET validator attached, and then add or remove a class depending if they are valid or not.
Obviously from here you can limit the function to a specific control by matching the controlToValidate property, and you can restyle, add controls, change classes but this should hopefully provide you a decent base to work from.

iScroll url hash change support

This is a known issue for iScroll and it only seems to happen in iOS5 where the menu completely stops working. All my sub links in iScroll are hash anchors. Does anyone have a workaround for this?
The way I handled it was to hijack the anchor links themselves and replace them with scrollToElement calls instead.
// Hijack hash anchors and scroll to them
$('a').click ( function (e) {
var id = $(this).attr('href');
if (id.substr(0,1) == '#') {
e.preventDefault();
setTimeout( function() {
scroller.scrollToElement ( id, 0 );
}, 0);
return false;
} else {
return true;
}
});
This code should only hijack links that begin with #. It then handles the scrollToElement in a setTimeout which fixes some other intermittent bugs. It works well on my end as long as your anchors are properly named with id's. If you are using name attributes instead of id attributes, you'll need to rewrite these.
This code will copy name attributes and put them in the id attribute if it is blank. You probably won't need this, though.
$('a').each (function (i, e) {
var n = $(e).attr('name');
var id = $(e).attr('id');
if ( typeof id == 'undefined' || id === null || id === '') {
$(e).attr('id', n);
}
});

Problem with event.target in IE

I'm writing js for a status update system to be used on various pages throughout a app that I'm working. I am really just starting to get more comfortable with javascript so it has been somewhat of a challenge to get to the point where I have everything now.
The status system is basically a facebook clone. For the most part everything is supposed to function the way that facebook's status updates and status comments do. The intended behavior is that when the user clicks in the status textarea, the div under the status textarea slides out revealing the submit button as well as some other checkboxes.
If the user clicks anywhere else on the page except a link or any element that has the class prevent_slideup the div slides up hiding the submit button and any checkboxes.
I'm using a document.body click function to determine what the user clicked on so I know which form elements to hide if I should even hide them. I do not want this slideup to take place on a textarea if that textarea has focus or the user is selecting a checkbox that goes with that form. Hence the prevent_slideup class. I also do not want to bother running the slideup logic if the user has clicked on a link. I'd prefer they just leave the page without having to wait for the animation.
The code that I was using to accomplish this task can be found in the $(document.body).click(function (e) section below where I'm doing a .is('a') check on the event target.
This code works as expected in chrome and firefox, however in ie when a link is clicked for the first time it seems that the element stored in var target is actually a div instead of an anchor. What ends up happening is that the submit div slides up and the user is not taken to the link that they just clicked on. If a link is clicked a second time the user is taken to the page as you would expect.
It seems to me that there's some kind of a lag in ie as to what the current event being fired is.
The entire status module is working other than this one strange ie bug regarding the users click on the link not being carried out the first time that they click a link after opening the status textarea. Does anything jump out in this script that would explain this behavior or does anyone have any other advice?
Thanks in advance for your help.
$(document).ready(function(){
$("textarea.autoresize").autoResize();
});
$(document.body).click(function (e){
var target = e.target || e.srcElement;
console.log(target);
console.log($(target).is('a'));
if($(target).hasClass('prevent_slideup') || $(target).is('a'))
{
return true;
}
else
{
var active_element = document.activeElement;
var active_status_id = $(active_element).attr('data-status_id');
var active_has_data_status_id = (typeof active_status_id !== 'undefined' && active_status_id !== false) ? true : false;
$('textarea').each(function(){
if($(this).hasClass('status_comment_textarea'))
{
var status_id = $(this).attr('data-status_id');
if($('#comment_textarea_'+status_id).val() === '' && (!active_has_data_status_id || active_status_id !== status_id))
{
hide_status_comment_submit(status_id);
}
}
else if($(this).attr('id') === 'status_textarea')
{
if($('#status_textarea').val() === '' && $(active_element).attr('id') !== 'status_textarea')
{
$('#status_textarea').html($("#status_textarea").attr('placeholder'));
hide_status_submit();
}
}
});
return true;
}
});
$("#status_textarea").live('click', function(){
if($('#status_textarea').val() === $("#status_textarea").attr('placeholder'))
{
$('#status_textarea').html('');
}
show_status_submit();
return false;
});
$(".comment_toggle").live('click', function(){
var status_id = $(this).attr('data-status_id');
show_status_comment_submit(status_id);
return false;
});
$(".status_comment_submit").live('click', function(){
var status_id = $(this).attr('data-status_id');
$('#status_comment_submit_wrapper_'+status_id).addClass('status_comment_submit_successful');
return false;
});
$(".show_hidden_comments").live('click', function(){
var status_id = $(this).attr('data-status_id');
$('#status_hidden_comments_'+status_id).show();
$(this).hide();
return false;
});
function hide_status_submit()
{
$("#status_textarea").removeAttr('style');
$("#status_textarea").blur();
$("#status_block").removeClass('padding_b10');
$("#status_submit_wrapper").slideUp("fast");
return false;
}
function show_status_submit()
{
if ($("#status_submit_wrapper").is(":hidden"))
{
$("#status_block").addClass('padding_b10');
$("#status_submit_wrapper").slideDown('fast');
}
return false;
}
function hide_status_comment_submit(status_id)
{
if(!$('#status_comment_submit_wrapper_'+status_id).is(":hidden"))
{
$('#status_comment_submit_wrapper_'+status_id).hide();
$('#fake_comment_input_'+status_id).show();
$('#comment_textarea_'+status_id).removeAttr('style');
}
return false;
}
function show_status_comment_submit(status_id)
{
if($('#status_comment_submit_wrapper_'+status_id).is(":hidden"))
{
$('#fake_comment_input_'+status_id).hide();
$('#status_comment_submit_wrapper_'+status_id).show();
$('#comment_textarea_'+status_id).focus();
}
return false;
}
function status_comment_submit_successful()
{
hide_status_comment_submit($('.status_comment_submit_successful').attr('data-status_id'));
$('.status_comment_submit_successful').removeClass('status_comment_submit_successful');
return false;
}
I figured out that there were two main issues with my script...
1.) The document.body function and the #status_textarea live click funtioins were conflicting with each other.
2.) After adding the logic for the #status_textarea function into the document.body function I noticed that the script still didn't quite work as expected in internet explorer unless I had an alert in the function. The problem at this point was that the autoresize plugin that I'm using on the textarea was also conflicting with the document.body function.
I was able to rectify the situation by adding a dummy text input and hiding the status textarea. On click of the dummy text input the status textarea is shown and the the dummy text input is hidden. I have no idea why this worked, but it seems to have solved my problems.

:not isn't working

I've created a simple navigation bar that when you click on an item, another opens under it. to disappear the opened I wrote:
$("#container:not(#navbar)").click(function(){
$("#mini_navbar_home").hide()
});
I wanted to say "wherever on the screen (except the navigation bar) that someone clicked, disappear the #mini_navbar_home", but clicking wherever on the container hides that
it's part of the script if helps:
var navs = new Array("#mini_navbar_home","#mini_navbar_aboutus","#mini_navbar_folan");
var colors = new Array("#home_t","#aboutus_t","#folan_t");
$(document).ready(function(){
$("#home_t").click(function(){
change_bg("#home_t")
navbar_slide_toggle("#mini_navbar_home")
});
.
.
.
$("#container:not(#navbar)").click(function(){
hide_all()
change_bg()
});
});
function change_bg(div){
for(i=0; i<colors.length; i++){
if (colors[i] != div){
$(colors[i]).css("backgroundColor", "#8895B7");
}
}
if ($(div).css("backgroundColor") == "rgb(169, 181, 212)"){
$(div).css("backgroundColor", "#8895B7")
}
else {
$(div).css("backgroundColor", "#A9B5D4")
}
}
function navbar_slide_toggle(div){
for(i=0; i<navs.length; i++){
if (navs[i] != div){
$(navs[i]).hide();
}
}
$(div).slideToggle(0);
}
function hide_all(){
for(i=0; i<navs.length; i++){
$(navs[i]).hide()
}
}
by the way, #navabr is nested with #container
i guess my solution will look silly to most of the users :D
I think you're saying that you want to hide #mini_navbar_home when a click happens on #container that is not inside #navbar. This is fairly simple:
$('#container').click(function(e){
var $navbar = $('#navbar');
if (($navbar[0] !== e.target) && // if the click wasn't on navbar itself
!$navbar.has(e.target).length // and it wasn't inside navbar
) {
$("#mini_navbar_home").hide() // hide it
}
});
The advantage this has over stopPropagation is that this allows you to keep using event bubbling on elements within #navbar. stopPropagation would break, for instance, $('a').live(...) calls.
The easier way is going to be to capture clicks on the document, and then preventing bubbling on your nav bar. That way, the click event will never reach the document, and your hide function is never triggered. You can extend the list of "blacklisted" elements later, as well, and this solution still works even if you click on an element inside of your mini nav bar.
var $mini_navbar_home = $("#mini_navbar_home");
$(document).click(function() { $mini_navbar_home.hide() });
$("#navbar").click(function(e) {
e.stopPropagation();
return false;
});

Categories