jquery not function miss element - javascript

I use a tool-tip to display error message on the page, I need it to be closed when I click elsewhere within the view. I use the below codes to control this action:
$(':not(.qtip)').click(function(){
$('.qtip').hide();
});
The ".qtip" is used for marking the tool-tip area. The tool-tip itself creates a new one when it comes out, what happened here is when I click on the tool-tip, it disappears.
But when I use a smaller scale of the selector instead of the whole body, it works fine, which is a little weird, for example:
$("#id").not('.qtip').click(function (){
$('.qtip').hide();
});

It would be advisable to just target document for handling the click outside of your tooltip; the selector for :not(.qtip) potentially returns a very big result set.
$(document).on('click', function() {
$('.qtip').hide();
}
On the tooltip itself you would need to prevent the click event from bubbling to document level, if you're not doing so yet:
$('.qtip').on('click', false);

Use event bubbling to your advantage
$(document).on("mouseup", function (e) {
var target = e.target || e.srcElement;
var container = $(".qtip");
if (container.not(target) && container.has(target).length === 0)
{
container.hide();
}
});

I suggest you to do two things:
$(document).click(function() {
$('.qtip').hide();
});
$('.qtip').click(function(e){
e.stopPropagation();
});
click of document to hide the .qtip
stop the event bubbling on click of .qtip, here click won't traverse up to the parent.

Try
$(document).on("click", function(e) {
var qtip = $(e.target).closest('.qtip');
if(!qtip.length)
$('.qtip').hide();
});

Related

EventListener not working with anchor tel:XXXXXXXXX

I have a tag with href="tel:XXXXXXXXX", and I need catch the click event.
I have tested the following code on chrome: $(document).on('click',console.log). If i click on this tag browser it calls the application, but does not trigger a click event.
$("a[href^='tel']").on('click', console.log);
This is working, but I my have a problem with content load by ajax. My code has loaded a page and after some time application added content by ajax. When i use $(document).on('click', ("a[href^='tel']", console.log), there is a problem.
$("a[href^='tel']").on("click", function(e){
e.preventDefault(); e.stopPropagation();
console.log(this);
alert(this.getAttribute("href"));
})
//or if you want to delegate your function
$(document).on('click', "a[href^='tel']", function(e){
e.preventDefault(); e.stopPropagation();
console.log(this);
alert(this.getAttribute("href"));
});
This will bind an event listener to all click on a tags with a href attribute and prevent the click itself. After click, you'll be able to use your console to see which element was click and what href was used.
Ok, i found resolve.
I use earlier event "mousedown" and change attr "href" to "only number" for disable action click.
Code:
const click2dial_Event = function(e) {
e.preventDefault();
let a = $(this), number;
if (a.attr('href') !== '#') {
number = a.attr('href');
number = number.substr(4);
a.attr('href', '#');
a.attr('data-dial', number)
a.addClass('click-to-dial');
} else {
number = a.attr('data-dial');
}
//...
};
$(document).on('mousedown', "a[href^='tel']", click2dial_Event);
$(document).on('mousedown', '.click-to-dial', click2dial_Event);
This would get the phone number from the a tag starting with a value of tel upon clicking it.
$("a[href^='tel']").on("click", function(e) {
var hrefText = this.getAttribute("href");
var str = hrefText;
var res = str.split(":");
alert(res[1]);
});
On Initial Load
I would first recommend that you wait for the initial DOM to be ready before binding any events to elements.
// DOM ready shorthand
$(function() {
$("a[href^='tel']").on('click', function(e) {
// Do work here
});
});
AJAX Content
If you are adding additional elements after the initial load you will have to bind events to those new elements as well.
You could also do something like adding a data attribute to the elements that you've bound click events to and only add to ones that don't yet have that data attribute - but that's additional unnecessary work.
Full Example Code
// DOM Ready Shorthand
$(function() {
// Click Handler
function clickEvent(e) {
// Do work here
}
// Bind click event to initial tels
$("a[href^='tel']").on('click', clickEvent);
// Arbitrary AJAX request for demonstration (wherever yours may be)
$.ajax('/newContent')
.done(function(html) {
// Adding our response HTML to the page within #someElement
$('#someElement').append(html);
// Bind click event to the new tel elements scoped to the returned html
$("a[href^='tel']", html).on('click', clickEvent);
});
});

Fire event only when clicking on an element, and not on its children

If I bind a click handler to the body element, when I click anything on the page the event is triggered. I can check the event.target on every click:
$("body").on("click", function(event) {
if (event.target.tagName == "BODY") {
...
}
});
but that seem a bit overkill. Is there a way to trigger the event only when clicking the blank area of the body itself?
You can use the eventPhase property of event. A value of 2 means that the event is currently triggering the target element:
$("body").on("click", function(event) {
//Cancel if not at target
if (event.eventPhase != 2) return;
//Other Code Here
});
Fiddle Here: http://jsfiddle.net/o0yptmmp/
You should put an
event.stopPropagation()
on all children you want to not bubble up.
jQuery Docs: http://api.jquery.com/event.stoppropagation/.
You can do it if you check on every click if the element clicked has a body parent. If the condition is false, you are clicking the body:
$("body").on("click", function(event) {
if ($(this).parents('body').length == 0) {
//Do something
}
});
In my opinion it's not a good practice, but it depends on your code and project.

jQuery Child Event Handling

I have a container element. The element may or may not have anchor tags in it. I want to listen for click events within that element. I want to handle each click only once, but I want to do something different if an anchor tag is clicked.
Issues that I've run into:
Listening at the container element level doesn't capture the anchor tag clicks: $('#ID').on('click', myFunction);
Listening to every child in the container ends up firing multiple events: $('#ID').find(*).on('click', myFunction);
How do I accomplish this?
This should work:
$('#ID').on('click', function(e) {
if ($(e.target).closest("a").length) {
anchorWasClicked();
} else {
somethingElseWasClicked();
}
});
You can check the target of the click. And as you seem to be trying to enable the click just once for every element within the container, you should then use .one():
$(function() {
$("#container").children().one("click", function(e) {
e.preventDefault(); // For testing purposes.
if ($(e.target).parents().is("a") || $(e.target).is("a")) {
// Anchor.
}
else {
// Others...
}
});
});
Demo
That's an improvement to the example I've posted in the comments previously.

jquery priority execution

Can anyone help me with this:
$('#n').click(function() {
$(this).parent().append(' delete');
$(this).next().click(function() {
alert('clicked'); //this not working
});
$(this).blur(function() {
$(this).next().remove();
});
});
JS Fiddle demo; the problem is that the blur() event is executed before click() event.
You can use a timeout to postpone the removal for some milliseconds.
example : http://jsfiddle.net/vkun9/7/
$(this).blur(function() {
var _this = this;
setTimeout(function(){$(_this).next().remove();},100);
});
I also moved the blur attaching to be outside of the click handler, as it was adding an additional one each time the element was clicked, and changed the click handler to the focus to avoid multiple remove buttons from repeated clicking on the input, as #dheerosaur noted.
so
$('#n')
.focus(function() {
$(this).parent().append(' delete');
$(this).next().click(function() {
alert('clicked'); //this not working
});
})
.blur(function() {
var _this = this;
setTimeout(function(){$(_this).next().remove();},100);
});
What you experience, though, is not a problem. It is the normal behaviour, as the element need to lose focus (fires the blur) before another element can have it.
You should also match the label for attribute with the id of the input element.
Use the outside events plugin and you can do something like this:
$('.input_field input').focus(function() {
var div = $(this).parent();
var link = $('delete').click(function(e) {
e.preventDefault();
alert('clicked');
}).appendTo(div);
$(this).data('delete', link);
}).bind('focusoutside clickoutside', function(e) {
var link = $(this).data('delete');
if (link && e.target != link[0]) {
link.remove();
}
});
First switch to using the focus event rather than the click event on your input field, some people actually use the keyboard to navigate through form fields ;-).
Then its creating the delete link, adding it to the page and storing a reference to it in on the input field.
Then with the outside event plugin we can bind focusoutside and clickoutside which get triggered when the user tabs or clicks outside the input field. By checking of the target of the event was the delete link or not we can tell if we should remove the link.
Example: http://jsfiddle.net/petersendidit/vkun9/6/
you can try setting a very short timeout in the blur event. this worked for me.
$(this).blur(function() {
setTimeout(function(){$(this).next().remove();}, 1);
});
Rather than using blur() I put together a hover()-based approach, though it does have a slightly clunky if/else statement:
$('.input_field').hover(
function(){
if ($(this).find('.delete').length) {
return false;
}
else {
$('delete')
.appendTo($(this));
}
},
function(){
if ($('#n').is(':focus')){
return false;
}
else {
$(this).find('.delete').remove();
}
}
);
JS Fiddle demo.
This approach does, however, ensure that there's only one delete link appended to the input_field (rather than the multiple links appended if the input is clicked multiple times in your original demo).

jQuery: Any way to "refresh" event handlers?

I have two divs, one that holds some stuff and the other with all possible stuff. Clicking on one of the divs will transfer items to the other div. The code I came up with is:
$("#holder > *").each(function() {
$(this).click(function(e) {
$(this).remove();
$("#bucket").append(this);
});
});
$("#bucket > *").each(function() {
$(this).click(function(e) {
$(this).remove();
$("#holder").append(this);
});
});
This one works perfectly, except that the event handlers need to be refreshed once I append or remove elements. What I mean is, if I first click on an element, it gets added to the other div, but if I click on this element again, nothing happens. I can do this manually but is there a better way to achieve this?
Try jquery live events .. the $.live(eventname, function) will bind to any current elements that match as well as elements added to the Dom in the future by javascript manipulation.
example:
$("#holder > *").live("click", function(e) {
$(this).remove();
$("#bucket").append(this);
});
$("#bucket > *").live("click", function(e) {
$(this).remove();
$("#holder").append(this);
});
Important:
Note that $.live has since been stripped from jQuery (1.9 onwards) and that you should instead use $.on.
I suggest that you refer to this answer for an updated example.
First, live is deprecated. Second, refreshing isn't what you want. You just need to attach the click handler to the right source, in this case: the document.
When you do
$(document).on('click', <id or class of element>, <function>);
the click handler is attached to the document. When the page is loaded, the click handler is attached to a specific instance of an element. When the page is reloaded, that specific instance is gone so the handler isn't going to register any clicks. But the page remains so attach the click handler to the document. Simple and easy.
Here you go, using the more intuitive delegate API:
var holder = $('#holder'),
bucket = $('#bucket');
holder.delegate('*', 'click', function(e) {
$(this).remove();
bucket.append(this);
});
bucket.delegate('*', 'click', function(e) {
$(this).remove();
holder.append(this);
});
EDIT: don't use live, it be deprecated!
Take advantage of the fact that events bubble. Using .on():
var = function( el1, el2 ) {
var things = $('#holder, #bucket');
things.each(function( index ) {
// for every click on or in this element
things.eq(index).on('click', '> *', function() {
// append will remove the element
// Number( !0 ) => 1, Number( !1 ) => 0
things.eq( Number(!index) ).append( this );
});
});
any click on any element (existing at the time of bind or not) will bubble up (assuming you haven't manually captured the event and stopped propagation). Thus, you can use that event delegation to bind only two events, one on each container. Every click that passed the selector test of the 2nd argument (in this case, > *, will remove that element and then append it to the alternate container as accesesed by things.eq( Number(!index) )
Have you looked at jQuery's live function?
The most Efficient way (dont load all event for all elements) it:
//NORMAL FUNCTION
function myfunction_click(){
//custom action
}
$('id_or_class_of_element').on('click', myfunction_click);
//LOAD OR REFRESH EVENT
$(document).on('click', 'id_or_class_of_element', myfunction_click);

Categories