Call onclick attribute programatically and talk to the event parameter - javascript

I have read the other post relating to this matter. Unfortunately it has not resolved my problem. I am happy to use jQuery, so I am looking for the cleanest solution.
I have radio buttons defined as follow:
a = 5;
input.value = "myButton";
input.onclick = (function (a) {
return function (e) {
changeSelectedRadio(e.srcElement, a);
};
})(a);
I need to be able to execute this when user click on the radio button (this works fine), and programatically.
I have tried:
$("input[type='radio'][value='myButton']").triggerHandler("click");
$("input[type='radio'][value='myButton']").click();
Both produce the same result: e (the event parameter) does not exist.
$("input[type='radio'][value='myButton']").onclick();
Does not work
Changing the input.onclick to input.click also did not work. When the use click, the function does not get triggered.
Thanks

If you're using jquery already, might as well build the inputs that way:
var input = $('<input value="something">').click(function(){
var elem = $(this); // the element clicked, as a jquery obj
alert(elem.attr('id');
});
$('body').append(input);
$('input').trigger('click');
Adjust the selectors as needed, and you'll need to actually append the elements to the DOM, but it'll work.

try this:
$("input[type='radio'][value='myButton']").bind( "click", function() {
alert( "clicked" );
});

What is passed to the function is a jQuery event, not a native event. You can use the target element to get at the source that was clicked on or use this to reference the properties of the object directly. See fiddle at http://jsfiddle.net/YQh3Q/
<p><input id="foo1" name="foo" type="radio" value="0" checked="checked"> Foo1</p>
<p><input id="foo2" name="foo" type="radio" value="1"> Foo2</p>
(function ($) {
var input = document.getElementById("foo2");
var a = 5;
input.value = "myButton";
input.onclick = (function (a) {
return function (e) {
alert(e.target + '|' + this.id);
};
})(a);
$("input[type='radio'][value='myButton']").each(function() {
$(this).trigger("click");
});
})(jQuery);
Alternatively (and probably better) you can use a pure jQuery solution
$(function() {
var a = 5;
$('input#foo2').on('click', function() {
changeSelectedRadio(this, a);
})
.val('myButton');
$("input[type='radio'][value='myButton']").trigger('click');
});

Its best to use addEventListener() you can add all types of events. example: "click", "mousemove", "mouseover", "mouseout", "resize" and many more. the false at the end is to stop the event from traversing up the dom. If you want parent dom objects to also receive the event just change it to true. also this example requires no javascript libraries. This is just plain old javascript and will work in every browser with nothing extra needed.
Also addEventListener() is better than onClick() as you can add an unlimited number of event listeners to a dom element. If you have an onClick() on an element and then set another onClick() on the same element you have overwritten the first onClick(). Using addEventListener() if i want multiple click events to trigger when i click on an element i can do it with no problem.
If you want data about the element that is triggering the event you can pass the event to the function. You will see in my example function(e) e is the event and you can use e or this to target the element that is being triggered. Using e or this i can also get more data about the triggered event. for example if the event was a mousemove or mouseclick i can get the x and y position of the mouse at the time of the event.
<!DOCTYPE html>
<html>
<head>
<title>exampe</title>
</head>
<body>
<a id="test" href="">test</a>
<script>
document.getElementById("test").addEventListener("click",function(e){
alert('hello world');
alert('my element '+e);
alert('my element '+this);
},false);
</script>
</body>
</html>
if you want to have addEventListener call a function just change the 2nd value to the function name like this.
document.getElementById("test").addEventListener("click",f1,false);
this will execute the function
function f1(){ ... }
When you want to remove an event listener just call target.removeEventListener(type, listener[, useCapture]). Very simple and easy to manage.

Related

How to bind 'this' to click listener and use the event - es6

I have a multistep form, with 4 frameset. Each one must come in when I press the "Next" button (of course)
My ES6 modular code cointains something like this:
class FormController {
// 1. describe and initiate object
constructor() {
this.nextBtn = $(".next");
this.next_fs;
....
this.events();
}
// EVENTS LISTENER
events(){
this.nextBtn.on("click", this.nextClicked.bind(this));
// other listeners
}
nextClicked() {
this.next_fs = $(this)
.parent()
.next(); // this is the next fieldset
// some actions...
}
// rest of the code
}
My problem is the following:
I need to bind "this" inside nextClicked function to be able tu use all variables and methods like this.next_fs, this.saveData(), etc...
But I also need to know which button has been clicked, and I cannot know that because this is no more "this button", and I cannot pass a variable (let's call it 'e') to trace the e.target.
What's the matter with my code? I know that's something stupid that I'm not seeing.
Thanks!
But I also need to know which button has been clicked, and I cannot know that because "this" is no more "this button", and I cannot pass a variable (let's call it 'e') to trace the e.target
The browser's event triggering code passes that. You just need to read it.
nextClicked(e) {
"...and I cannot pass a variable (let's call it 'e') to trace the e.target"
Actually, you don't need to pass it as variable, because even if you don't pass the e you can get it in nextClicked because browsers do it by default, so it will come as parameter if you declare the function as nextClicked(e){...} and keep the bind as you have.
Or, you can pass parameters after this, such as ...bind(this, this.nextBtn), then the first parameter on nextCliked will be the button.
See below these two possibilities I mentioned:
$(".buttons").on("click", this.nextClicked.bind(this))
function nextClicked(e){
//here your context is the same as when you binded the function, but you have the event
let target = e.target;
console.log(target.id);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button id="btn-1" class="buttons">click me 1</button>
<button id="btn-2" class="buttons">click me 2</button>
let nextButton = $("#btn-1")[0];
$(".buttons").on("click", this.nextClicked.bind(this, nextButton))
function nextClicked(nextBtn, e) {
//here your context is the same as when you binded the function,
//but you have the button AND the event
console.log("NextButton Id: " + nextBtn.id);
console.log("Clicked button Id: " + e.target.id);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button id="btn-1" class="buttons">next</button>
<button id="btn-2" class="buttons">previous</button>
You are doing
this.next_fs = $(this)
But, earlier you set this to an instance of FormController
this.nextBtn.on("click", this.nextClicked.bind(this));
so what you are doing is
this.next_fs = $( (FormController)this);
You are expecting jQuery to work with a class instance, instead of the event object.
I strongly discourage you from using $(this) ever in a event handling context. this can change it's meaning as you have shown in your sample by the code breaking.
Always use event.target or event.currentTarget. I prefer currentTarget as it points to the element on which the event was bound, and not a deeper lying element within that element.
so your code should be
nextClicked(e) {
this.next_fs = $(e.currentTarget)
.parent()
.next(); // this is the next fieldset
// some actions...
}

jquery not changing src of element

I have a select element in my HTML, i then have an iframe that displays PDFs. i have some jquery code that should change the "src" attribute of the iframe when a user selects an option but so far i cant seem to get it to trigger. when i click an option from the select nothing happens. i have tried using .change() and .on("change") but they do not work. i have console.log within the function but it does not log anything into the console.
The jquery
$(document).ready(function(){
var x = $("#demo-category").val();
$("#demo-category").on("change", "#demo-category", function(){
$("#readframe").attr("src", x);
console.log(x);
console.log("test");
});
});
should you need any more information i will provide it if i can.
Event delegation (that is, your
.on("change", "#demo-category", function(){
) is for when the element that triggers the event is different from the element that the listener is added to. When you want to add a plain listener to a single element, don't pass another selector - if you do that, the listener won't fire. Instead just call .on('change', fn....
Also, you're retrieving x on document load. Retrieve the new value after #demo-category changes instead:
$(document).ready(function() {
$("#demo-category").on("change", function() {
var x = $(this).val();
$("#readframe").attr("src", x);
console.log(x);
console.log("test");
});
});
I think this will work
$(document).ready(function(){
$("#demo-category").on("change", function(){
$("#readframe").attr("src", $(this).val());
});
});

jQuery force dynamic event to bind first

I'm binding events on the document element to make them dynamic.
The problem is that these events execute AFTER events binded directly on the elements.
I have code that binds an element to execute first, but it doesn't work with dynamic content. Here is the code I would use for non dynamic content :
bindFirst: function (name, fn) {
var elem, handlers, i, _len;
this.bind(name, fn);
for (i = 0, _len = this.length; i < _len; i++) {
elem = this[i];
handlers = jQuery._data(elem).events[name.split('.')[0]];
handlers.unshift(handlers.pop());
}
}
This function is under .fn.extend.
As I said earlier, I want to be able to do the same, for for dynamic content bound on the document variable. Eg...
$(document).on("click", "div", function(){});
I want this to execute AFTER the code directly above :
$("div").on("click", function(){});
Like #epascarello wrote in the comment:
this is not possible, you need to figure out something different.
A workaround must be thought around the logic of your code. In any case I propose you a "let me say" bad code just to create the evidence of what should happen in order to revert event bubling.
Use the .trigger() method in order to add parameters and use event.stopPropagation() in order to avoid an infinite loop.
Test in the delegated event if the current element has the click event handler and so trigger again the event.
$('#btn').on('click', function(e) {
$(document.body).append($('<div/>', {text: 'CLICK ME: NEW DIV'}));
});
$("div").on("click", function(e, fromInner){
// revert event bubling....
if (fromInner == undefined) {
return;
}
e.stopPropagation();
//normal code.........
console.log('Normal click event');
});
$(document).on("click", "div", function(e) {
// revert event bubling....
if ($._data(this).events != undefined && $._data(this).events[e.type] != undefined) {
$(this).trigger('click', ['fromInner']);
}
console.log('Delegated Click');
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button type="button" id="btn">Add new DIV</button>
<div>CLICK ME</div>
You can't do this with jQuery event delegation, it just uses event bubbling, which works from the target element out to the containers. But the plain Javascript addEventListener() method also supports event capture, which goes the other direction. The optional third argument can be used to enable capture mode for an event listener. See Event Bubbling and Capturing.
So I think you should be able to write:
document.addEventListener("click", function() {...}, true);

Two Html select drop down apply class for span element using Javascript

I am working on HTML select Dropdown. I have two dropdowns one is for font size adjust and other is for text alignment.
When I select the fontsize from the dropdown it has to apply along with text-capitalize (bootstrap css) and If I select the font alignment all three should apply for the span element. For Example.
<div>
<span id="Title"class="text-capitalize">check</span>
</div>
Right now the code was like this
function changeFont_size () {
var select = document.getElementById('font_size');
// Bind onchange event
select.onchange = function() {
document.querySelector("#Title").className = this.value += " text-
capitalize";
};
}
function changeAlignment () {
var select = document.getElementById('text_align');
// Bind onchange event
select.onchange = function() {
document.querySelector("#Title").className = this.value;
};
}
Actually I am newbe on Javascript. Some how I am not getting.
The output result would be the combination of :
<span class="h1 left text-capitalize">Text</span>
Everything should be in pure javascript.
Thanks in advance. Kindly help me.
Here is the Link
This jsfiddle makes your code work. You need to run the code when the document is loaded, so that your onchange functions are being hooked in time.
It does not work exactly like you intended though. Your alignment classes need to be on the parent element and when you select your alignment, you disregard the previously set h1 or h2 class.
window.onload = function() {
var font_size = document.querySelector('#font_size');
// Bind onchange event
font_size.onchange = function() {
document.querySelector("#Title").className = this.options[this.selectedIndex].value += " text-capitalize";
};
var text_align = document.querySelector('#text_align');
// Bind onchange event
text_align.onchange = function() {
document.querySelector("#Title").className = this.options[this.selectedIndex].value;
};
};
You are mixing things up. There are two ways to bind events (well, two ways which are still common even with recent browsers).
The first one is to put a function call in the onsomething property of an element in the html code. Whatever is put there will be executed when the event happens.
<button onclick="alert('hi');">Click me</button>
You should pass the event object to an event handler instead of writing inline code.
<button id="helloworld" onclick="helloworld_onclick(event)">Run</button>
...
function helloworld_onclick(e) {
alert("Hello world!");
}
If you want to be able to bind events dynamically, if you want to bind multiple events to an object and if you want to keep the JavaScript outside of your HTML, the modern way to to so is with addEventListener.
document.querySelector("#helloworld").addEventListener("click", function(e) {
alert("Hello world!");
});
The event object passed (called e in my functions) contains information about what triggered the event and can be used to prevent default behavior and to control event propagation. You can't use "this" in event handlers, but the element which called the handler will be stored in e.target.
In your code, you created functions which, when called, bind events to the elements. Then you bound those functions to the elements with the html attributes.
Finally, you seem to be stuck between querySelector and getElementById. Note that querySelector(All) returns a static node/nodelist while getElement(s)By(...) returns a live node/nodelist. A static node is a copy of all the information about the element. A live node is a reference to the real element. If you modify the element, it modifies the live node, but the static node will keep the old information. You should use getElementById over querySelector for that, and because it runs faster. For code simplicity however, you might prefer always using querySelector. Just don't mix using querySelector("#something") on a line and getElementById("something") on another one, it's the best way to get confused and end up wasting time on a bug because you wrote querySelector("something") or getElementById("#something") instead.
function changeFont_size (element) {
if(element.options[element.selectedIndex].value != 'select'){
document.getElementById('Title').className = element.options[element.selectedIndex].value;
} else{
document.getElementById('Title').className = '' }
}
function changeAlignment (element) {
if(element.options[element.selectedIndex].value != 'select'){
document.getElementById('container').className = element.options[element.selectedIndex].value;
} else{
document.getElementById('container').className = '' }
}
Try this, Hope it will work

How to clone an element and not fire events in Chrome?

I am attempting to clone an input element of type="file". In this input element there is an onchange event. The clone method is called in the function that is called from the onchange event.
The problem I am having is that when I clone the file upload input, the onchange event is fired again. This only happens in Chrome, but works as intended in IE.
<input type="file" id="fileUpLoad" onchange="doFunction();" />
doFunction = function() {
var oldEl = $('#fileUpLoad');
var newEl = $(oldEl).clone();
$(oldEl).attr('id','fileUpLoadOLD');
$(oldEl).before(newEl);
}
I have created a fiddle duplicating this issue. Here is the fiddle.
How can I clone this file upload input without firing the onchange event again and again? I am using jQuery 1.7.1. This is actually a simplified a snippet from ajaxfileuploader.js:
var oldElement = jQuery('#' + fileElementId);
var newElement = jQuery(oldElement).clone();
jQuery(oldElement).attr('id', fileId);
jQuery(oldElement).before(newElement);
jQuery(oldElement).appendTo(form);
UPDATE: fiddle I think this is accomplishing what I need based on #MichaelAngstadt answer. Still testing though.
This is what seems to be working for me in the ajaxfileuploader.js extension:
var oldElement = jQuery('#' + fileElementId);
var oldElEvents = oldElement.data("events");
var newElement = jQuery(oldElement).attr('id', fileId).data("events", null).clone();
jQuery(oldElement).attr('id', fileElementId).before(newElement);
jQuery(oldElement).data("events", oldElEvents);
jQuery(newElement).appendTo(form);
You could always hold the events in a temporary object and re-attach them after cloning like:
doFunction = function(){
var oldEl = $('#fileUpLoad');
var oldElEvents = oldEl.data("events");
var newEl = $(oldEl).data("events", null).clone();
$(oldEl).attr('id','fileUpLoadOLD');
$(oldEl).before(newEl.data("events",oldElEvents));
}
This way oldEl doesn't actually have events defined to be cloned. Otherwise you'll be battling some fundamental functionality with regards to how cloning & the DOM work.
Have you tried cloning the object using $.extend instead.
var newEl = $.extend({},oldEl);
It seems the problem is related to onchange attribute. You can remove/reset the attribute before cloning. After cloning, the change event is triggered again and it results in an infinite loop.
var newEl = oldEl.removeAttr('onchange').clone();
You are loading jQuery, why not using it's methods? If you are using onchange attribute for keeping the event handler, you can use event delegation technique instead.
$(document).on('change', '.fileUpLoads', function() {
$(this).clone().insertBefore(this);
});
You don't need anything fancy here. If you attach the onchange event with jQuery/javascript instead of in the HTML, then clone( ) will only create one copy, as desired.
HTML:
<input type="file" id="fileUpLoad" />
JS:
$(document).ready( function() {
$('#fileUpLoad').change( function() {
doFunction();
});
});
doFunction = function() {
var oldEl = $('#fileUpLoad');
var newEl = $(oldEl).clone( );
$(oldEl).attr('id','fileUpLoadOLD');
$(oldEl).before(newEl);
}
P.S fileUpLoad, really? That sneaky capital L in there caused me some problems.
Building on the answer from #undefined (which works) I'd suggest actually making the change event a delegated event on a container object. Otherwise you end up with one input (the old one) which clones itself on change and another (the new one) which doesn't.
HTML:
<div class="container">
<input type="file" class="foo" id="fileUpLoad" />
</div>
Javascript:
$(function () {
$('.container').on('change', '.foo', function () {
var oldEl = $('#fileUpLoad');
var newEl = $(oldEl).clone().val('');
$(oldEl).attr('id', 'fileUpLoadOLD');
$(oldEl).before(newEl);
});
});
Working fiddle (I have also reset the value of the new input to null)
Note: This is still crashing Firefox for me. Not sutre why but might be my FF - the change event hasn't fired (in the other browsers) at the point FF crashes.
Explanation
I think what is happening here is that jQuery does not (by default) clone events when you clone an element. It does, however, clone attributes. So the onchange attribute on the element gets cloned and creates a change event on the cloned element, which for some reason is then called triggering an infinte loop. Not sure why .clone() triggers change events
Events attached via .on() on the object are not cloned - so no extra elements but no event on them either. By making the event a delegated event on a container we avoid the problem (since when the change event is triggered during clone the new element is not part of the page yet and so does not trigger the delegated event) but still have the functionality on the new object (once we insert it into the page).
You need better handling of the IDs if you want to be able to get more than two such inputs.

Categories

Resources