HTML multiple events to trigger the same function - javascript

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));

Related

jquery if (value)... else avoiding "duplicate selector"

I have a notification on PhpStorm that "Duplicate JQuery Selector" for a JQuery if...else conditional based on a value and then updating that value.
$(document).ready(function() {
$('#forgotten').click(function () {
if($('#button').val() === 'Login') {
$('#button').val('Send New Password');
}
else {
$('#button').val('Login');
}
return false;
});
});
PhpStorm tells me
Duplicated jQuery selector
Inspection info: Checks that jQuery selectors are used in an efficient way. It warns about duplicated selectors which could be cached and optionally about attribute and pseudo-selectors usage
Does this really matter? (I suspect not, it's micro-optimisation)
Is there a better way of writing this code (I suspect so)?
What is this better way?
Attempts:
if($('#button').val() === 'Login') {
$(this).val('Send New Password');
}
else {
$(this).val('Login');
}
The above code using this doesn't work; It seems that the JQuery isn't aware of what this is because it's not an invocation.
Attempt two is to use This useful answer:
$('#something')[$(this).val()=='X'?'show':'hide']();
But I can't see the syntax of how to apply this to swapping the value.
$('#button')[$(this).val() === 'Login'?$(this).val('Send New Password'):$(this).val('Login')];
The above attempt does not make the change expected (and does not give any console notices).
So, how do I do it; how do I write the original IF statement without repeating the reference?
Creating a jquery has (some, minor) overhead, so is not the most efficient. Your first code could be written as:
var btn = $("#button");
if (btn.val() === 'Login') {
btn.val('Send New Password');
}
else {
btn.val('Login');
}
while, in this case, it's a micro-optimisation, if you were doing this 1000s of times with very complicated selectors, it can save a lot of time to only run the jquery selection once.
Regarding your other attempts, using this will only make sense if this has relevant context, eg if inside an event:
$("#button").click(function() {
var btn = $(this);
...
In the case of .val() (and many other jquery functions (but not all)) a callback can be provided which is called for each entry in the jquery collection.
https://api.jquery.com/val/#val-function
A function returning the value to set. this is the current element. Receives the index position of the element in the set and the old value as arguments.
In your case, this becomes:
$("#button").val(function(i, v) { return v === "Login" ? "Send new" : "login" });
This will run the callback function on each item in the collection provided by the selector, so very useful if you want to run against multiple items with different results on each, example:
$(".button").val(function(i, v) { return v === "Login" ? "Send new" : "login" });
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type="button" class="button" value="Login"></input>
<input type="button" class="button" value="Login"></input>
<input type="button" class="button" value="Not Login"></input>
Whenever you call $("#button") jQuery searches the document and gets the corresponding DOM element. So you can try to assign the selection to a variable as followings to avoid the repetition of the search:
var btn = $('#button');
if(btn.val() === 'Login') {
btn.val('Send New Password');
}
else {
btn.val('Login');
}

callback function with universal argument handling

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);
}

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>

Trying to dynamically validate fields with jQuery - custom function

I'm working on a validation function in jQuery and am getting a bit stuck. I've got a working version that is very lengthy and full of hardcoded form values which I'm trying to avoid. Here's what works, currently:
$(document).ready(function(){
var fname = $("#formFName");
var lname = $("#formLName");
fname.blur(validateFName);
lname.blur(validateLName);
function validateFName(){
if(fname.val().length > 0){
fname.removeClass("req_error");
return true;
}
else {
fname.addClass("req_error");
return false;
}
}
function validateLName(){
if(lname.val().length > 0){
lname.removeClass("req_error");
return true;
}
else {
lname.addClass("req_error");
return false;
}
}
});
That part works fine for those two fields but I'd like to encapsulate the whole thing in a function that's a bit easier to maintain. Something like this:
$(document).ready(function(){
$("#first_name").blur(validateField("first_name","text"));
$("#last_name").blur(validateField("last_name","text"));
$("#email_address").blur(validateField("email_address","email"));
function validateField(formfield, type){
var field = $("#" + formfield);
switch(type) {
case "text":
if(field.val().length > 0){
field.removeClass("req_error");
return true;
}
else {
field.addClass("req_error");
return false;
}
break;
case "email":
var filter = /^[a-zA-Z0-9]+[a-zA-Z0-9_.-]+[a-zA-Z0-9_-]+#[a-zA-Z0-9]+[a-zA-Z0-9.-]+[a-zA-Z0-9]+.[a-z]{2,4}$/;
if(filter.test(field.val())) {
field.removeClass("req_error");
return true;
else {
field.addClass("req_error");
return false;
}
break;
}
}
});
However, when I do that I get the following error in Firefox's JS error log:
Error: ((f.event.special[r.origType] || {}).handle || r.handler).apply is not a function
Source File: /scripts/jquery-1.7.1.min.js
Line: 3
A quick Google for that error hasn't yielded anything that means anything to me, unfortunately. I've tried alerts in various spots and doing so has verified that the proper form field names are indeed being passed where there supposed to be, but as I'm fairly new to jQuery (and not great at JavaScript) I'm at a bit of a loss here.
Thanks to anyone who can point me in the right direction. Also, if anyone thinks that I'm going about this in the wrong way, I'm more than happy to change. I tried using the jQuery validation plugin but I'm also using some dynamically created fields and unfortunately the plugin prevents the visitor from submitting the form when hidden required fields are involved.
Sounds like you could simplify this by attaching behavior instead of specific elements:
<input type="text" id="someId" class="validate-text" />
<input type="text" id="someOtherId" class="validate-email" />
$('.validate-text').live('blur', function()
{
$(this).removeClass('req_error');
if($.trim(this.value).length < 1)
$(this).addClass('req_error');
});
$('.validate-email').live('blur', function()
{
// Same thing with the email validation logic
});
This way, you dont need to attach specific event handlers to your elements and instead use those handlers to check the behavior you want. Then you simply mark HTML elements with specific classes to mark the validation mode you want.
Assuming I understood your question correctly.
You can't pass a function invocation expression to .blur(). You can pass an anonymous function constructor:
$("#first_name").blur(function () {validateField("first_name","text");});
Or pass the name of a function:
function validateFirstName() {
validateField("first_name","text");
}
* * *
$("#first_name").blur(validateFirstName));
#Tejs's suggestion to use classes to attach validators is a good one, as well.

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

Categories

Resources