In my sample work, I would like to detect the click event from anywhere of my html element. It works when I click on direct html but not for iFrames - so I would like to hear from any where of my window. What is the correct way to do that using jQuery ?
Even I would like to hear from dynamic htmls too. (my case there is a loop with numbers
here is the demo
my code :
var findAllClicks = function() {
$(document).on('click', '*', function() {
console.log($(this)[0]); //only works on direct html element.
})
}
var outsideFunction = function() {
console.log('loop ends');
}
outsideFunction();
$(function() {
//finding click events from any where.
findAllClicks();
var total = 1000;
var i = 0;
var iterate = function() {
setTimeout(function() {
var place = $('#iFrame1').contents().find('#iFrame2').contents().find('body');
place.append('<ul class="list"></ul>');
for (i = 0; i < total; i++) {
place.find('.list').append('<li>' + i + '</li>');
}
}, 3000);
//how to find all this done from outside of this function?
}
var iFrame1 = $('<iframe />', {
id: 'iFrame1'
});
var iFrame2 = $('<iframe />', {
id: 'iFrame2'
});
var button2 = $('<button />', {
text: 'Child Button',
click: iterate
});
var button = $('<button />', {
text: 'Click Me',
click: function() {
$(this).parents('body').append(iFrame2);
$('#iFrame1').contents().find('#iFrame2').contents().find('body').append(button2);
}
});
setTimeout(function() {
$('.container').append(iFrame1);
$('#iFrame1').contents().find('body').append(button);
}, 1000);
});
Sorry if I misunderstood but if you just wanna log the number of clicks on the window, you could use
window.onclick = function() {count++;console.log(count);};
Related
I'm creating a javascript function which creates a modal. Here's the function:
function createModal(options) {
var self = this;
modalHeaderText = options.header;
modalBodyText = options.body;
$modal = $('<div />').addClass('modal').appendTo('body');
$modalOverlay = $('<div />').addClass('modal-overlay').appendTo($modal);
$modalContainer = $('<div />').addClass('modal-container').appendTo($modal);
$modalHeader = $('<div />').addClass('modal-header').addClass(options.headerClass).html(modalHeaderText).appendTo($modalContainer);
$modalBody = $('<div />').addClass('modal-body').addClass(options.bodyClass).html(modalBodyText).appendTo($modalContainer);
if (options.buttons) {
$modalFooter = $('<div />').addClass('modal-footer').appendTo($modalContainer);
$.each(options.buttons, function(name, buttonOptions) {
$modalButton = $('<button />').addClass(buttonOptions.class).html(name).appendTo($modalFooter);
if(buttonOptions.callback) {
$modalButton.on('click', function() {
buttonOptions.callback();
});
} else {
$modalButton.on('click', function(e) {
$modal.remove();
});
};
});
};
$modal.addClass('active');
if (options.closeOnOverlayClick == true) {
$modalOverlay.on('click', function(e) {
$modal.remove();
});
};
};
This works fine, but I want to be able to call the function within the same function, like this:
$('#modal').on('click', function(e){
e.preventDefault();
createModal({
header : 'Enter your name',
body : '<input type="text" class="name" />',
buttons : {
'OK' : {
class : 'btn btn-success',
callback : function() {
var name = self.$modalBody.find('.name').val();
if (!name) {
createModal({
header : 'Error',
body : 'You must provide a name',
buttons : {
'OK' : {
class : 'btn'
}
}
});
} else {
alert(name);
};
},
},
'Close' : {
class : 'btn btn-error'
}
}
});
});
What I want is the following: when someone clicks the button with ID "modal" (hence "#modal"), a modal is opened with a input. When the OK-button is pressed, it checks if the input ('name') has a value. If so, the value is shown in an alert. If not, a new modal is openend (over the current modal) with the text 'You must provide a name'.
If I enter a name, it works. The name is shown in an alert, and also the close button works. But if I do not enter a name, and the second modal is shown, all the variables in the function are overwritten.
How can I preserve the variables/elements from the first modal so that, after the second modal is shown (and cleared), the buttons from the first modal still work.
I've created a JSFiddle here: https://jsfiddle.net/6pq7ce0a/2/
You can test it like this:
1) click on 'open modal'
2) enter a name
3) click on 'ok'
4) the name is shown in an alert
==> this works
The problem is here:
1) click on 'open modal'
2) do NOT enter a name
3) click on 'ok'
4) a new modal is shown
5) click on 'ok' in the new (error) modal
6) the buttons from the first modal (with the input field) don't work anymore
Thanks in advance!
Update
If I change the function to the function below, the first modal does not work at all.
function createModal(options) {
var self = this;
var modalHeaderText = options.header;
var modalBodyText = options.body;
var $modal = $('<div />').addClass('modal').appendTo('body');
var $modalOverlay = $('<div />').addClass('modal-overlay').appendTo($modal);
var $modalContainer = $('<div />').addClass('modal-container').appendTo($modal);
var $modalHeader = $('<div />').addClass('modal-header').addClass(options.headerClass).html(modalHeaderText).appendTo($modalContainer);
var $modalBody = $('<div />').addClass('modal-body').addClass(options.bodyClass).html(modalBodyText).appendTo($modalContainer);
if (options.buttons) {
var $modalFooter = $('<div />').addClass('modal-footer').appendTo($modalContainer);
$.each(options.buttons, function(name, buttonOptions) {
var $modalButton = $('<button />').addClass(buttonOptions.class).html(name).appendTo($modalFooter);
if(buttonOptions.callback) {
$modalButton.on('click', function() {
buttonOptions.callback();
});
} else {
$modalButton.on('click', function(e) {
$modal.remove();
});
};
});
};
$modal.addClass('active');
if (options.closeOnOverlayClick == true) {
$modalOverlay.on('click', function(e) {
$modal.remove();
});
};
};
The problem is here:
var name = self.$modalBody.find('.name').val();
$modalBody is not defined if I add 'var' to all the elements.
So in addition to the comments above regarding not declaring var you also are storing a reference to window in the self variable. To avoid all of that I went down the road in this fiddle: https://jsfiddle.net/10fanzw6/1/.
Quick explanation.
First don't assign this to self as this is window
Second assign everything to the empty self object as well as a local var (for better readability)
Third pass the self var back to any button callback giving you access to any part of the modal you may need.
For posterity, including the updated function here:
function createModal(options) {
var self = {};
var modalHeaderText = options.header;
var modalBodyText = options.body;
var $modal = self.$modal = $('<div />').addClass('modal').appendTo('body');
var $modalOverlay = self.$modalOverlay = $('<div />').addClass('modal-overlay').appendTo($modal);
var $modalContainer = self.$modalContainer = $('<div />').addClass('modal-container').appendTo(self.$modal);
self.$modalHeader = $('<div />').addClass('modal-header').addClass(options.headerClass).html(modalHeaderText).appendTo($modalContainer);
self.$modalBody = $('<div />').addClass('modal-body').addClass(options.bodyClass).html(modalBodyText).appendTo($modalContainer);
if (options.buttons) {
var $modalFooter = self.$modalFooter = $('<div />').addClass('modal-footer').appendTo($modalContainer);
$.each(options.buttons, function(name, buttonOptions) {
var $modalButton = $('<button />').addClass(buttonOptions.class).html(name).appendTo($modalFooter);
if (buttonOptions.callback) {
$modalButton.on('click', function() {
buttonOptions.callback(self);
});
} else {
$modalButton.on('click', function(e) {
$modal.remove();
});
};
});
};
$modal.addClass('active');
if (options.closeOnOverlayClick == true) {
$modalOverlay.on('click', function(e) {
$modal.remove();
});
};
};
$('#modal').on('click', function(e) {
e.preventDefault();
createModal({
header: 'Enter your name',
body: '<input type="text" class="name" />',
buttons: {
'OK': {
class: 'btn btn-success',
callback: function(modal) {
var name = modal.$modalBody.find('.name').val();
if (!name) {
createModal({
header: 'Error',
body: 'You must provide a name',
buttons: {
'OK': {
class: 'btn'
}
}
});
} else {
alert(name);
};
},
},
'Close': {
class: 'btn btn-error'
}
}
});
});
Simply not using var in front of $modal variable causing it to be stored in window scope. When the next next $modal is closed, the variable is referencing to an already removed element, so nothing happens on first modal's Close button click.
I'm obviously missing something, but I haven't been able to find what I am doing wrong and I have been staring at this for entirely too long
function message(options) {
...
options.onclose = options.onclose || null;
...
this.gui = document.createElement('div');
this.msg = document.createElement('div');
...
if (options.onclose != null) {
var close = document.createElement('i');
close.innerHTML = 'close';
close.className = 'material-icons close';
close.onclick = options.onclose;
console.log(close.onclick);
this.msg.append(close);
}
this.msg.innerHTML += options.msg;
this.gui.append(this.msg);
...
return this.gui;
}
msgContainer.append(new message({
class: 'update',
sticky: true,
icon: 'mic',
msg: 'You are in a call',
onclose: () => { console.log('click'); }
}));
from the developer console document.querySelector('.close').onclick is null, but if I add an on click document.querySelector('.close').onclick = () => { console.log('click'); }; it works?
Why it wont work is because on click is a function:
document.querySelector('.close').onclick
doesn't do anything so why call it.
document.querySelector('.close').onclick = () {
alert("did something");
}
so the real question is what do you want to do when clicked? create a new link or div.. look below. I would start using jQuery.
jQuery answer:
$(document).ready(function(){
$(".myclass").click(function(){
$(".container_div").append("<a href='test.php'>test link</a>");
// also .prepend, .html are good too
});
});
Here is working example. I changed your code a little bit. You can add more events by passing it to an array. I used addEventListener.
var msgContainer = document.getElementById('msgContainer');
function message(options) {
options.onclose = options.onclose || null;
this.gui = document.createElement('div');
this.msg = document.createElement('div');
if (options.onclose != null) {
var close = document.createElement('i');
close.innerHTML = 'closepp';
close.className = 'material-icons close';
close.dataset.action = 'close';
this.msg.append(close);
}
this.msg.innerHTML += options.msg;
this.gui.append(this.msg);
// Create listeners dynamically later on
events = [
{ selector: close.dataset.action, eventType: 'click', event: options.onclose }
];
renderElement(this.gui, events);
}
function renderElement(element, events) {
msgContainer.append(element);
for (i = 0; i < events.length; i++) {
var currentEvent = events[i];
var selector = element.querySelector('[data-action="' + currentEvent['selector'] + '"]');
selector.addEventListener(currentEvent['eventType'], currentEvent['event'].bind(this), false);
}
}
new message({
class: 'update',
sticky: true,
icon: 'mic',
msg: 'You are in a call',
onclose: () => { console.log('click'); }
});
<div id="msgContainer">
</div>
I finally figured it out! setting innerHTML makes chrome rebuild the dom and in the process it loses the onclick event, onclick works fine if I use textContent instead of innerHTML. In the below example if you comment out the last line of JS the onclick works, here's the same thing in jsFiddle
var blah = document.getElementById('blah');
var div = document.createElement('button');
div.style['background-color'] = 'black';
div.style.padding = '20px;';
div.style.innerHTML = 'a';
div.onclick = () => { alert('wtf');};
blah.appendChild(div);
// Uncomment this to make onclick stop working
blah.innerHTML += ' this is the culprit';
<div id="blah">
</div>
I would like to know when my iteration completes from outside of my web page, where my iteration happening inside of a frame's child iframe
here my example: Live URL click first button and second button wait 3 sec.
$(function(){
var total = 1000;
var i = 0;
var iterate = function(){
setTimeout(function(){
var place = $('#iFrame1').contents().find('#iFrame2').contents().find('body');
place.append('<ul class="list"></ul>');
for(i=0; i < total; i++) {
place.find('.list').append('<li>'+i+'</li>');
}
}, 3000);
//how to find all this done from outside of this function?
}
var iFrame1 = $('<iframe />', {id:'iFrame1'});
var iFrame2 = $('<iframe />', {id:'iFrame2'});
var button2 = $('<button />', {text:'Child Button', click:iterate});
var button = $('<button />',
{
text:'Click Me',
click:function(){
$(this).parents('body').append(iFrame2);
$('#iFrame1').contents().find('#iFrame2').contents().find('body').append( button2 );
}
}
);
setTimeout(function(){
$('.container').append( iFrame1 );
$('#iFrame1').contents().find('body').append(button);
},1000);
});
After the place had all lis how to I know from outside of the document. I am running my code from chrome browser console.
I have created this fiddle to attempt to answer this question. Here's what I have done:
Added this handler to run when the iteration is complete:
var onIterationDone = function() {
console.log("Iteration Done");
alert("Done!");
};
Wired this handler to a custom event iterationDone on button2 right after it's added:
var button = $('<button />', {
text: 'Click Me',
click: function() {
$(this).parents('body').append(iFrame2);
$('#iFrame1').contents().find('#iFrame2').contents().find('body').append(button2);
button2.on('iterationDone', onIterationDone);
}
});
Fired the custom event as soon as the iteration is done:
setTimeout(function() {
var place = $('#iFrame1').contents().find('#iFrame2').contents().find('body');
place.append('<ul class="list"></ul>');
for (i = 0; i < total; i++) {
place.find('.list').append('<li>' + i + '</li>');
}
// Trigger the custom event.
button2.trigger('iterationDone');
}, 1000);
Is this what you wanted to achieve ?
If I create a new element with jquery and add a click function like above, the click-function do not work certain.
I would like to set focus on the eqivalent element but it focus only the last one.
To better explain I made a jsfiddel here
var newUL = $('<ul />',{
text: "ul text",
'class': 'errorListUl'
});
for ( var i = 0; errorList[i]; i++ ) {
var el = errorList[i]; console.log("element: ",el.element);
$( "<li/>", {
"class": "errorListLi",
html: "<span>"+errorList[i].element.name+"</span><span>"+errorList[i].method+"</span>"+errorList[i].message,
click: function() {
$(el.element).focus(); console.log("go to: ",$(el.element));
}
}).appendTo(newUL);
}
newUL.appendTo( $('#response') );
Your for loop finishes before your element is inserted into dom. Due to this fact, it will add handlers only on the last element. You need an anonymous function (closure) to handle this issue. Updated fiddle.
var newUL = $('<ul />',{
html: "Click on error-message (li) shout focus the equivalent element. But the focus is always set to the last element.<br><br>",
'class': 'errorListUl'
});
for ( var i = 0; errorList[i]; i++ ) {
(function(_i) {
var el = errorList[_i],
htmlText = "<span>" + el.element.name + "</span><span>" + el.method + "</span>" + el.message;
console.log("element: ", el.element);
$( "<li/>", {
"class": "errorListLi",
html: htmlText,
click: function() {
$(el.element).focus(); console.log("go to: ",$(el.element));
}
}).appendTo(newUL);
})(i)
}
newUL.appendTo( $('#response') );
You have a problem of closure: this link will explain better than me :)
check my modifications on your fiddle
var errorList = [];
var check = function( element ) {
errorList.push({
message: "text-message",
element: element,
method: "text-method"
});
}
$(document).find("input, select, textarea").each(function(i, item) {
var checked = check(item);
});
console.log(errorList);
var newUL = $('<ul />',{
html: "Click on error-message (li) shout focus the equivalent element. But the focus is always set to the last element.<br><br>",
'class': 'errorListUl'
});
for ( var i = 0; errorList[i]; i++ ) {
var _item = errorList[i];
(function (item) {
$( "<li/>", {
"class": "errorListLi",
html: "<span>"+item.element.name+"</span><span>"+item.method+"</span>"+item.message,
click: function() {
$(item.element).focus();
}
}).appendTo(newUL);
})(_item)
}
newUL.appendTo( $('#response') );
The problem here is that you are using the el variable in the click handler, which is defined in the outer closure and which will change to be the last of the list, when the for loop has completed. If you want to change the behaviour to be correct, you must write the loop as:
for ( var i = 0; errorList[i]; i++ ) {
var el = errorList[i];
console.log("element: ",el.element);
(function (el2) {
$( "<li/>", {
"class": "errorListLi",
html: "<span>"+errorList[i].element.name+"</span><span>"+errorList[i].method+"</span>"+errorList[i].message,
click: function() {
$(el2.element).focus();
console.log("go to: ",$(el2.element));
}
}).appendTo(newUL);
})(el);
}
This way, you will create a new variable el2, which will not change over the loop, since it is copied to the instantly invoking function body.
As stated in title. Im trying to create a tooltip which will have some buttons inside. The problems is with the onclick function, which is somehow not working. This is the actual code I have.
$('#button_nowtime').popover({
trigger: 'click',
html: 'true',
title: "<b>Čas</b>",
content:
function() {
var returnstring="",button;
for(var i=0; i<files.length; i++){
button = document.createElement("a");
button.innerText = fileNametoButtonTime(files[i]);
button.onclick = (function() {
var currentID = i;
return function() {
alert("asd"); currentTimeIndex=currentID; setNowTimeButton(); drawImage(); $('#button_nowtime').popover('hide');
}
})();
button.href="#";
returnstring+=button.outerHTML;
returnstring+=" | ";
}
return returnstring;
}
});
The buttons appear in the tooltip but not react to the onclick function.
I've adjusted your original question (Demo Fiddle: http://jsfiddle.net/WfcM9/) to use jQuery to instead create the buttons and event handling.
With jQuery, it'll be adding the buttons to the DOM, giving them an class then outside the popover() function, give it a $(document).on('click', 'classname') for the document to wait for.
With jQuery .on('click')
<script>
var files = [ "FileOne", "FiletWO" ],
options = {
trigger: 'click',
html: 'true',
title: "<b>Čas</b>",
content: function() {
var $buttonsContainer = $('<div />');
for( var i=0; i< files.length; i++ ) {
var addLink = $('<a>').addClass('fileclick btn btn-default')
.attr( 'data-id', files[i] )
.html( files[i] );
$buttonsContainer.append( addLink );
}
return $buttonsContainer;
}
};
/**
* Create the Popover with above Options
**/
$('#button_nowtime').popover(options);
/**
* Listen for the Class Click on the buttons created.
**/
$(document).on('click', '.fileclick', function() {
alert( $(this).data('id') );
//Alerts FileOne or FileTwo
});
</script>
Fiddle Demo: http://jsfiddle.net/M2HQD/3/