Javascript - Pass param function to async onchange event - javascript

Good evening,
I have a problem with the construction of form in Javascript. For avoid the repetition of code I'd like to use the same function:
function addCheckBoxItem(p, name, value) {
// add checkbox
var newCheckbox = document.createElement("input");
newCheckbox.type = "checkbox";
newCheckbox.setAttribute("value", p);
newCheckbox.setAttribute("id", p);
newCheckbox.setAttribute("name", name);
newCheckbox.onchange = function(){
var cbs = document.getElementsByName(name);
for (var i = 0; i < cbs.length; i++) {
cbs[i].checked = false;
}
this.checked = true;
// define the peer selected as choice
value = this.value;
// TODO: MY PROBLEM IS HERE
};
form.appendChild(newCheckbox);
// add label to checkbox
var label = document.createElement('label');
label.setAttribute("name", name);
label.htmlFor = p;
label.appendChild(document.createTextNode(p));
form.appendChild(label);
// add br tag to checkbox
var br = document.createElement("br")
br.setAttribute("name", name);
form.appendChild(br);
}
I call my function inside loop
for (i = 0; i < array.length; i++) {
addCheckBoxItem(array[i].key, nameItemCheckbox, peer_choice);
}
I know that value = this.value isn't possible because onchange event is Async but i want retrieve the value of this event and associate it with my param. I have find different response to this problem. One of this is: Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference I have understand the basic concept but none of the example is relevant to my problem. Someone could help me?
EDIT - SOLUTION
Thanks to #Tibrogargan i have modified my function in this way:
for (i = 0; i < array.length; i++) {
addCheckBoxItem(form, array[i].key, form_peer_available_class, peer_choice, (value) => peer_choice = value);
}
and
function addCheckBoxItem(p, name, value, callback) {
// add checkbox
var newCheckbox = document.createElement("input");
newCheckbox.type = "checkbox";
newCheckbox.setAttribute("value", p);
newCheckbox.setAttribute("id", p);
newCheckbox.setAttribute("name", name);
newCheckbox.onchange = function(){
var cbs = document.getElementsByName(name);
for (var i = 0; i < cbs.length; i++) {
cbs[i].checked = false;
}
this.checked = true;
// define the peer selected as choice
callback(this.value);
};
form.appendChild(newCheckbox);
// add label to checkbox
var label = document.createElement('label');
label.setAttribute("name", name);
label.htmlFor = p;
label.appendChild(document.createTextNode(p));
form.appendChild(label);
// add br tag to checkbox
var br = document.createElement("br")
br.setAttribute("name", name);
form.appendChild(br);
}

Pass callback into addCheckBoxItem like that
// accumulator
var data = {}
// callback
var storeData = (name, value, p) => data[name] = value;
// callback as third argument
addCheckBoxItem('data1', 'checkbox1', storeData);
addCheckBoxItem('data2', 'checkbox2', storeData);
addCheckBoxItem('data3', 'checkbox3', storeData);
Check full example here http://jsfiddle.net/gtqnc109/9/

Related

Save on localstorage appended checkbox state

I have this function:
function test() {
var a = document.getElementById('test');
var b = document.createElement('input');
b.type = 'checkbox';
b.addEventListener( 'change', function() {
if(this.checked) {
//do something and save the state (checked)
} else {
//do something else and save the state(not checked)
}
}
and I want to save the state of the checkbox on localstorage from the appended checkbox, what is the best way to do it?
so if you are appending multiple checkboxes and you want to probably set all of their data separately you are going to need to have a different id for each checkbox so when you append a new one I would increment the ids
//function that appends new checkbox
var i = 0;
function appendCheckBox(){
i++
checkBoxId = 'checkbox' + i;
document.getElementById('checkbox-container').innerHTML = `<input type="checkbox" id="${checkBoxId}" onclick="handleCheckBoxClick(this)"></input>`;
}
//function to handle checkbox click you would probably want to make it check if
//the checkbox is already checked if it is set value to unchecked
function handleCheckBoxClick(ev){
var checkBoxId = ev.id;
localStorage.setItem(checkBoxId, 'checked')
}
You can use :
Setting storage :
localStorage.setItem('checkbox', b.checked);
Getting storage :
var checkVal=localStorage.getItem('checkbox');
You'll have to do a bit of work. localStorage doesn't work in a snippet here, so a working example of the example code can be found # this JSFiddle
localStorage.setItem("Checkboxes", "{}");
const showCurrentCheckboxStates = () =>
document.querySelector("pre").textContent = `Checkboxes saved state ${
JSON.stringify(JSON.parse(localStorage.getItem("Checkboxes")), null, " ")}`;
const saveCheckboxState = (val, id) => {
localStorage.setItem("Checkboxes",
JSON.stringify({
...JSON.parse(localStorage.getItem("Checkboxes")),
[`Checkbox ${id}`]: val })
);
showCurrentCheckboxStates();
};
const createCheckbox = id => {
let cb = document.createElement('input');
cb.type = 'checkbox';
cb.dataset.index = id;
cb.title = `Checkbox ${id}`;
document.body.appendChild(cb);
// save the initial state
saveCheckboxState(0, id);
};
document.addEventListener("click", evt =>
evt.target.dataset.index &&
saveCheckboxState(+evt.target.checked, evt.target.dataset.index)
);
for (let i = 1; i < 11; i += 1) {
createCheckbox(i);
}

Iterate through JSON object array radio button

A JSON like this is with me in a variable
var options_array =
[{"optionText":"1safsafs 1","optionDbId":1},{"optionText":"1safsafs 2","optionDbId":2},{"optionText":"1safsafs 3","optionDbId":3},{"optionText":" 1safsafs 4","optionDbId":4}]
I have to build a radio buttons with the items in this JSON and i am using the below code
var choice_div = document.getElementById("choice_div");
var options_array = "[{\"optionText\":\"1safsafs 1\",\"optionDbId\":1},{\"optionText\":\"1safsafs 2\",\"optionDbId\":2},{\"optionText\":\"1safsafs 3\",\"optionDbId\":3},{\"optionText\":\" 1safsafs 4\",\"optionDbId\":4}]";
console.log(options_array);
console.log(options_array.length); //174 is coming here instead of 4
for (i = 0; i < options_array.length; i++) {
var _text = JSON.stringify(options_array[i].optionText);
//console.log(_text); //all values are coming as undefined
var _value = JSON.stringify(options_array[i].optionDbId);
//console.log(_value);
var option_entry = makeRadioButton("selectedoption", _value, _text);
choice_div.appendChild(option_entry);
}
function makeRadioButton(name, value, text) {
var label = document.createElement("label");
var radio = document.createElement("input");
radio.type = "radio";
radio.name = name;
radio.value = value;
label.appendChild(radio);
label.appendChild(document.createTextNode(text));
return label;
}
but this code is adding 170 items to the DIV and i am getting radio button contents as undefined . Not able to spot the reason?
I am expecting this to build 4 radio buttons with 4 options in it
you had some funny errors XD, first this the working one
$(document).ready(function () {
var choice_div = document.getElementById('mydiv');
data = [{ "optionText": "1safsafs 1", "optionDbId": 1 }, { "optionText": "1safsafs 2", "optionDbId": 2 }, { "optionText": "1safsafs 3", "optionDbId": 3 }, { "optionText": " 1safsafs 4", "optionDbId": 4 }]
$.each(data, function (key, item) {
var text = item.optionText;
var value = item.optionDbId;
console.log(value);
var option_entry = makeRadioButton("option" + key, value, text);
choice_div.appendChild(option_entry);
});
});
function makeRadioButton(name, value, text) {
var label = document.createElement("label");
var radio = document.createElement("input");
radio.type = "radio";
radio.name = name;
radio.value = value;
label.appendChild(radio);
console.log("bot "+value);
label.appendChild(document.createTextNode(text));
return label;
}
then lets check what you did first you used JSON.stringify() with no reason , secondly you typed the json keys wrong thats was a little funny XD.
Javascript Object key is case sensitive. You've made some typos on your object keys.
optiontext -> optionText
optiondbid -> optionDbId
for (i = 0; i < options_array.length; i++) {
var _text = JSON.stringify(options_array[i].optionText);
//console.log(_text);
var _value = JSON.stringify(options_array[i].optionDbId);
//console.log(_value);
var option_entry = makeRadioButton("option" + i,_value, _text);
choice_div.appendChild(option_entry);
}
Update (11/10/2019)
The reason you are getting incorrect length is because you are logging JSON string length ( number of characters in your JSON string ) instead of the array length.
var choice_div = document.getElementById("choice_div");
// Get options_array as actual array instead of JSON string
var options_array = JSON.parse("[{\"optionText\":\"1safsafs 1\",\"optionDbId\":1},{\"optionText\":\"1safsafs 2\",\"optionDbId\":2},{\"optionText\":\"1safsafs 3\",\"optionDbId\":3},{\"optionText\":\" 1safsafs 4\",\"optionDbId\":4}]");
for (i = 0; i < options_array.length; i++) {
// Dont need to stringify here
var _text = options_array[i].optionText;
var _value = options_array[i].optionDbId;
var option_entry = makeRadioButton("selectedoption", _value, _text);
choice_div.appendChild(option_entry);
}
function makeRadioButton(name, value, text) {
var label = document.createElement("label");
var radio = document.createElement("input");
radio.type = "radio";
radio.name = name;
radio.value = value;
label.appendChild(radio);
label.appendChild(document.createTextNode(text));
return label;
}

Replace placeholder of an input in a dynamic form

What I am trying to achieve is to set the placeholder of an input field dynamically. I have an input where I say how many inputs I want to render in the form. On that created inputs I set an onchange event:
function inputOnchange (){
setTimeout(function(){
var createdInputs = document.querySelectorAll("*[class^='createInput']");
createdInputs.forEach( function(item){
item.onchange = function() {
changeFormPlaceholder();
}
})
}, 200);
}
As you see it runs an function when the onchange event is triggered below the function:
function changeFormPlaceholder(){
var inputs = document.querySelector('.formFieldInputs');
var num = 0;
var valueArray = {};
inputs.childNodes.forEach( function(input){
var inputValue = input.value;
var name = 'value' + num++;
valueArray[name] = inputValue;
})
for( var newPlaceholder in valueArray ){
if(valueArray.hasOwnProperty(newPlaceholder)){
console.log("newPLH", newPlaceholder, valueArray[newPlaceholder])
var form = document.querySelectorAll("*[class^='exitIntentInput']");
for(var i = 0; i < form.length; ++i){
// console.log("aaraay", form[i].placeholder);
form[i].placeholder = valueArray[newPlaceholder];
}
}
}
}
Now It changes only on the last input field and sets all input field to the second value.
So how can I change them individually?
Here is an FIDDLE
Type in something in the inputs on the sidebar you will see them appear on the right and now change the input value on the left you see my issue
You run a for loop in the other for loop,
for( var newPlaceholder in valueArray ){
if(valueArray.hasOwnProperty(newPlaceholder)){
console.log("newPLH", newPlaceholder, valueArray[newPlaceholder])
var form = document.querySelectorAll("*[class^='exitIntentInput']");
for(var i = 0; i < form.length; ++i){
// console.log("aaraay", form[i].placeholder);
form[i].placeholder = valueArray[newPlaceholder];
}
}
}
and when the second time of the outer for loop, the new Placeholdee="value1",
for(var i = 0; i < form.length; ++i)
// console.log("aaraay", form[i].placeholder);
form[i].placeholder = valueArray[newPlaceholder];
}
then the inner loop will set placeholder of all indexes of form to valueArray["value1"], the last value of inputs.
The simplest way to solve this problem is that declarie var valueArray as an array but object.
Thus no need to run twice for loops.
Code as follows:
function changeFormPlaceholder(){
var inputs = document.querySelector('.formFieldInputs');
var num = 0;
var valueArray = [];
inputs.childNodes.forEach( function(input){
var inputValue = input.value;
var name = 'value' + num++;
valueArray.push(inputValue);
})
var form = document.querySelectorAll("*[class^='exitIntentInput']");
for(var i = 0; i < form.length; ++i){
// console.log("aaraay", form[i].placeholder);
form[i].placeholder = valueArray[i];
}
}

How to access dynamically created button?

btnUpdate = document.createElement("BUTTON");
var t = document.createTextNode("Update");
btnUpdate.id = 'update0';
btnUpdate.appendChild(t);
tabCell.appendChild(btnUpdate);
I have a simple line of code where I have created a button with my javascript. How do I access this button through the same javascript file? I want to add onClick feature to it.
document.getElementById("update0").onclick = edit_row(0);
I tried doing so by adding the above line of code, but now it won't display the table but straight away jumps to the edit_row() function.
Edit:
function showCustomer() {
var obj, dbParam, xmlhttp, myObj, x, txt = "",tabCell;
var btnUpdate;
obj = { "table":"Successful", "limit":20 };
dbParam = JSON.stringify(obj);
xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
myObj = JSON.parse(xmlhttp.responseText);
console.log(myObj);
var col = [];
for (var i = 0; i < myObj.length; i++) {
for (var key in myObj[i]) {
if (col.indexOf(key) === -1) {
col.push(key);
}
}
}
key="Update";
col.push(key);
console.log(col);
// CREATE DYNAMIC TABLE.
var table = document.createElement("table");
// CREATE HTML TABLE HEADER ROW USING THE EXTRACTED HEADERS ABOVE.
var tr = table.insertRow(-1); // TABLE ROW.
for (var i = 0; i < col.length; i++) {
var th = document.createElement("th"); // TABLE HEADER.
th.innerHTML = col[i];
tr.appendChild(th);
}
// ADD JSON DATA TO THE TABLE AS ROWS.
for (var i = 0; i < myObj.length; i++) {
tr = table.insertRow(-1);
tabCell = null;
for (var j = 0; j < col.length-1; j++) {
tabCell = tr.insertCell(-1);
tabCell.innerHTML = myObj[i][col[j]];
}
tabCell = tr.insertCell(-1);
btnUpdate = document.createElement("BUTTON");
var t = document.createTextNode("Update");
btnUpdate.id = 'update'+i;
btnUpdate.appendChild(t);
tabCell.appendChild(btnUpdate);
}
tr = table.insertRow(-1);
tabCell = null;
for (var j = 0; j < col.length-1; j++) {
tabCell = tr.insertCell(-1);
tabCell.innerHTML = " ";
}
tabCell = tr.insertCell(-1);
var btn = document.createElement("BUTTON");
var t = document.createTextNode("Add Row");
btn.appendChild(t);
tabCell.appendChild(btn);
document.getElementById("update0").addEventListener = function (){
edit_row(0);
};
// FINALLY ADD THE NEWLY CREATED TABLE WITH JSON DATA TO A CONTAINER.
var divContainer = document.getElementById("showData");
divContainer.innerHTML = "";
divContainer.appendChild(table);
}
};
xmlhttp.open("POST", "http://localhost:8090/Vaccine", true);
xmlhttp.setRequestHeader("Content-type", "application/JSON");
xmlhttp.send("x=" + dbParam);
}
function edit_row(no)
{
alert("HELLO");
}
With this line :
document.getElementById("update0").onclick = edit_row(0);
You are not "attaching" the click event to the edit_row function. You're setting the onclick property with the result of the edit_row(0) invokation.
Also, don't use the onclick property.
Use the addEventListener function instead.
document.getElementById("update0").addEventListener("click", function () {
edit_row(0);
});
If you need a reason : by overwriting the onclick property, you could be disabling any other click event listener on your elements. By using addEventListener(), you can have several events listener on the same element/event couple.
And you can do this right after you created the button. You don't need to get it by its id later.
Your code would look like this :
btnUpdate = document.createElement("BUTTON");
var t = document.createTextNode("Update");
btnUpdate.id = 'update0';
btnUpdate.appendChild(t);
btnUpdate.addEventListener("click", function () {
edit_row(0);
});
You have to do that in callback of on click event. If you inline, it executes directly when javascript reading your code.
document.getElementById("update0").onclick = function (){
edit_row(0);
};
How do I access this button through the same javascript file?
The same way you've been accessing it all along.
It is stored in the btnUpdate variable. Use that.
but now it won't display the table but straight away jumps to the edit_row() function.
That is because you are calling edit_row and setting its return value as the click handler.
Since you want to pass arguments to it, the easiest thing to do is to create a new function.
function edit_row_first_argument_0 () {
edit_row(0);
}
button.addEventListener("click", edit_row_first_argument_0);
(You can use an anonymous function expression, I use the verbose approach above for clarity).
Try this:
btnUpdate = document.createElement("BUTTON");
var t = document.createTextNode("Update");
btnUpdate.id = 'update0';
btnUpdate.appendChild(t);
tabCell.appendChild(btnUpdate);
btnUpdate.addEventListener("click", (e) => {
// this linked to btnUpdate
// Here make whatever you want
// You can call edit_row now
edit_row(0)
})
It seems that your button is not in the DOM yet, so you are not able to find it with document. You can use the variable btnUpdate if it is in the same file like btnUpdate.onclick = function() {}, or using addEventListenerlike btnUpdate.addEventListener('click', function() {}).
Also, it seems you are executing the edit_row(0) function. You need to put it inside a function like
btnUpdate.addEventListener('click', function() {
edit_row(0);
})
You call the function when you have () at the end so
document.getElementById("update0").onclick = edit_row(0);
will immediately call edit_row
Why not do this instead:
btnUpdate = document.createElement("BUTTON");
var t = document.createTextNode("Update");
btnUpdate.id = 'update0';
btnUpdate.onclick=function() {
edit_row(this.id.replace("update","")); // or use a data-attribute
}
btnUpdate.appendChild(t);
tabCell.appendChild(btnUpdate);
or use event delegation:
Native JS equivalent to jquery delegation

How to change a button from another function?

var ButtonFarmAtivada = new Array();
function X() {
var tableCol = dom.cn("td"); //cell 0
//create start checkbox button
ButtonFarmAtivada[index] = createInputButton("checkbox", index);
ButtonFarmAtivada[index].name = "buttonFarmAtivada_"+index;
ButtonFarmAtivada[index].checked = GM_getValue("farmAtivada_"+index, true);
FM_log(3,"checkboxFarm "+(index)+" = "+GM_getValue("farmAtivada_"+index));
ButtonFarmAtivada[index].addEventListener("click", function() {
rp_farmAtivada(index);
}, false);
tableCol.appendChild(ButtonFarmAtivada[i]);
tableRow.appendChild(tableCol); // add the cell
}
1) is it possible to create the button inside an array as I'm trying to do in that example? like an array of buttons?
2) I ask that because I will have to change this button later from another function, and I'm trying to do that like this (not working):
function rp_marcadesmarcaFarm(valor) {
var vListID = getAllVillageId().toString();
FM_log(4,"MarcaDesmarcaFarm + vListID="+vListID);
var attackList = vListID.split(",");
for (i = 0; i <= attackList.length; i++) {
FM_log(3, "Marca/desmarca = "+i+" "+buttonFarmAtivada[i].Checked);
ButtonFarmAtivada[i].Checked = valor;
};
};
For number 1) yes, you can.
function createInputButton(type, index) { // um, why the 'index' param?
// also, why is this function called 'createInputButton'
// if sometimes it returns a checkbox as opposed to a button?
var inputButton = document.createElement("input");
inputButton.type = type; // alternately you could use setAttribute like so:
// inputButton.setAttribute("type", type);
// it would be more XHTML-ish, ♪ if that's what you're into ♫
return inputButton;
}
I don't really understand part 2, sorry.

Categories