I am trying to dynamically add an anchor element through Javascript. The problem I have is the onclick event is not firing. I believe the problem is how I am generating the HTML. I am creating an array and then push my HTML code to the array. After I have created my output I am joining the array and then adding it to the div tag I have.
var itemLink = new Object();
itemLink.LinkName = "Edit User";
itemLink.LinkListClass = "";
itemLink.LinkListRole = "";
itemLink.LinkFunction = function() {
//do something specific with rowItem variable
alert(rowItem);
}
var aTag = document.createElement("a");
aTag.setAttribute('class', 'btn btn-primary');
aTag.innerHTML = itemLink.LinkName;
aTag.setAttribute('href', '#');
var rowItem = 'abc1111'; //would be setting the rowId or some sort of identifier
aTag.onclick = itemLink.LinkFunction;
var output = [];
output.push('<table>');
output.push('<thead>');
output.push('<tr><th>col1</th><th>col2</th></tr>');
output.push('</thead>');
output.push('<tbody>');
output.push('<tr><td>col1 data</td><td>col2 data</td></tr>');
output.push('</tbody></table>')
var d1 = document.createElement('div');
d1.appendChild(aTag);
output.push(d1.innerHTML);
var mainView = document.getElementById('mainViewer');
mainView.innerHTML = output.join('');
<div id="mainViewer"></div>
When I generate the output without the use of the array and joining of the output, the anchor element gets created and the onclick event works just fine.
Any ideas?
I will have multiple anchor links and I don't want to hardcode the function name. I want the onclick event to fire whatever function the itemLink Object has set.
What's the problem? You bind a function to a temp DOM element, then append its html, not its events (that's how innerHTML works). So when a link appended to the DOM, it's a different DOM link, so although the link looks the same it's not.
So, what is the solution? to push a DOM element instead of string, something like this:
//var itemLink = new Object();
//itemLink.LinkName = "Edit User";
//itemLink.LinkListClass = "";
//itemLink.LinkListRole = "";
//itemLink.LinkFunction = function() {
//do something specific with rowItem variable
//alert(rowItem);
//}
var itemLink = {
LinkName: "Edit User",
LinkListClass: "",
LinkListRole: "",
LinkFunction: function() {
//do something specific with rowItem variable
alert(rowItem);
}
};
var aTag = document.createElement("a");
aTag.setAttribute('class', 'btn btn-primary');
aTag.innerHTML = itemLink.LinkName;
aTag.setAttribute('href', '#');
var rowItem = 'abc1111'; //would be setting the rowId or some sort of identifier
aTag.onclick = itemLink.LinkFunction;
var output = [];
output.push('<table>');
output.push('<thead>');
output.push('<tr><th>col1</th><th>col2</th></tr>');
output.push('</thead>');
output.push('<tbody>');
output.push('<tr><td>col1 data</td><td>col2 data</td></tr>');
output.push('</tbody></table>')
var mainView = document.getElementById('mainViewer');
mainView.innerHTML = output.join('');
var d1 = document.createElement('div');
d1.appendChild(aTag);
mainView.appendChild(d1)
<div id="mainViewer"></div>
Thanks to #David Thomas for his comment :)
Related
I have such code:
var pageCount = 5; //for example, doesn't really matter
var paginationList = document.createElement("ul");
paginationList.className = "pagination";
for(var i = 1; i <= pageCount; i++){
var paginationNode = document.createElement("li");
var paginationLink = document.createElement("a");
paginationLink.innerHTML = i;
paginationLink.href = "#";
paginationLink.onclick = function(){ console.log("yay"); }; //removed loadProperties here
paginationNode.appendChild(paginationLink);
paginationList.appendChild(paginationNode);
}
divxml.innerHTML = "";
divxml.appendChild(paginationList);
//code replaced by this comment inserts a lot of content to divxml
//for this bug or something to work, you need next line
divxml.innerHTML += "<br>";
divxml.appendChild(paginationList);
As you can see, I'm doing pagination here. The problem is that first pagination buttons don't work, I can't see yay in console when I click on them, but the second and last ones do work (I see yay in console when I click on them). What's wrong, How do I fix that?
You will have to create two list elements and two sets of list item elements for this to work:
var pageCount = 5; //for example, doesn't really matter
var paginationList1 = document.createElement("ul");
var paginationList2 = document.createElement("ul");
paginationList1.className = paginationList2.className = "pagination";
for(var i = 1; i <= pageCount; i++){
paginationList1.appendChild(createPaginationLink(i));
paginationList2.appendChild(createPaginationLink(i));
}
document.body.appendChild(paginationList1);
document.body.appendChild(document.createElement("br"));
document.body.appendChild(paginationList2);
function createPaginationLink(text) {
var paginationNode = document.createElement("li");
var paginationLink = document.createElement("a");
paginationLink.innerText = text;
paginationLink.href = "#";
paginationLink.addEventListener("click", function(){ console.log("yay"); }); //removed loadProperties here
paginationNode.appendChild(paginationLink);
return paginationNode;
}
And as stated in the other answer, mutating innerHTML will cause your elements to be re-created without their event listeners, so instead create and append your <br/> element using createElement and appendChild.
Codepen
divxml.innerHTML += "<br>";
Reading from innerHTML converts the DOM into HTML. The HTML does not have the event handlers that were attached to the DOM.
Writing the HTML back to the innerHTML (after appending <br> to it) converts the HTML to DOM and overwrites the DOM that was there before.
You have now destroyed the event handlers.
Don't use innerHTML.
How do I change the HREF for an anchor tag that is inside an ordered list? More specifically, how do I change the HREF of the anchor tag in my specific case where the list is appended to the body?
Here is what I have tried so far:
var image = document.createElement("img");
image.src = "http://archiveteam.org/images/1/15/Apple-logo.jpg"
image.className = "image";
var aboutMe = document.createElement("p");
aboutMe.innerHTML = "Hello";
aboutMe.className = "Border";
var movies = ["Inception", "Remember the Titans", "Happy Gilmore", "Interstellar", "The Martian"]
var listOfMovies = document.createElement("ol");
for (var i = 0; i < 5; i++) {
var anchor = document.createElement("a");
anchor.href = "#";
anchor.innerHTML = movies[i];
var bullets = document.createElement("li");
bullets.appendChild(anchor);
listOfMovies.appendChild(bullets);
}
listOfMovies.getElementsByTagName("li")[0].href = 'http://www.imdb.com/title/tt1375666/';
listOfMovies.getElementsByTagName("li")[1].href = 'http://www.imdb.com/title/tt0210945/';
listOfMovies.getElementsByTagName("li")[2].href = 'http://www.imdb.com/title/tt0116483/';
listOfMovies.getElementsByTagName("li")[3].href = 'http://www.imdb.com/title/tt0816692/';
listOfMovies.getElementsByTagName("li")[4].href = 'http://www.imdb.com/title/tt3659388/';
document.body.appendChild(image);
document.body.appendChild(aboutMe);
document.body.appendChild(listOfMovies)
listOfMovies.className = "Border"
You are setting the li element's href attribute instead of the a (anchor) element. So your first line of code to change the href should be:
listOfMovies.getElementsByTagName("a")[0].href = 'http://www.imdb.com/title/tt1375666/';
You could also iterate through this list to have simpler code by adding the href's to an array in the same order as movies or even creating a movies object with Movie title and url like:
movies = [{ title: "Inception", url: "http://www.imdb.com/title/tt1375666/" },{...}...];
I am having an issue deleting or replacing a div with a either an empty div or a new veriosn of the div. I have tried to destroy the div with delete $targetname I've tried to replace the div with $("#divname").replace() and I seem to be missing some. I have the function tied to a button click that also clears a textarea and that part works fine but my form continues to show the divs that are getting appended but never removed. Below is the link to the fiddle for my code, any help is appreciated.
http://jsfiddle.net/fNfK8/
emWindow = window.open("", null, "height=400,width=800,status=yes,toolbar=no,menubar=no,location=no");
emWindow.document.title = "Emote Builder";
emWindow.document.body.style.background = "#00214D";
emWindow.document.body.style.color = "White";
// create a form and set properties
var emForm = document.createElement('form');
emForm.id = 'emForm';
// insert into the body of the new window
emWindow.document.body.appendChild(emForm);
// add text before the input
var emoteBuildL = document.createElement('emoteBuildL');
emForm.appendChild(document.createTextNode('Emote Build Window:'));
//add linebreak
var linebreak = document.createElement('br');
emForm.appendChild(linebreak);
// add a text input
var emoteBuild = document.createElement('textarea');
emoteBuild.type = 'text';
emoteBuild.name = 'emoteBuild';
emoteBuild.id = 'emoteBuild';
emoteBuild.rows = 6;
emoteBuild.cols = 80;
emoteBuild.value = '';
emForm.appendChild(emoteBuild);
var emoteTosend = document.getElementById('emoteBuild');
//add linebreak
var linebreak = document.createElement('br');
emForm.appendChild(linebreak);
var ePreview = document.createElement('button');
ePreview.type = 'button';
ePreview.innerHTML = 'Preview Emote';
ePreview.onclick = emoteFunc;
emForm.appendChild(ePreview);
var eSubmit = document.createElement('button');
eSubmit.type = 'button';
eSubmit.innerHTML = 'Send Emote';
eSubmit.onclick = function () {
client.send_direct("" + emoteBuild.value);
};
emForm.appendChild(eSubmit);
var eClear = document.createElement('button');
eClear.type = 'button';
eClear.innerHTML = 'Clear Emotes';
eClear.onclick = function () {
emoteBuild.value = '';
delete $emPreviews;
};
emForm.appendChild(eClear);
//add linebreak
var linebreak = document.createElement('br');
emForm.appendChild(linebreak);
// add text before the input
var emotePviewL = document.createElement('emotePviewL');
emForm.appendChild(document.createTextNode('Emote Previews:'));
//add linebreak
var linebreak = document.createElement('br');
emForm.appendChild(linebreak);
//add linebreak
var linebreak = document.createElement('br');
emForm.appendChild(linebreak);
function emoteFunc() {
var emPreview = emoteBuild.value;
emPreview = emPreview.replace(/%%(.+?)%%/g, "\<font color=\"red\"\>\"$1\"\</font\>");
emPreview = emPreview.replace(/%%/g, "\"");
emPreview = emPreview.replace(/\^/g, "");
emPreview = emPreview.replace(/(\w+_him)/g, "(him/her)");
emPreview = emPreview.replace(/(\w+_his)/g, "(his/her)");
emPreview = emPreview.replace(/(\w+_he)/g, "(he/she)");
emPreview = emPreview.replace(/#/g, "");
var div = document.createElement("div");
div.class = 'emPreviews';
div.id = 'emPreviews';
div.style.color = "black";
div.style.backgroundColor = "white";
div.innerHTML = emPreview;
emForm.appendChild(div);
emForm.appendChild(linebreak);
}
You will find it very much more efficient to put the HTML into a separate file and use that as the source for the new window. Alternatively, use document.write to add content to the page, e.g. the following replaces about 20 lines at the start of your script:
function openWin() {
var emWindow = window.open("", null, "height=400,width=800,status=yes");
emWindow.document.write(
'<!doctype html><title>Emote Builder<\/title>' +
'<style type="text/css">body{background-color: #00214D;color:White;}<\/style>' +
'<form id="emForm">' +
'Emote Build Window:<br>' +
'<textarea name="emoteBuild" id="emoteBuild" rows="6" cols="80"><\/textarea>'
);
emWindow.document.close();
}
Note that when you do:
var linebreak = document.createElement('br');
it creates an element in the current document, but then:
emForm.appendChild(linebreak);
appends it to an element in a different document. You really should do:
var linebreak = emWindow.document.createElement('br');
emForm.appendChild(linebreak);
Or just put it in the HTML above.
You are also creating a button in the opener window, appending it to the form, then having it call a function in the opener. The new window has a new global context, it doesn't have access to the opener's scope. You can do:
ePreview.onclick = window.opener.emoteFunc;
or similar but you might find that blocked in some browsers.
I'd suggest you re–write the function to firstly generate the HTML you want, then write it to a new window using emWindow.document.write. Don't forget to call emWindow.document.close at the end.
Edit
Remember that you are working across documents. So if you are still running the script in the opener (the original window), you have to preface any reference to methods in the child window with a reference to emWindow, e.g. to get a reference to the form in the child window you have to use:
function emoteFunc() {
// Get a reference to the form in the child window
var emPreview = emWindow.document.getElementById('emoteBuild');
...
// Create a div in the child window to append to it
var div = emWidnow.document.createElement('div');
...
// The form and div are in the same document, so just append
emForm.appendChild(div);
// Create a BR element in the child and append it
emForm.appendChild(emWindow.document.createElement('br'));
...
}
Edit 2
Here is a trivial example of sending data between a child and opener.
<script>
var win;
function newWin(){
win = window.open('','','');
win.document.write(
'<title>new window<\/title>' +
'<script>function getValue() {' +
'document.getElementById("i0").value = opener.document.forms.f0.i0.value;}<\/script>' +
'<input id="i0">' +
'<input type="button" onclick="getValue()" value="Get value from opener">' +
'<input type="button" onclick="opener.getValue()" value="Get value using function in opener">'
);
win.document.close();
};
function getValue() {
console.log('getValue called');
console.log(win.document.getElementById('i0').value);
win.document.getElementById('i0').value = document.f0.i0.value;
}
function sendValue(value) {
win.document.getElementById('i0').value = value;
}
</script>
<button onclick="newWin()">Open child</button>
<form id="f0">
<p>Value to get from child
<input name="i0" value="value in opener">
<input type="button" value="Send value" onclick="sendValue(this.form.i0.value)">
</form>
You will discover that (in IE at least) you can:
call a function in the child window to get a value from the opener
call a function in the opener to send a value to the child
call a function in one window from the other,
but you can't call a function in the other window that updates the current window, that's one too many hops.
So any function you want to call from the child should be in the child, and any function you want to call from the opener should be in the opener.
I have the following script
var counter = 0;
function appendText(){
var text = document.getElementById('usertext').value;
if ( document.getElementById('usertext').value ){
var div = document.createElement('div');
div.className = 'divex';
var li = document.createElement('li');
li.setAttribute('id', 'list');
div.appendChild(li);
var texty = document.createTextNode(text);
var bigdiv = document.getElementById('addedText');
var editbutton = document.createElement('BUTTON');
editbutton.setAttribute('id', 'button_click');
var buttontext = document.createTextNode('Edit');
editbutton.appendChild(buttontext);
bigdiv.appendChild(li).appendChild(texty);
bigdiv.appendChild(li).appendChild(editbutton);
document.getElementById('button_click').setAttribute('onClick', makeAreaEditable());
document.getElementById('usertext').value = "";
counter++;
}
};
var makeAreaEditable = function(){
alert('Hello world!');
};
I want the makeAreaeditable function to work when the Edit button is pressed(for each of the edit buttons that are appended under the textarea).. In this state, the script, alerts me when i hit the Addtext button.
the following is the html. P.S. i need this in pure javascript, if you can help. thanks
<textarea id="usertext"></textarea>
<button onClick="appendText()">Add text </button>
<div id="addedText" style="float:left">
</div>
instead of:
document.getElementById('button_click').setAttribute('onClick', makeAreaEditable());
you need to do this:
editbutton.onclick = makeAreaEditable;
the function's name goes without brackets unless you want to execute it
instead of obtaining the element from the DOM using document.getElementById('button_click')
you can use the editbutton variable already created. this object is the DOM element you are looking for
SIDE NOTE:
the standard way to do it is to add the onclick property before appending the element
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.