Condition not working inside eventListener - javascript

I need to make a simple events listener, which will change the 1st value element of the input.value each time, when the button will be clicked. To solve this problem, I wrote a simple condition inside the function menuide for onclick listener. But for some reason it's only works once when listening to an event, although every time an event triggers, it should work and fulfil one of the conditions.
Can anyone explain to me why my function change input.value[0] only once of all clicks?
function menuide() {
menu.classList.toggle('ul-wide');
var arr = 'b';
var value = Array.prototype.slice.call(inp.value);
var newValue = value.splice(1);
if (inp.value[0] != 'b') {
inp.value = arr + newValue.join('');
}
if (inp.value[0] == 'b') {
inp.value[0] == 'a' + newValue.join('');;
}
}
inp.addEventListener('click', menuide);
ul {
display: none;
}
.ul-wide {
display: grid;
}
<input type="button" id="inp" value="a click on me to make a wonder! :)"></input>
<ul id="menu">
<li>Smile</li>
<li>Happy</li>
<li>Dog</li>
</ul>

There is few errors in your code:
1. Instead of inp.value[0] == 'a' + newValue.join('');;
you probably want to write inp.value = 'a' + newValue.join('');
2. Also before second if you need to add else
function menuide() {
menu.classList.toggle('ul-wide');
var arr = 'b';
var value = Array.prototype.slice.call(inp.value);
var newValue = value.splice(1);
if (inp.value[0] !== 'b') {
inp.value = arr + newValue.join('');
} else if (inp.value[0] === 'b') {
inp.value = 'a' + newValue.join('');
}
}

Related

Triggering change events from within a change event

EDIT: here is a much simpler JSFiddle version of the code that illustrates the problem more succinctly:
https://jsfiddle.net/Lfo463d9/2/
I have a bunch of form elements that when updated change the options of the element next in the list. I have that working fine. However, now I am trying to get it so that if the root element is changed then it checks the next element to see if it is part of the new list and if not then makes it blank and then triggers the change event of the next one (so that it will in turn make the next element blank and so on). The change event doesn't seem to be firing.
I am not getting any errors in the console.
Is this because I am trying to fire a change event from within a change event? Is there some sort of blocking going?
(or am I just doing something stupid - I only started javascript a week or so ago)
I've tried calling the change() function on the element in javascript too.
function addChainOptions(anelementID, nextelementID, listToChangeID, firstToSecond, secondFromFirst)
{ var anelement = document.getElementById(anelementID);
anelement.addEventListener("change", function() {
var nextelement = document.getElementById(nextelementID);
var listToChange = document.getElementById(listToChangeID);
console.log(this.id + "has changed");
if(this.value.length == 0)
{
nextelement.value = "";
$("#" + nextelementID).change();
}
nextelement.disabled = true;
google.script.run.withSuccessHandler(function(value) {
htmlOptions = value.map(function(r){return '<option value = "' + r[0] + '">';}).join(" ")
listToChange.innerHTML = htmlOptions;
if(value.length == 1) {
nextelement.value = value[0];
nextelement.change();
}
if(value.includes(nextelement.value) == false && nextelement.value.length > 0)
{
nextelement.value = "";
console.log(nextelement.id + "set to blank - triggering change")
$("#" + nextelementID).change();
}
nextelement.removeAttribute("disabled");
}).subListLookUp(firstToSecond, secondFromFirst, this.value);
});
};
addChainOptions("productTypesInput01", "productsInput01", "productsList01", "ProductTypeMulti", "Products");
addChainOptions("brandsInput01", "productTypesInput01", "productTypesList01", "BrandToProductType", "ProductTypeFromBrand");
addChainOptions("category", "brandsInput01", "brandsList01", "CategoryToBrand", "BrandFromCategory");
At the moment it is setting the next one to blank and trying to trigger the change but nothing happens.
You should try listening to "input" event instead of "change".
const firstinput = document.getElementById("input1");
const secondinput = document.getElementById("input2");
const thirdinput = document.getElementById("input3");
function dispatchEvent(target, eventType) {
var event = new Event( eventType, {
bubbles: true,
cancelable: true,
});
target.dispatchEvent(event);
}
firstinput.addEventListener("input", function() {
secondinput.value = 2;
dispatchEvent(secondinput,"input");
});
secondinput.addEventListener("input", function() {
thirdinput.value = 3;
//dispatchEvent(thirdinput,"input");
});
<input id="input1">
<input id="input2">
<input id="input3">

How do I make "Enter" keypress in an <input> Element shift focus to the next <input> element on the page. (JavaScript)

How do I make make an Enter keypress in an <input> element shift focus to the next <input> element on the page?
I have a for loop that creates <li> elements with <input> elements inside. I need to make so that when the user hits enter on their keyboard, the website will focus on the next input field so that the user can enter the next player name without having to toggle between using their mouse and their keyboard.
I thought using the nextSibling property was the solution but it wont work because the <input> elements technically dont have any siblings because each of them is inside/are children of diferent <li> elements.
Here is my JavaScript:
for ( var i = 1 ; i <= numberOfPlayers ; i++ ){
var inputElement = document.createElement('input');
var liElement = document.createElement('li');
inputElement.setAttribute( 'type' , 'text' );
inputElement.setAttribute ( 'id' , 'name-input-' + i );
inputElement.setAttribute ( 'class' , 'name-input');
inputElement.setAttribute ( 'placeholder' , 'Enter a name for player ' + i );
liElement.appendChild(inputElement);
nameInputArray[i] = inputElement;
document.getElementById('name-list').appendChild(liElement);
inputElement.addEventListener( 'keypress' , function(event){
if ( event.which === 13 ) {
alert(this);
document.getElementById( 'name-input-' + (i+1)).focus();
}
} );
}
I tried using the "i" in the for loop and string concatenation to select the ID of the next element but the "i" variable isn't working either because by the time that code runs that "i" is equal to the highest number that it can be after the whole for loop has ran.
Problem:
The problem with your actual code is that i is always equal to numberOfPlayers+1 in the event handler callback function, so you were trying to focus on a null element, you can read more about JavaScript closures to see why i was always equal to numberOfPlayers+1.
Solution:
First you need to use the onkeypress event on your input, then test if the pressed key is the Enter, if it's pressed get the id of the current input, extract i value from it and focus on the next input element using the next id.
This is how should be your code:
inputElement.addEventListener('keypress', function(event) {
if (event.which === 13) {
var i = parseInt(this.id.charAt(this.id.length-1));
console.log(i);
if(i<=numberOfPlayers){
document.getElementById('name-input-' + (i + 1)).focus();
}
}
});
This is a working snippet:
var numberOfPlayers = 5;
var nameInputArray = [];
for (var i = 1; i <= numberOfPlayers; i++) {
var inputElement = document.createElement('input');
var liElement = document.createElement('li');
inputElement.setAttribute('type', 'text');
inputElement.setAttribute('id', 'name-input-' + i);
inputElement.setAttribute('class', 'name-input');
inputElement.setAttribute('placeholder', 'Enter a name for player ' + i);
liElement.appendChild(inputElement);
nameInputArray[i] = inputElement;
document.getElementById('name-list').appendChild(liElement);
inputElement.addEventListener('keypress', function(event) {
if (event.which === 13) {
var i = parseInt(this.id.charAt(this.id.length - 1));
console.log(i);
if(i<numberOfPlayers){
document.getElementById('name-input-' + (i + 1)).focus();
}
}
});
}
<ul id="name-list"></ul>
If you want to stick with vanilla JS, use this:
for (var i = 1; i <= numberOfPlayers; i++) {
var inputElement = document.createElement("input");
var liElement = document.createElement("li");
inputElement.type = "text";
inputElement.id = "name-input-" + i;
inputElement.className = "name-input";
inputElement.placeholder = "Enter a name for player " + i;
liElement.appendChild(inputElement);
nameInputArray[i] = inputElement;
document.getElementById("name-list").appendChild(liElement);
(function(i) {
inputElement.addEventListener("keypress", function(event) {
if (event.which === 13) {
alert(this);
document.getElementById("name-input-" + (i + 1)).focus();
}
});
})(i);
}
This is my solution.
Do not forget that the created <li> element needs to be appended to something like <body>. I have actually added a <ul> element and appended it to the <body> and then appended the <li> elements to the <ul> element.
If you use nextSibling, you do not need to keep elements in nameInputArray. I have not removed it to show how it should be initialized before you can use it in your loop. Also, nextSibling works in my solution since I have put all the <li>s under one <ul> which I think is the correct thing to do anyway.
Other than that, I just corrected a few things here and there. Let me know if you have more questions about this code.
function eventFunc(event) {
if (event.which === 13) {
var nextInput = event.target.parentElement.nextSibling.childNodes[0];
if (nextInput !== null)
nextInput.focus();
}
}
var numberOfPlayers = 4;
var nameInputArray = [];
var ulElement = document.createElement('ul');
document.body.append(ulElement);
for (var i = 0; i < numberOfPlayers; i++) {
var liElement = document.createElement('li');
ulElement.append(liElement);
var inputElement = document.createElement('input');
inputElement.setAttribute('type', 'text');
inputElement.setAttribute('id', 'name-input-' + i);
inputElement.setAttribute('class', 'name-input');
inputElement.setAttribute('placeholder', 'Enter a name for player ' + i);
inputElement.setAttribute('onkeypress', "eventFunc(event)");
liElement.appendChild(inputElement);
nameInputArray[i] = inputElement;
}
UPDATE: Getting each input box from parent <li> elements:
After comment from the OP, I see that they want a structure like this:
<ul>
<li>input box1</li>
<li>input box2</li>
<li>input box3</li>
</ul>
In this structure, each input box is the first child node of its parent <li> element. Therefore, we can still use nextSibling (as the OP intended to use) in this way:
nextInput = event.target.parentElement.nextSibling.childNodes[0];
This line first finds the parent <li> element, applies nextSibling to get the next li element and then gets the input box inside that element.
$('input').on('keyup', function(event){
if(event.keyCode == 13){ // 13 is the keycode for enter button
$(this).next('input').focus();
}
});
https://jsfiddle.net/jat1merL/
are you looking for this?
by the way, use keyup instead of keypress. if a key is hold it fires mass of keypress events in a speed you can't handle ;)

javascript how to return a value from event function to outer function

Can someone please help me with this. I what to return var from input event function to outer function.
function takeInputText() {
var input = document.getElementById('inputText')
var newText;
input.onkeyup = function(e) {
var text = input.value;
if ( e.which == 13 ) {
newText = text;
input.value = '';
//return newText - I want to return 'newText' to 'takeInputText()' so i can
// use 'takeInputText()' as a variable
}
}
}
takeInputText();
If you are willing to play with the value of the input once user hit enter key, bind keyup event over input and manipulate the value in the callback function.
You can also call another function in which value of the input could be passed.
Example:
var input = document.getElementById('inputText');
input.onkeyup = function(e) {
var code = e.which || e.keyCode;
if (code == 13) {
appendInput(this.value);
this.value = '';
}
}
function appendInput(value) {
var elem = document.createElement('h2');
elem.textContent = value;
document.getElementById('preview').appendChild(elem);
}
<input type="text" id="inputText">
<div id="preview"></div>
You cannot use takeInputText() as a variable since what you are doing inside takeInputText is just attaching a keyup listener to the input element and the function returns immediately (undefined is returned in this case).
To make use of the value, pass the variable as an argument to a function that you want to invoke when the condition inside the handler is true, for example:
input.onkeyup = function(e) {
var text = input.value;
if ( e.which == 13 ) {
input.value = '';
yourFunction(text);
}
}

Compare onclick action of two html button using javascript

I have this two HTML Form buttons with an onclick action associated to each one.
<input type=button name=sel value="Select all" onclick="alert('Error!');">
<input type=button name=desel value="Deselect all" onclick="alert('Error!');">
Unfortunately this action changes from time to time. It can be
onclick="";>
or
onclick="alert('Error!');"
or
onclick="checkAll('stato_nave');"
I'm trying to write some javascript code that verifies what is the function invoked and change it if needed:
var button=document.getElementsByName('sel')[0];
// I don't want to change it when it is empty or calls the 'checkAll' function
if( button.getAttribute("onclick") != "checkAll('stato_nave');" &&
button.getAttribute("onclick") != ""){
//modify button
document.getElementsByName('sel')[0].setAttribute("onclick","set(1)");
document.getElementsByName('desel')[0].setAttribute("onclick","set(0)");
} //set(1) and set(0) being two irrelevant function
Unfortunately none of this work.
Going back some steps I noticed that
alert( document.getElementsByName('sel')[0].onclick);
does not output the onclick content, as I expected, but outputs:
function onclick(event) {
alert("Error!");
}
So i guess that the comparisons fails for this reason, I cannot compare a function with a string.
Does anyone has a guess on how to distinguish which function is associated to the onclick attribute?
This works
http://jsfiddle.net/mplungjan/HzvEh/
var button=document.getElementsByName('desel')[0];
// I don't want to change it when it is empty or calls the 'checkAll' function
var click = button.getAttribute("onclick");
if (click.indexOf('error') ) {
document.getElementsByName('sel')[0].onclick=function() {setIt(1)};
document.getElementsByName('desel')[0].onclick=function() {setIt(0)};
}
function setIt(num) { alert(num)}
But why not move the onclick to a script
window.onload=function() {
var button1 = document.getElementsByName('sel')[0];
var button2 = document.getElementsByName('desel')[0];
if (somereason && someotherreason) {
button1.onclick=function() {
sel(1);
}
button2.onclick=function() {
sel(0);
}
}
else if (somereason) {
button1.onclick=function() {
alert("Error");
}
}
else if (someotherreason) {
button1.onclick=function() {
checkAll('stato_nave')
}
}
}
Try casting the onclick attribute to a string. Then you can at least check the index of checkAll and whether it is empty. After that you can bind those input elements to the new onclick functions easily.
var sel = document.getElementsByName('sel')[0];
var desel = document.getElementsByName('desel')[0];
var onclick = sel.getAttribute("onclick").toString();
if (onclick.indexOf("checkAll") == -1 && onclick != "") {
sel.onclick = function() { set(1) };
desel.onclick = function() { set(0) };
}
function set(number)
{
alert("worked! : " + number);
}
working example: http://jsfiddle.net/fAJ6v/1/
working example when there is a checkAll method: http://jsfiddle.net/fAJ6v/3/

How do I call a sub-function from within a function object in javascript

I've checked the related questions on stack overflow, but can't seem to find an answer to my predicament. I'm trying to use a plugin for javascript (Tag it! - Tag Editor) and I need to find a way to call one of its functions "create_choice()" EDIT: at some point after it has been initiated. Is there a way after calling :
$tagit = $("#mytags").tagit();
that I can then call something like
$tagit.create_choice('test123');
Here is a link for the example :
http://levycarneiro.com/projects/tag-it/example.html
Below is the code from the plugin if it is any help
(function($) {
$.fn.tagit = function(options) {
var el = this;
const BACKSPACE = 8;
const ENTER = 13;
const SPACE = 32;
const COMMA = 44;
// add the tagit CSS class.
el.addClass("tagit");
// create the input field.
var html_input_field = "<li class=\"tagit-new\"><input class=\"tagit-input\" type=\"text\" /></li>\n";
el.html (html_input_field);
tag_input = el.children(".tagit-new").children(".tagit-input");
$(this).click(function(e){
if (e.target.tagName == 'A') {
// Removes a tag when the little 'x' is clicked.
// Event is binded to the UL, otherwise a new tag (LI > A) wouldn't have this event attached to it.
$(e.target).parent().remove();
}
else {
// Sets the focus() to the input field, if the user clicks anywhere inside the UL.
// This is needed because the input field needs to be of a small size.
tag_input.focus();
}
});
tag_input.keypress(function(event){
if (event.which == BACKSPACE) {
if (tag_input.val() == "") {
// When backspace is pressed, the last tag is deleted.
$(el).children(".tagit-choice:last").remove();
}
}
// Comma/Space/Enter are all valid delimiters for new tags.
else if (event.which == COMMA || event.which == SPACE || event.which == ENTER) {
event.preventDefault();
var typed = tag_input.val();
typed = typed.replace(/,+$/,"");
typed = typed.trim();
if (typed != "") {
if (is_new (typed)) {
create_choice (typed);
}
// Cleaning the input.
tag_input.val("");
}
}
});
tag_input.autocomplete({
source: options.availableTags,
select: function(event,ui){
if (is_new (ui.item.value)) {
create_choice (ui.item.value);
}
// Cleaning the input.
tag_input.val("");
// Preventing the tag input to be update with the chosen value.
return false;
}
});
function is_new (value){
var is_new = true;
this.tag_input.parents("ul").children(".tagit-choice").each(function(i){
n = $(this).children("input").val();
if (value == n) {
is_new = false;
}
})
return is_new;
}
function create_choice (value){
var el = "";
el = "<li class=\"tagit-choice\">\n";
el += value + "\n";
el += "<a class=\"close\">x</a>\n";
el += "<input type=\"hidden\" style=\"display:none;\" value=\""+value+"\" name=\"item[tags][]\">\n";
el += "</li>\n";
var li_search_tags = this.tag_input.parent();
$(el).insertBefore (li_search_tags);
this.tag_input.val("");
}
};
String.prototype.trim = function() {
return this.replace(/^\s+|\s+$/g,"");
};
})(jQuery);
I've created a working example at http://jsfiddle.net/nickywaites/DnkBt/ but it does require making changes to the plugin.
Change
$.fn.tagit = function(options) { ...
to
$.fn.tagit = function(options,callback) { ...
Add
if (callback && typeof callback == 'function') {
callback();
}
after
String.prototype.trim = function() {
return this.replace(/^\s+|\s+$/g,"");
};
Now you can call a function of your choice right after the tagit call:
$tagit = $("#mytags").tagit(yourOptions, function(){
alert('hi')!
});
You can try to add
return this;
right after the function create_choice block. tagit will return itself and you can call make_choice or any function contained in .fn.tagit

Categories

Resources