Button created dynamically cant accses - javascript

I am learning javascript, and i am trying to get accses to a button that is created dynamically within a function. The first function createHtml just gets data and creates elements and store them in a variable that i add to the html element and store them in the beerContainer, and that works. I cant however accses the button that is created in the function createHtml. How can i get the alert to pop up when im clicking on saveBeer?
let btn = document.querySelector('#myBtn');
let beerContainer = document.querySelector('#beer-data');
function createHtml(result) {
var html = '';
for(let i = 0; i < result.data.length; i++) {
html += "<h3>"+ result.data[i].name +"</h3>"
html += "<p>"+ result.data[i].description +"</p>"
html += "<button id='save-beer' data-id='"+ result.data[i].id+"'>Save Beer</button>"
}
beerContainer.innerHTML = html;
}
btn.addEventListener('click', function(event) {
fetchApiData(createHtml);
});
var saveBeer = document.querySelector('.save-beer');
saveBeer.addEventListener('click', function(event) {
alert("Hi");
});

try using
var saveBeer = document.querySelector('#save-beer'); // access by id
rather than
var saveBeer = document.querySelector('.save-beer'); // trying to access by class which does not exist
Note the '#' rather than '.' in the querySelector argument

Related

Javascript - Get Id from innerHTML element

I have a function which creates new elements in a for loop. For example, I want a div for every item in an array. But I need the ID of the created html div-tag to trigger another function.
This is what I currently got:
function change() {
for (let i = 0; i <= 2; i++) {
let modal = document.createElement('div');
let a = '<div id="id'+i+'"> innerHTML </div>';
modal.innerHTML = a;
// document.getElementById(a.this.id).innerHTML = "get by id";
document.getElementById('test').appendChild(
modal
);
}
}
<div class="test" id="test">test</div>
<button onclick="change()">Change</button>
I need to get the id of every div which is created onclick.
I tried to to like document.getElementById('id' + i).innerHTML = "do something"; but this doesnt work. Someone have a solution for my problem? jQuery is also an option!
You can only use document.getElementById after the element has been added to the DOM.
//...
document.getElementById('test').appendChild(modal);
document.getElementById('id' + i).innerHTML = "get by id";
//...

Is there a way to make a function that can be accessed later in a google chrome extension?

I am trying to make an extension that makes a button which then executes a function, however, because the extension executes a javascript file after the page loads. However, when I create the button I want to run a function. Is there a way I can store a function and variables that can be run and access later by the button?
var effect = [[1,100],[2,32], [5,3]];
var points = (function(){var adding = 0;for(var i = 0; i<effect.length;i++){adding+=effect[i][0];};return adding;})()
var score = (function(){var adding = 0;for(var i = 0; i<effect.length;i++){adding+=effect[i][1];};return adding;})()
var percentage=(score/points*100).toString()+"%";
this.effect = effect;
this.points = points;
this.score = score;
var percentage = points/score;
function list_effect(){
var effect_string = "";
for(var i = 0; i<effect.length;i++){
effect_string += ((points-effect[i][0])/score) - ((points)/score);
}
alert(effect_string);
}
if(percentage == 'NaN%'){
// alert('ERROR');
}else{
document.getElementsByClassName("agenda")[0].innerHTML = "<button type=\'button\' id=\'get_list\'>Get List</button>"+ document.getElementsByClassName("agenda")[0].innerHTML;
document.getElementsByClassName("agenda")[0].innerHTML += "<script>" + "this.effect=" + effect.toString() + ";\nthis.points=" + points.toString()+ ";\nthis.score=" + score.toString() +"document.getElementById(\"get_list\").addEventListener(\"onclick\", list_effect());" + "</script>"
}
I have tryied useing this. however that does not work
<script> won't run when added via innerHTML, you should add it using appendChild
normally you don't need to add a <script> element at all, just use createElement and attach the listeners directly
var button = document.createElement('button');
button.id = 'get_list';
button.onclick = function (e) {
// use your variables here directly
};
// clear the previous contents
document.querySelector('.agenda').textContent = '';
// add the button
document.querySelector('.agenda').appendChild(button);

javascript adding click events to buttons in a loop

The code below gets info from xml file.
I succesfully presents the id and name of each planet with a button.
I want to add an onclick event on the button.
Problem now is: it does add the onclick event but only on the last button created in the loop.
What am i doing wrong? Why doesnt it create a onclick event for each button, but only for the last one in loop?
function updatePlaneten() {
var valDiv, planets, valButton, textNode;
// Get xml files
planets = this.responseXML.getElementsByTagName("planeet");
// loop through the <planet> tags
for (var i = 0; i < planets.length; i++) {
valDiv = ''; // clear valDiv each time loop starts
// Get the id and the name from the xml info in current <planet> tag
valDiv += planets[i].getElementsByTagName("id")[0].childNodes[0].nodeValue + "<br>";
valDiv += planets[i].getElementsByTagName("name")[0].childNodes[0].nodeValue + "<br>";
document.getElementById("planetenID").innerHTML += valDiv + "<br>";
// Create button with a value and pass in this object for later reference use (valButton.object=this)
valButton = document.createElement("input");
// valButton.setAttribute("planeetID", planets[i].getElementsByTagName("id")[0].childNodes[0].nodeValue);
valButton.setAttribute("value", 'Meer info');
valButton.setAttribute("type", 'button');
valButton.id = (i + 1);
valButton.object = this;
//
// Here is the problem i cant get fixed
//
//valButton.onclick = function(){ showinfo(); }
valButton.addEventListener('click', showinfo);
// Place the button on screen
document.getElementById("planetenID").appendChild(valButton);
}
}
// simple function to check if it works
function showinfo() {
console.log(this.object);
console.log(this.id);
}
The trouble is this line:
document.getElementById("planetenID").innerHTML += valDiv + "<br>";
When you set innerHTML the content currently in there gets destroyed and replaced with the new html, meaning all your old buttons are now destroyed and new ones are created. The previously attached event listeners do not get attached to the new buttons.
Instead simply create a div/span or whatever container would best help, add your planet text or whatever to it and then use appendChild
valDiv = document.createElement("div");
var id = planets[i].getElementsByTagName("id")[0].childNodes[0].nodeValue;
var name = planets[i].getElementsByTagName("name")[0].childNodes[0].nodeValue;
valDiv.innerHTML = id+"<br>"+name+"<br>";
document.getElementById("planetenID").appendChild(valDiv);
You could also use insertAdjacentHTML
var id = planets[i].getElementsByTagName("id")[0].childNodes[0].nodeValue;
var name = planets[i].getElementsByTagName("name")[0].childNodes[0].nodeValue;
valDiv = id+"<br>"+name+"<br>";
document.getElementById("planetenID").insertAdjacentHTML("beforeend",valDiv);
function updatePlaneten() {
var valDiv, planets, valButton, textNode;
// Get xml files
planets = this.responseXML.getElementsByTagName("planeet");
// loop through the <planet> tags
for (var i = 0; i < planets.length; i++) {
(function(num){
valDiv = document.createElement("div");
// Get the id and the name from the xml info in current <planet> tag
var id = planets[num].getElementsByTagName("id")[0].childNodes[0].nodeValue + "<br>";
var name = planets[num].getElementsByTagName("name")[0].childNodes[0].nodeValue + "<br>";
valDiv.innerHTML = id+"<br>"+name+"<br>";
document.getElementById("planetenID").appendChild(valDiv);
// Create button with a value and pass in this object for later reference use (valButton.object=this)
valButton = document.createElement("input");
// valButton.setAttribute("planeetID", planets[i].getElementsByTagName("id")[0].childNodes[0].nodeValue);
valButton.setAttribute("value", 'Meer info');
valButton.setAttribute("type", 'button');
valButton.id = (num + 1);
valButton.object = this;
// FIX: PASS showinfo TO AN ANONYMOUS FUNCTION CONTAINING THE OBJECT
valButton.addEventListener('click', function(){
showinfo(valButton);
});
// Place the button on screen
document.getElementById("planetenID").appendChild(valButton);
}(i));
}
}
// simple function to check if it works
function showinfo(valButton) {
console.log(valButton.object);
console.log(valButton.id);
}

Using this within functions called with onclick event in Javascript

I'm currently building a small Todo list application using vanilla Javascript but I'm having some issues creating a delete button that onClick removes it's parent element.
From what I have read, when an onClick is called in Javascript the this keyword can be used to refer to the element that called the function. With this in mind I have the following code:
window.onload = initialiseTodo;
function addRecord(){
var title = document.getElementById('issueTitle');
var issueContent = document.getElementById('issueContent');
var contentArea = document.getElementById('contentArea');
if(title.value.length > 0 && issueContent.value.length > 0){
var newItem = document.createElement('div');
newItem.id = 'task' + count++;
newItem.className = 'task';
newItem.innerHTML = '<div class="taskbody"><h1>' + title.value + '</h1>'+ issueContent.value + '</div><div class="deleteContainer">'
+ '<a class="delete">DELETE</a></div>';
contentArea.appendChild(newItem);
assignDeleteOnclick();
}
}
function deleteRecord(){
this.parentNode.parentNode.parentNode.parentNode.removeChild(this.parentNode.parentNode);
}
function assignDeleteOnclick(){
var deleteArray = document.getElementsByClassName('delete');
for(var i=0;i<deleteArray.length;i++){
deleteArray[i].onclick= deleteRecord();
}
}
function initialiseTodo(){
var btn_addRecord = document.getElementById('addRecord');
btn_addRecord.onclick = addRecord;
}
Basically I have a form that has two fields. When these fields are filled and the addRecord button is clicked a new div is added at the bottom of the page. This div contains a delete button. After the creation of this I assign an onclick event to the delete button which assigns the deleteRecord function when the delete button is clicked. My issue is with the deleteRecord function. I have used this to refer to the calling element (the delete button) and wish to remove the task div that is the outermost container however I current get a message that says: 'Cannot read property 'parentNode' of undefined ' which suggests to me the this keyword is not working correctly.
Any help would be greatly appreciated.
I've added the full code to a fiddle.
http://jsfiddle.net/jezzipin/Bd8AR/
J
You need to provide the element itself as a parameter. I did so by changing the html to include onclick="deleteRecord(this)" to make it a little easier to deal with. This means you can remove the assignDeleteOnclick() function
function deleteRecord(elem){
elem.parentNode.parentNode.remove();
}
Demo
You might style the .content to be hidden better if there are no elements to prevent that extra white space
Edit
Since you don't want an inline onclick, you can do it with js the same:
function deleteRecord(elem){
elem.parentNode.parentNode.remove();
}
function assignDeleteOnclick(){
var deleteArray = document.getElementsByClassName('delete');
for(var i=0;i<deleteArray.length;i++){
// Has to be enveloped in a function() { } or else context is lost
deleteArray[i].onclick=function() { deleteRecord(this); }
}
}
Demo

obj is null, javascript

function init()
{
alert("init()");
/**
* Adds an event listener to onclick event on the start button.
*/
xbEvent.addEventListener(document.getElementById("viewInvitation"), "click", function()
{
new Ajax().sendRequest("31260xml/invitations.xml", null, new PageMaster());
xbEvent.addEventListener(document.getElementById("declinebutton"), "click", function ()
{
declineInvitation();
});
});
ok so what I have here is a event listerner function, the case is when viewInvitation is clicked , the program will fetch my xml file and run page master function where I created my decline button with id="declinebutton", however this does not work, the error message that i get is obj=null or the program could not find id = declinebutton, why is it so? I have created it when I called page master using dom. any help will be appreciated.
function PageMaster()
{
this.contentDiv = document.getElementById("content");
}
/**
* Builds the main part of the web page based on the given XML document object
*
* #param {Object} xmlDoc the given XML document object
*/
var subjectList;
var i;
PageMaster.prototype.doIt = function(xmlDoc)
{
alert("PageMaster()");
alert("Clear page...");
this.contentDiv.innerHTML = "";
if (null != xmlDoc)
{
alert("Build page...");
//create div Post
var divPost = document.createElement("div");
divPost.className = "post";
//create h1 element
var h1Element = document.createElement("h1");
var headingText = document.createTextNode("Invitations");
h1Element.appendChild(headingText);
//insert h1 element into div post
divPost.appendChild(h1Element);
subjectList = xmlDoc.getElementsByTagName("subject");
var groupList = xmlDoc.getElementsByTagName("group");
for (i = 0; i < subjectList.length; i++) //for each subject
{
var divEntry = document.createElement("div");
divEntry.className = "entry";
var subjectNum = subjectList[i].attributes[0].nodeValue;
var subjectName = subjectList[i].attributes[1].nodeValue;
var groupId = groupList[i].attributes[0].nodeValue;
var groupName = groupList[i].attributes[1].nodeValue;
var ownerId = groupList[i].attributes[2].nodeValue;
//set up the invitation table attributes
var table=document.createElement("table");
table.width = 411;
table.border = 3;
table.borderColor = "#990000"
var input=document.createElement("p");
var inputText=document.createTextNode("You are invited to join " + groupName + "(groupId : " + groupId +")");
input.className="style11";
var blank=document.createElement("nbps");
input.appendChild(inputText);
var acceptButton=document.createElement("input");
acceptButton.type="button";
acceptButton.id="acceptbutton";
acceptButton.value="accept";
var declineButton=document.createElement("input");
declineButton.type="button";
declineButton.id="declinebutton";
declineButton.value="decline";
table.appendChild(input);
table.appendChild(acceptButton);
table.appendChild(declineButton);
divEntry.appendChild(table);
var blankSpace = document.createElement("p");
divEntry.appendChild(blankSpace);
divPost.appendChild(divEntry);
}
//insert div post into div content
this.contentDiv.appendChild(divPost);
}
};
/**function getValueOf()
{
return i;
}**/
function declineInvitation()
{
alert("decline");
}
function acceptInvitation()
{
alert("hello");
/**var pos=getValueOf();
alert(subjectList[pos].attributes[0].nodeValue);**/
}
That's my page master function, and I definitely have created the button. but it does not work.
Try calling your function like this:
window.onload=init;
The javascript runs as the page loads. At that point, the element does not yet exist in the DOM tree. You'll need to delay the script until the page has loaded.
The example you gave doesn't create the "Decline" button, as your question suggests it should. If it should, you might want to look at that.
Of course, if the button already exists, please disregard this answer.
You have a listener inside a listener. Is that right?
What about this?:
function init(){
alert("init()");
/** * Adds an event listener to onclick event on the start button. */
xbEvent.addEventListener(document.getElementById("viewInvitation"), "click", function()
{
new Ajax().sendRequest("31260xml/invitations.xml", null, new PageMaster());
}
xbEvent.addEventListener(document.getElementById("declinebutton"), "click", function ()
{
declineInvitation();
});
As far as I understand, you create button with id="declinebutton" for each entry from xml, is that right?
If yes, I'd suggest you to generate different id's for each button (for example, append line index to 'declinebutton', so you have buttons 'declinebutton0', 'declinebutton1' an so on), and assign event listener to buttons separately in the loop.

Categories