I have a few location attrs on my website for a few dynamic drop downs and clickable divs. While testing I saw that they are not working on any ipads or iphones. Is there a reason for this?
They look like this
$('.storyClick').click(function () {
var context = $(this).closest('.storyClick'),
story_id = context.find('.story_id').val();
$(location).attr('href', '/chapters/' + story_id)
});
The updated code? Sure...
$('.storyClick').click(function () {
var context = $(this).closest('.storyClick'),
story_id = context.find('.story_id').val();
location.href = '/chapters/' + story_id;
});
Why are you making a jQuery object out of that?
location.href = '/chapters/' + story_id;
DOM nodes are the only things that should be wrapped in a jQuery object. (Well, ideally, nothing would be, but here we are.)
And you apparently need to handle two events using .on('click touchstart', …), because it’s not a link.
Related
I'm working on a HTML5 friendly drag and drop system and I've encountered another mystery that seems to make no sense...
The system is working in Edge - it's when I'm emulating IE8 that I encounter this latest problem.
I have a set of '.draggable' divs that get the following listener attached:
$(document).ready(function() {
$('#reset-button').click(resetDraggables);
if (!dragAndDropSupported()) {
var $draggables = $('.draggable');
$draggables.each( function (index) {
$(this).mousedown( jQueryStartDrag );
});
}
}
The draggables can be sent back to their original locations by hitting a 'reset' button. That all works fine.
The problem is - any divs that get sent back to their origins are no longer draggable. Even if I re-attach the listener in the reset function, it does not fire. Once again, this issue is only happening when I'm emulating IE8 and I don't remove the listener anywhere in my code.
function resetDraggables() {
if ( !$('#reset-button').hasClass('inactive') ) {
var $dropTargets = $('.drop-target');
$dropTargets.each(function (index) {
var draggableId = $(this).attr('data-contains');
var $originDraggable = $('#' + draggableId);
if ($originDraggable.attr('id')!=undefined) {
var $droppedDraggable = $(this).find('.draggable');
$droppedDraggable.remove();
$originDraggable.removeClass('inactive').addClass('draggable').attr('draggable', 'true').css('filter', 'alpha(opacity=100)').hide().fadeIn('fast');
$('#' + draggableId).mousedown( jQueryStartDrag );
$(this).removeClass('occupied').attr('data-contains', '');
$('#reset-button').addClass('inactive');
}
});
}
}
I've realised it's the $droppedDraggable.remove() line that's causing the problem. I'm not sure why a line to remove ONE object would remove the listener from another. The $droppedDraggable object was cloned from the other; Is that causing the issue?
Any ideas what might be going on?
OK, so I replaced the jQuery remove() lines with...
var droppedDraggable = document.getElementById('dropped-' + draggableId);
droppedDraggable.outerHTML = "";
...and that has done the trick. I'm guessing there must have been some hidden association made between the objects when one was cloned from the other and remove()ing one removed the mousedown listener from the other.
If anyone has a better theory, feel free to let me know, but this seems to have solved the problem.
Edit
I've just realised the above fixed the problem in IE8, but not in 9. Great! If anyone has any pointers on how NOT to include a bunch of browser-specific work arounds in my code, I'd be very keen to hear them. Thanks.
I am currently learning JavaScript using O'Reilly's "Learning Web Application Development". In the example, we are constructing a website using HTML and CSS, which includes 3 tabs which should be able to be selected and become the "active" tab. The books claims that the following two ways of writing the tab code are equivalent:
1)
var main = function() {
"use strict";
var tabNumber;
for (tabNumber=1;tabNumber<=3;tabNumber++) {
var tabSelector = ".tabs a:nth-child("+tabNumber+") span";
$(tabSelector).on("click",function() {
$(".tabs span").removeClass("active");
$(tabSelector).addClass("active");
$("main .content").empty();
return false;
});
}
}
$(document).ready(main);
2)
var main = function() {
"use strict";
$(".tabs a span").toArray().forEach(function(element) {
$(element).on("click", function() {
console.print("this element: " + element);
$(".tabs span").removeClass("active");
$(element).addClass("active");
$("main .content").empty();
return false;
});
});
}
$(document).ready(main);
However, they do not output the same result. The version using forEach works correctly, so that when I click one of the tabs the attention moves to that tab and it becomes highlighted. However, in the version using a for loop, whenever I click any tab, the attention always moves to the last tab. To confirm what is happening, I printed out the name of the element inside the event listener with both methods, using 3 tabs total. And using the for loop, no matter which tab I click I am getting a response of
"this element: .tabs a:nth-child(3) span"
Could someone please help me explain why this is happening? Why is the output different using for or forEach? And why, using for, is it always passing the last element of tabs to the event listener?
Looks like there's a problem here:
var tabSelector = ".tabs a:nth-child("+tabNumber+") span";
$tabSelector.on("click",function(){
You've created a variable that doesn't have the $ at the beginning, then attached the event to a variable (not sure what it would refer to) with a $ at the beginning.
It should be changed to this, I believe:
$(tabSelector).on("click",function(){
In the for loop solution, you are setting tabSelector multiple times like so:
var tabSelector = ".tabs a:nth-child("+tabNumber+") span";
This selector is, in the end, going to be set to the last tabNumber, which is always going to be called when you make a reference to it:
$(tabSelector).addClass("active");
To avoid that, replace it by this, which will be different for each of them:
$(this).addClass("active");
JS Fiddle Demo
I have a list composed by some divs, all of them have a info link with the class .lnkInfo. When clicked it should trigger a function that adds the class show to another div (like some sort of PopUp) so it is visible and when clicked again it should hide it.
I am quite certain this must be a very basic thing and most likely I will get some scoffs...but hey! Once I have this down that's one thing less I will ever have to ask again. Anyway I am starting to leave the safety of html and css to start learning JS, PHP and the like and I came to a bit of a problem.
When testing it before it was working, that was until I added another div, it only worked with the first one, reading a bit and with some suggestion I realized it must be something related to a array, the problem is that I am not quite certain of the syntax for accomplishing what I am visualizing.
Any help would be deeply appreciated.
This is my JS code and below I will attack a Fiddle of how the html looks just in case.
var infoLab = document.getElementsByClassName('lnkInfo'),
closeInfo = document.getElementById('btnCerrar');
infoLab.addEventListener('click', function () {
for (var i = 0 ; i < infoLab.length; i++) {
var links = infoLab[i];
displayPopUp('popUpCorrecto1', 'infoLab[i]');
};
});
function displayPopUp(pIdDiv, infoLab[i]){
var display = document.getElementById(pIdDiv),
for (var i = 0 ; i < infoLab.length; i++) {
infoLab[i]
newClass ='';
newClass = display.className.replace('hide','');
display.className = newClass + ' show';
};
}
JSFiddle.
Thanks a lot in advance and sorry for any facepalms!
EDIT:
This a jQuery function (in another file) that I need to call using the link because it fetches the data that will be inside the div, thus why I wanted to just add a hide/show.
$(".lnkInfo").click(function() {
var id = $('#txtId').val();
var request = $.ajax({
url: "includes/functionsLabs.php",
type: "post",
data: {
'call': 'displayInfoLabs',
'pId':id},
dataType: 'html',
success: function(response){
$('#info').html(response);
}
});
});
EDIT 2:
To a future reader of this question,
If you managed to find this answer throughout space and time, know that this is how the solution ended being, may it help you in your quest to stop being a noob.
SOLUTION
Here is a rudimentary working example of how to make a popup appear after clicking on a specific element given your current code. Note that I added an id to your link element.
// Select the element.
var infoLink1 = document.getElementById('infoLink1');
// Add an event listener to that element.
infoLink1.addEventListener('click', function () {
displayPopUp('popUpCorrecto1');
});
// Display a the popup by removing it's default "hide"
// class and adding a "show" class.
function displayPopUp(pIdDiv) {
var display = document.getElementById(pIdDiv);
var newClass = display.className.replace('hide', '');
display.className = newClass + ' show';
}
Fiddle.
There are various ways to generalize this to work for all links/popups. You could add a data-link-number=1, data-link-number=2, etc to each link element (more on data-). Select an element containing all of your links. Bind to that element an event listener that, when clicked, detects the link element that was clicked (see event delegation / "bubbling"). You can determine which link was clicked based on the value of your data-link-number attribute. Then show the appropriate popup.
You may also want to use jQuery for this. Changing an element's class by setting it's className property makes for brittle DOM code. There is an addClass and a removeClass method available. jQuery's events also work cross-browser; element.addEventListener() will not work in IE8 which still has a significant market share.
I'm creating a notification system for a game to work similar to how notifications might work in a phone.
The notifications are all created initially, hidden, and later the game is supposed to "activate" certain ones from in-game triggers.
I'm running into problems when trying to keep the notifications separate in terms of their classes. Each notification starts off as a small rectangular box with only the title visible. Upon clicking, the notification expands and the description becomes visible.
Right now, clicking a notification does expand that notification and display its notification, but any other notifications also show their descriptions as well.
Example code:
var NotificationItems = new Array();
scope.registerNotification = function(title, description)
{
//add it to the array
NotificationItems.push(new scope.Application(title, description));
var $NotificationContainer = $("#NotificationContainer");
$NotificationContainer.append('<div class="Notification" title="'+title+'"></div>');
var $thisNotification = $NotificationContainer.children('.Notification[title='+title+']');
$thisNotification.append('<div class="NotificationTitle">'+title+'</div>');
$thisNotification.append('<div class="NotificationDescription">'+description+'</div>');
$(".NotificationDescription").hide();
$thisNotification.click(function()
{
$(this).toggleClass('expanded');
$('.NotificationDescription').slideToggle('slow');
});
}
How can I get the .NotificationDescription to be uniquely recognized for each notification?
You could try the .children() method: jQuery docs for children method
$thisNotification.click(function()
{
$(this).toggleClass('expanded').children('.NotificationDescription').slideToggle('slow');
});
Just find the right one for the clicked element:
$thisNotification.click(function()
{
$(this).toggleClass('expanded');
$(this).find('.NotificationDescription').slideToggle('slow');
});
You can chain the calls if you like:
$thisNotification.click(function()
{
$(this).toggleClass('expanded').find('.NotificationDescription').slideToggle('slow');
});
You might want to try out event delegations.
$('#NotificationContainer > div.Notification').live('click',function()
{
$(this).toggleClass('expanded').find('div.NotificationDescription').slideToggle('slow');
});
This way you only need to attach the event once (on init), and a single event handles all the notifications.
You also should add all your html at one time:
var $NotificationContainer = $("#NotificationContainer");
var $Notification = $('<div class="Notification" title="'+title+'"></div>');
$Notification.append('<div class="NotificationTitle">'+title+'</div>');
$Notification.append('<div class="NotificationDescription">'+description+'</div>');
$NotificationContainer.append($Notification);
notice the subtle difference, we're building the elements in jquery rather than the dom, and append them all at once.
The best way to understand this is to look at this fiddle.
Notice how mouse wheel over the fixed content in the red box does nothing. I would like the scrollable div to scroll.
In case the fiddle dies - basically I have a scrollable div with a fixed element over it. Typically when you mouse wheel over a scrollable div it will of course scroll. But if you are over the fixed element instead then no scroll happens. Depending on your site layout this could be counter intuitive to a user.
jQuery solutions are okay.
A much, MUCH simpler, but much less widely supported, answer is the following:
#fixed{ pointer-events:none; }
jsFiddle
Doesn't work in IE at all though unfortunately! But you could use modernizr or somesuch to detect whether it was supported and use the jQuery as a stop-gap where it isn't.
Courtesy of Mr. Dominic Stubbs
I had this problem and this works for me (using jquery):
$(document).ready( function (){
$('#fixed').on('mousewheel',function(event) {
var scroll = $('#container').scrollTop();
$('#container').scrollTop(scroll - event.originalEvent.wheelDeltaY);
return true;
});
});
Works on Safari and Chrome: http://jsfiddle.net/5bwWe/36/
I think this does what you're asking for!
$('#fixed').bind('mousewheel', function(e){
var scrollTo= (e.wheelDelta*-1) + $('#container').scrollTop();
$("#container").scrollTop(scrollTo);
});
EDIT: Updated the jsFiddle link to one that actually works
DOUBLE EDIT: Best to dispense with the .animate() on further testing...
jsFiddle Example
TRIPLE EDIT:
Much less pretty (and will probably be horribly slow with a lot of elements on the page), but this works and I owe a lot to this stackoverflow answer.
$('#fixed').bind('mousewheel', function(e) {
var potentialScrollElements = findIntersectors($('#fixed'), $('*:not(#fixed,body,html)'));
$.each(potentialScrollElements, function(index, Element) {
var hasVerticalScrollbar = $(Element)[0].scrollHeight > $(Element)[0].clientHeight;
if (hasVerticalScrollbar) {
var scrollTo = (e.wheelDelta * -1) + $(Element).scrollTop();
$(Element).scrollTop(scrollTo);
}
});
});
function findIntersectors(targetSelector, intersectorsSelector) {
var intersectors = [];
var $target = $(targetSelector);
var tAxis = $target.offset();
var t_x = [tAxis.left, tAxis.left + $target.outerWidth()];
var t_y = [tAxis.top, tAxis.top + $target.outerHeight()];
$(intersectorsSelector).each(function() {
var $this = $(this);
var thisPos = $this.offset();
var i_x = [thisPos.left, thisPos.left + $this.outerWidth()]
var i_y = [thisPos.top, thisPos.top + $this.outerHeight()];
if (t_x[0] < i_x[1] && t_x[1] > i_x[0] && t_y[0] < i_y[1] && t_y[1] > i_y[0]) {
intersectors.push($this);
}
});
return intersectors;
}
UPDATE (August 2016): It seems the browser implementations have changed and it's no longer possible to re-dispatch a WheelEvent on a different target. See the discussion here.
For an alternative solution that should work across platforms, try this:
var target = $('#container').get(0);
$('#fixed').on('wheel', function (e) {
var o = e.originalEvent;
target.scrollTop += o.deltaY;
target.scrollLeft += o.deltaX;
});
Working example: https://gist.run/?id=6a8830cb3b0564e7b16a4f31a9405386
Original answer below:
Actually, the best way to do it is to copy the original event. I've tried #Tuokakouan's code but scrolling behaves strangely (too fast) when we use a multitouch touchpad that has inertia.
Here's my code:
var target = $('#container').get(0);
$('#fixed').on('wheel', function(e){
var newEvent = new WheelEvent(e.originalEvent.type, e.originalEvent);
target.dispatchEvent(newEvent);
});
You can try it here: http://jsfiddle.net/NIXin/t2expL6u/1/
What I'm trying to do now is also to pass the touch events, without much success. Since mobile phones and touch screens are now more popular, some people might want to scroll using their fingers instead - neither of the answers offered solves that.
Well,all solutions with js are kind of delayed when scrolling on it. if the fixed element you use is just for display, then I have a good css tricks to achieve that.
make the fixed element z-index:-1 and the container element background-color:transparent
here is the jsfiddle you can see: https://jsfiddle.net/LeeConan/4xz0vcgf/1/