I have a script where I'm appending elements to a list. I would need that when I click the element a function is called, and for this function the value of a variable when creating the li is needed (it's the li content).
I've checked solutions like adding newLi.onclick = function(){...}.
The problem with this solution is that I'm not getting the right value in the function, I get the value of another element in the list.
Right now this is how I'm creating the elements:
var ULlist = document.getElementById('ULid');
for(i=0;i<data.length;i++){
var Value = data[i] //function to get data
var newLi = document.createElement('li');
newLi.appendChild(elements.createTextNode(Value));
newLi.onclick = function(){alert(Value)} //not displaying the right value
ULlist.appendChild(newLi);
}
So the question is, is there any way to create te onclick event giving to the element the right value of the variable?
Edit: I've added a portion more of code.
Li's are being created, and information displayed correctly, the only problem is when trying to create the event that it's not giving the right value, that should be the value cointained at the li
You can achieve this by creating function inside and keeping the value in the scope of that function.
var data = [10, 20, 30, 40, 50, 60, 70];
addItems = function() {
var list = document.getElementById("list");
for (var i = 0; i < data.length; i++) {
var newLi = document.createElement("li");
newLi.innerHTML = i + 1;
list.appendChild(newLi);
(function(value){
newLi.addEventListener("click", function() {
alert(value);
}, false);})(data[i]);
}
}
jsfiddle : http://jsfiddle.net/Qf5JZ/1/
Use DOM2 event listeners, in particular the element.addEventListener API:
function clickHandlerFor(data) {
return function(event) {
var li = event.target;
// do something with data and li.
};
}
for (...) {
var Data = ... //function to get data
var newLi = elements.createElement('li');
newLi.appendChild(elements.createTextNode(Data));
newLi.addEventListener("click", clickHandlerFor(Data), false);
ULlist.appendChild(newLi);
}
Another option is much simpler: use the TextNode value in your handler:
function handler(event) {
var dataValue = event.target.firstChild.nodeValue; // value of TextNode created by elements.createTextNode(Data)
// handle dataValue
}
newLi.addEventListener("click", handler, false);
When I experienced this problem, I solved it like this:
var ULlist = document.getElementById('ULid');
for(var i=0; i<data.length; i++){
var index = i;
(function() {
var Value = data[index] //function to get data
var newLi = document.createElement('li');
newLi.appendChild(elements.createTextNode(Value));
newLi.onclick = function() { ... };
ULlist.appendChild(newLi);
}());
}
Edit: Today, I remember another thing about for scope. It is another solution to send parameter 'i' to function inside the loop:
var ULlist = document.getElementById('ULid');
for(var i=0; i<data.length; i++){
(function(index) {
var Value = data[index] //function to get data
var newLi = document.createElement('li');
newLi.appendChild(elements.createTextNode(Value));
newLi.onclick = function() { ... };
ULlist.appendChild(newLi);
}(i));
}
Try this and let me know if it works.
Related
So I'm trying to create a list of input with unique values which are gotten from a array of objects. But for some reason it only iterates once and stops.
function loadLayer() {
//Get the object from local storage
var project = JSON.parse(localStorage.getItem('project'));
var projectLayers = project.layers
for (var x = 0; x < projectLayers.length; x++) {
var x = createLayer(projectLayers[x].name)
appendLayer(x)
}
}
So project layer is basically an array like [{id=1,name="bob},{id=2,name="kevin"}]
function createLayer(name) {
var li = document.createElement("li");
li.className = "list-group-item"
var x = document.createElement("INPUT")
x.setAttribute("type", "text")
x.setAttribute("value", name)
li.appendChild(x)
return li
}
function appendLayer(layer) {
var layerList = document.getElementById("layerList")
layerList.appendChild(layer)
}
and appendlayer just adds the li to the ul
However, after i run the program my only has one with a input with bob inside it. Where did the other no go. I tried printing to see if second loop was called but it didn't seem like it. I don't know why and been stuck for hours.
Just like you have been told, you need to be careful with the way you name variables.
Secondly I will also suggest using let instead of var. Because you could easily overwrite a variable declared with var outside its initial scope.
And now to your code:
I made some edit to your code especially the loadLayer function and it appends both names to the list:
<script>
let projectList = [
{
id:1,
name:"bob"
},
{
id:2,
name:"kevin"
}
]
function loadLayer() {
window.localStorage.setItem('project', JSON.stringify(projectList));
let p = JSON.parse(window.localStorage.getItem('project'));
for (let i = 0; i < p.length; i++) {
let projectName = createLayer(p[i].name)
appendLayer(projectName)
}
}
function createLayer(name) {
let li = document.createElement("li");
li.className = "list-group-item"
let x = document.createElement("INPUT")
x.setAttribute("type", "text")
x.setAttribute("value", name)
li.appendChild(x)
return li
}
function appendLayer(layer) {
let layerList = document.getElementById("layerList")
layerList.appendChild(layer)
}
loadLayer()
</script>
You are naming the variable of the iteration in the loop as x and the var x = createLayer(projectLayers[x].name) conflicts with it, change one of them.
I'm looping through some elements by class name, and adding event listeners to them. I then grab the id of the selected element (in this case "tom"), and want to use it to find the value of "role" in the "tom" object. I'm getting undefined? can anyone help?
var highlightArea = document.getElementsByClassName('highlightArea');
for (var i = 0; i < highlightArea.length; i++) {
highlightArea[i].addEventListener("mouseover", showPopup);
highlightArea[i].addEventListener("mouseover", hidePopup);
}
function showPopup(evt) {
var tom = { title:'tom', role:'full stack man' };
var id = this.id;
var role = id.role;
console.log(role)
}
You are not selecting the elements correctly, the class is hightlightArea and you are querying highlightArea (missing a 't'), so, no elements are found (you can easily discover that by debugging or using console.log(highlightArea) that is the variable that holds the elements found.
Just because the id of an element is the same name as a var, it doesn't mean that it have the properties or attributes of the variable... So when you get the Id, you need to check which one is and then get the variable that have the same name.
Also, you are adding the same listener two times mouseover that way, just the last would work, it means just hidePopup. I changed to mouseenter and mouseleave, this way will work correctly.
After that, you will be able to achieve your needs. Below is an working example.
var highlightArea = document.getElementsByClassName('hightlightArea');
var mypopup = document.getElementById("mypopup");
var tom = { title:'tom', role:'marketing'};
var jim = { title:'jim', role:'another role'};
for (var i = 0; i < highlightArea.length; i++) {
highlightArea[i].addEventListener("mouseenter", showPopup);
highlightArea[i].addEventListener("mouseleave", hidePopup);
}
function showPopup(evt) {
let ElemId = this.id;
let role;
let title;
if (ElemId == 'tom'){
role = tom.role;
title = tom.title;
}else if (ElemId == 'jim'){
role = jim.role;
title = jim.title;
}
let iconPos = this.getBoundingClientRect();
mypopup.innerHTML = role;
mypopup.style.left = (iconPos.right + 20) + "px";
mypopup.style.top = (window.scrollY + iconPos.top - 60) + "px";
mypopup.style.display = "block";
}
function hidePopup(evt) {
mypopup.style.display = "none";
}
<div class="hightlightArea" id="jim">Div Jim</div>
<div class="hightlightArea" id="tom">Div Tom</div>
<div id="mypopup"></div>
in your function 'showPopup' you have this:
var id = this.id
but this.id is not defined. You probably meant to write this:
var title = dom.title;
below I'm trying to add new anchor elements to the DOM.
I also like to add an onclick event to each new created element that returns its id, but can't get it done.
All help is welcome!
var text = document.getElementById("output");
for (var i = 0; i < uld.length; i++){
var x = document.createElement("A");
var t = document.createTextNode(uld[i][1]);
x.setAttribute('id', i);
x.onclick = function getId() {alert("kikker");};
x.appendChild(t);
text.appendChild(x);
}
The 'this' pointer in a onclick is refering to the element.
So you could use the 'id' like this:
var text = document.getElementById("output");
var i;
for (i = 0; i < uld.length; i++) {
var x = document.createElement("A");
var t = document.createTextNode(uld[i][1]);
x.setAttribute("id", i);
x.onclick = function() {
var id = this.id;
alert(id);
};
x.appendChild(t);
text.appendChild(x);
}
In Google App Scripts (GAS), I want to be able to add and remove TextBox and TextArea elements to a FlexTable (that's being used as a form) and not worry about how many there are. I've named the text elements based on a counter to make this process easier.
So, is there a way to get the number of inputs (TextBox + TextArea) passed to e.parameter after the form is submitted?
Here's the relevant code from the FlexTable:
function doGet() {
var app = UiApp.createApplication();
var flex = app.createFlexTable().setId('myFlex');
var counter = 0;
var row_counter = 0;
...
var firstnameLabel = app.createLabel('Your FIRST Name');
var firstnameTextBox = app.createTextBox().setWidth(sm_width).setName('input' + counter).setText(data[counter]);
flex.setWidget(row_counter, 1, firstnameLabel);
flex.setWidget(row_counter, 2, firstnameTextBox);
row_counter++;
counter++;
var lastnameLabel = app.createLabel('Your LAST Name');
var lastnameTextBox = app.createTextBox().setWidth(sm_width).setName('input' + counter).setText(data[counter]);
flex.setWidget(row_counter, 1, lastnameLabel);
flex.setWidget(row_counter, 2, lastnameTextBox);
row_counter++;
counter++;
...
var submitButton = app.createButton('Submit Proposal');
flex.setWidget(row_counter, 2, submitButton);
var handler = app.createServerClickHandler('saveProposal');
handler.addCallbackElement(flex);
submitButton.addClickHandler(handler);
var scroll = app.createScrollPanel().setSize('100%', '100%');
scroll.add(flex);
app.add(scroll);
return app;
}
And here's the code for the ClickHandler (notice that I currently have 39 elements in my FlexTable):
function saveProposal(e){
var app = UiApp.getActiveApplication();
var userData = [];
var counter = 39;
for(var i = 0; i < counter; i++) {
var input_name = 'input' + i;
userData[i] = e.parameter[input_name];
}
So, is there a way to get the number of elements (in this case 39) without manually counting them and assigning this value to a variable?
I'm new at this stuff and I'd appreciate your help.
Cheers!
The simplest way is to add a hidden widget in your doGet() function that will hold the counter value like this :
var hidden = app.createHidden('counterValue',counter);// don't forget to add this widget as a callBackElement to your handler variable (handler.addCallBackElement(hidden))
then in the handler function simply use
var counter = Number(e.parameter.counterValue);// because the returned value is actually a string, as almost any other widget...
If you want to see this value while debugging you can replace it momentarily with a textBox...
You can search for arguments array based object.
function foo(x) {
console.log(arguments.length); // This will print 7.
}
foo(1,2,3,4,5,6,7) // Sending 7 parameters to function.
You could use a while loop.
var i = 0;
var userData = [];
while (e.parameter['input' + i] != undefined) {
userData[i] = e.parameter['input' + i];
i++;
};
OR:
var i = 0;
var userData = [];
var input_name = 'input0';
while (e.parameter[input_name] != undefined) {
userData[i] = e.parameter[input_name];
i++;
input_name = 'input' + i;
};
I am creating div tags on the fly inside a for loop.
The divs are outputted nicely like a chess table and there is a unique id for each.
I just don't know how to retrieve it in its click function. 'this.id' or $(this).id doesn't work (I generally use it in $.each methods).
*How could I retrieve/refer to the id inside the click function ? *
I've posted a bigger code part width variables, but the main part is this:
$("<div/>", {
class: gridClass,
id: cardID,
click: function(e) {
alert(this.id);
}
});
more from the code:
var init = function() {
//variable declaration
var GRID_WIDTH = 2,
GRID_HEIGHT = 2,
var FACE_DOWN = 0;
var cont = $("<div/>", {
id: 'container'
});
var c1 = "card";
var c2 = "card cardfirstInRow";
var gridClass = "";
var cardID = "";
// end variable declaration
// creating DIV-s on the fly
for (var x = 0; x < GRID_WIDTH; x++) {
for (var y = 0; y < GRID_HEIGHT; y++) {
y === 0 ? gridClass = 'card cardfirstInRow' : gridClass = 'card';
cardID = controller.getCardID(); //returns a unique number converted to string
$("<div/>", {
class: gridClass,
id: cardID,
click: function(e) {
alert(this.id);
}
}).appendTo(cont);
}
}
}
The problem is in your click function, not your creation of the div function. Because you are adding the div's to the DOM you need to use event delegation to capture the click event when it bubbles up -
$('body').on('click', 'div' function() {
console.log( this.id );
});
e.target gives you the element (javascript object)
To get the id just use
var elemId = e.target.id;
try this
$(this).attr('id');
that is the method that returns an attribute value of an element using jQuery
Here is the Fiddle