callback function with universal argument handling - javascript

I would like to make a JS function which handles its arguments independedently from where it is called.
AFAIK the arguments differ, depending where the function is called.
Example 1
A commom usage is to register the function in HTML:
<input type="text" id="text1" onkeyup="myFunc(this);">
The element will then be passed on to the function:
function myfunc(element) {
alert(element.value);
}
Example 2
Another, appoach is to register it dynamically, when the document is finished loading. Something along those lines:
// init() gets called when document is ready
function init() {
document.getElementById('text2').addEventListener('keyup', myFunc2);
}
Now the function will receive an Event-Object instead of an Element-Object.
I need to change the functions code to access the information.
function myFunc2(event) {
var element = event.target;
alert(element.value);
}
Example 3
One way to solve this problem would be to completely ingnore arguments and always gather all information inside the function, like this:
function myFunc3(event) {
var element = document.getElementById('text3');
alert(element.value);
}
The ugly thing about this solution is, that the GUI will be thigtly coupled to the logic.
Example 4?
One solution I can think of would be to change Solution 1 and pack the this into an Event-Object? I have not tried this yet and I'm not sure how to do this most elegantly.
Ps: No JQuery "allowed"

The first one can be rewritten like this (note that it's preferred not to mix your markup with event handlers, however if you really want it to, then it can be written like this)
<input type="text" id="text1" onkeyup="myFunc(event);">
and the second one will take the input from the events target property.
function myFunc(e) {
let element = e.target;
console.log( 'event comming from ' + element.id );
console.log( 'current value is ' + element.value );
}
window.addEventListener('load', function() {
let el = document.querySelector('#text2');
el.addEventListener('keyup', myFunc);
});
<input type="text" id="text1" onkeyup="myFunc(event);">
<input type="text" id="text2">

This covers both cases:
function foo(e) {
let element = e.target || e;
}

You could have your function check the instance/type of the argument(s) and delegate the logic to other functions.
function myGeneralFunction(arg) {
if(arg instanceof Event) {
return handerForEvents(arg);
}
return otherHandler(arg);
}

Related

HTML multiple events to trigger the same function

Is there a way to have multiple events (e.g. oninput, onblur) trigger exactly the same function in the HTML?
This is the HTML that I'm trying to simplify:
<input id="Email" name="Email" type="text" oninput="toggleSuccessIcon(this, isEmail)" onblur="toggleSuccessIcon(this, isEmail)">
I know this is possible in jQuery as explained here, but since I have a lot of different inputs (e.g. address, postcode, etc.) that need to call different functions (e.g. toggleSuccessIcon(this, isAddresss), toggleSuccessIcon(this, isPostCode), etc.) I wanted to avoid having a long and messy initialisation in the JavaScript. However, if I am being foolish by doing this in HTML rather than JQuery I'd appreciate an explanation as to the advantage of using JQuery.
Note that isEmail, isAddress, isPostCode, etc. is a function name.
You could use a helper function
// events and args should be of type Array
function addMultipleListeners(element,events,handler,useCapture,args){
if (!(events instanceof Array)){
throw 'addMultipleListeners: '+
'please supply an array of eventstrings '+
'(like ["onblur","oninput"])';
}
//create a wrapper for to be able to use additional arguments
var handlerFn = function(e){
handler.apply(this, args && args instanceof Array ? args : []);
}
for (var i=0;i<events.length;i+=1){
element.addEventListener(events[i],handlerFn,useCapture);
}
}
function handler(e) {
// do things
};
// usage
addMultipleListeners(document.getElementById('Email'),
['oninput','onblur'],handler,false);
You can use data as:
<input class="configurable-events" type="text" data-events="blur focus click" data-function="myFunction" />
<input class="configurable-events" type="password" data-events="blur focus" data-function="myPasswordFunction" />
in jQuery you can use something like:
$('.configurable-events').each(function(){
$(this).on($(this).data('events'), function(){
$(this).data('function')($(this));
});
});
function myFunction(myInput) {
console.log(myInput.value());
}
function myPasswordFunction(myPasswordInput) {
console.log(myPasswordInput.size());
}
$("input").on( "click blur", toggleSuccessIcon(this, isEmail));

How to count string length, if length equals X, then execute code? - JavaScript

Using JavaScript, I want to call an anonymous function that checks the length of a string for every onkeyup event. When the string length equals 9, a conditional statement will execute a block of code. What am I doing wrong?
<input type="text" id="length_test" placeholder="Enter text here..." />
var length_test = document.getElementById('length_test');
var string_value = document.getElementById('length_test').value;
var x = 9;
length_test.onkeyup = function () {
if (string_value.length == x) {
// execute code here...
}
}
Give the following a try.
Note: The example below uses JQuery. If you didn't wait to use JQuery that is fine.
You could natively do it with the following.
document.getElementById("length_test").addEventListener("keyup", myFunction);
You would need to then create a function called myFunction that has your if statement in it.
$(document).ready(function() {
$("#length_test").on("keyup", function(event) {
if (event.currentTarget.value.length == 9) {
//do your logic here
alert("length is 9");
}
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text" id="length_test" placeholder="Enter text here..." />
document.getElementById returns a live node. This means that any changes happening to the actual element in the page will be reflected on the object. When you write something else in the field, the value property of the element gets updated. However, the value stored in string_value doesn't get updated, since it's just a good old string, not some kind of live object.
Another way to see it is that
var string_value = document.getElementById('length_test').value;
makes a copy of the element's .value and stores it in string_value (even though that's not exactly how it works). When you type in the input, it updates the .value but not the string_value variable.
But what you should do is:
document.getElementById('length_test').addEventListener("keyup", function(e) {
if(e.target.value.length === 9) {
alert("length is 9");
}
});
This is much better because document.getElementById is only executed once, when binding the event. Event listener functions can revieve the event through their first argument (commonly named e). e.target is the element which called the event, in this case the input element.
You could try:
<input type="text" id="length_test" placeholder="Enter text here..." onkeyup="keyupFunction()">
<script type = "text/javascript">
keyupFunction function () {
if(document.getElementById('length_test').value == 9) {
// execute code here...
}
}
</script>
Alternatively, you could use javascript to add an event listener to the input element:
<input type="text" id="length_test" placeholder="Enter text here...">
<script type = "text/javascript">
document.getElementById('length_test').addEventListener("keyup", function(evt) {
if(document.getElementById('length_test').value == 9) {
// execute code here...
}
});
</script>

Why my jQuery extension's function act "static"?

I made a custom jQuery extension to handle files for upload.
My stripped version: http://jsfiddle.net/6huV6/
My full version: http://jsfiddle.net/LQrJm/
My problem is that buildBondye is called 2 times, but my extension is added 2 x 2 droppers and buttons..
How do I fix this?
You get four because for each element in your set of matched elements you're calling the buildBondye function, which in turn calls the addButton and addDropper functions. Those functions use $this, which is the entire set of matched elements (so both of them), not only the element for that iteration of .each().
You can fix this by passing a reference to a single element to those two functions, and using that instead:
var buildBondye = function () {
// inside buildBondye this refers to the specific element for the iteration of .each()
// different to the this inside the $.fn.bondye function
addButton(this);
addDropper(this);
}
var addDropper = function (element) {
$dropper = $('<input type="text" readonly />');
$dropper.val('drop here');
$(element).after($dropper);
}
var addButton = function (element) {
$button = $('<input type="button" />');
$button.val('browse');
$button.bind('click', function () {
$(element).trigger('click');
});
$(element).after($button);
}
Take a look at this updated jsFiddle.

How to call two methods on button's onclick method in HTML or JavaScript?

How to call two methods on button's onclick method in HTML or JavaScript ?
Try this:
<input type="button" onclick="function1();function2();" value="Call2Functions" />
Or, call second function at the end of first function:
function func1(){
//--- some logic
func2();
}
function func2(){
//--- some logic
}
...and call func1() onclick of button:
<input type="button" onclick="func1();" value="Call2Functions" />
As stated by Harry Joy, you can do it on the onclick attr like so:
<input type="button" onclick="func1();func2();" value="Call2Functions" />
Or, in your JS like so:
document.getElementById( 'Call2Functions' ).onclick = function()
{
func1();
func2();
};
Or, if you are assigning an onclick programmatically, and aren't sure if a previous onclick existed (and don't want to overwrite it):
var Call2FunctionsEle = document.getElementById( 'Call2Functions' ),
func1 = Call2FunctionsEle.onclick;
Call2FunctionsEle.onclick = function()
{
if( typeof func1 === 'function' )
{
func1();
}
func2();
};
If you need the functions run in scope of the element which was clicked, a simple use of apply could be made:
document.getElementById( 'Call2Functions' ).onclick = function()
{
func1.apply( this, arguments );
func2.apply( this, arguments );
};
The modern event handling method:
element.addEventListener('click', startDragDrop, false);
element.addEventListener('click', spyOnUser, false);
The first argument is the event, the second is the function and the third specifies whether to allow event bubbling.
From QuirksMode:
W3C’s DOM Level 2 Event specification pays careful attention to the problems of the traditional model. It offers a simple way to register as many event handlers as you like for the same event on one element.
The key to the W3C event registration model is the method addEventListener(). You give it three arguments: the event type, the function to be executed and a boolean (true or false) that I’ll explain later on. To register our well known doSomething() function to the onclick of an element you do:
Full details here: http://www.quirksmode.org/js/events_advanced.html
Using jQuery
if you're using jQuery, there is a nice API for event handling:
$('#myElement').bind('click', function() { doStuff(); });
$('#myElement').bind('click', function() { doMoreStuff(); });
$('#myElement').bind('click', doEvenMoreStuff);
Full details here: http://api.jquery.com/category/events/
<input type="button" onclick="functionA();functionB();" />
function functionA()
{
}
function functionB()
{
}
Hi,
You can also do as like below... In this way, your both functions should call and if both functions return true then it will return true else return false.
<input type="button"
onclick="var valFunc1 = func1(); var valFunc2 = func2(); if(valFunc1 == true && valFunc2 ==true) {return true;} else{return false;}"
value="Call2Functions" />
Thank you,
Vishal Patel

Passing in parameter from html element with jQuery

I'm working with jQuery for the first time and need some help. I have html that looks like the following:
<div id='comment-8' class='comment'>
<p>Blah blah</p>
<div class='tools'></div>
</div>
<div id='comment-9' class='comment'>
<p>Blah blah something else</p>
<div class='tools'></div>
</div>
I'm trying to use jQuery to add spans to the .tools divs that call variouis functions when clicked. The functions needs to receive the id (either the entire 'comment-8' or just the '8' part) of the parent comment so I can then show a form or other information about the comment.
What I have thus far is:
<script type='text/javascript'>
$(function() {
var actionSpan = $('<span>[Do Something]</span>');
actionSpan.bind('click', doSomething);
$('.tools').append(actionSpan);
});
function doSomething(commentId) { alert(commentId); }
</script>
I'm stuck on how to populate the commentId parameter for doSomething. Perhaps instead of the id, I should be passing in a reference to the span that was clicked. That would probably be fine as well, but I'm unsure of how to accomplish that.
Thanks,
Brian
Event callbacks are called with an event object as the first argument, you can't pass something else in that way. This event object has a target property that references the element it was called for, and the this variable is a reference to the element the event handler was attached to. So you could do the following:
function doSomething(event)
{
var id = $(event.target).parents(".tools").attr("id");
id = substring(id.indexOf("-")+1);
alert(id);
}
...or:
function doSomething(event)
{
var id = $(this).parents(".tools").attr("id");
id = substring(id.indexOf("-")+1);
alert(id);
}
To get from the span up to the surrounding divs, you can use <tt>parent()</tt> (if you know the exact relationship), like this: <tt>$(this).parent().attr('id')</tt>; or if the structure might be more deeply nested, you can use parents() to search up the DOM tree, like this: <tt>$(this).parents('div:eq(0)').attr('id')</tt>.
To keep my answer simple, I left off matching the class <tt>"comment"</tt> but of course you could do that if it helps narrow down the div you are searching for.
You don't have a lot of control over the arguments passed to a bound event handler.
Perhaps try something like this for your definition of doSomething():
function doSomething() {
var commentId = $(this).parent().attr('id');
alert(commentId);
}
It might be easier to loop through the comments, and add the tool thing to each. That way you can give them each their own function. I've got the function returning a function so that when it's called later, it has the correct comment ID available to it.
The other solutions (that navigate back up to find the ID of the parent) will likely be more memory efficient.
<script type='text/javascript'>
$(function() {
$('.comment').each(function(comment) {
$('.tools', comment).append(
$('<span>[Do Something]</span>')
.click(commentTool(comment.id));
);
});
});
function commentTool(commentId) {
return function() {
alert('Do cool stuff to ' + commentId);
}
}
</script>
Getting a little fancy to give you an idea of some of the things you can do:
var tool = $('<span>[Tool]</span>');
var action = function (id) {
return function () {
alert('id');
}
}
$('div.comment').each(function () {
var id = $(this).attr('id');
var child = tool.clone();
child.click(action(id));
$('.tools', this).append(child);
});
The function bind() takes, takes the element as a parameter (in your case the span), so to get the id you want from it you should do some DOM traversal like:
function doSomething(eventObject) {
var elComment = eventObject.parentNode.parentNode; //or something like that,
//didn't test it
var commentId= elComment.getAttribute('commentId')
alert(commentId);
}

Categories

Resources