I have a function in a javascript file that adds a link to a paragraph that I created in the HTML file. I want to call a function that is defined in the javascript file when the user clicks the link.
My HTML:
<p id="para"></p>
My JavaScript:
var paraHTML = document.getElementById("para");
function addLink(id) {
paraHTML.innerHTML += '<a id="' + id + '" onclick="clickedTest(); return false;">Click me!</a>'
}
function clickedTest() {
console.log('here');
}
I have also tried using href e.g.
paraHTML.innerHTML += '<a id="' + id + '" href="javascricpt:clickedTest();">Click me!</a>'
But both ways give me an error saying: ReferenceError: clickedTest is not defined
I have tried using the following code from this question but the number of links is constantly changing whilst my code is running which makes it difficult to use:
var elements = document.getElementsByTagName('a');
for(var i = 0, len = elements.length; i < len; i++) {
elements[i].onclick = function () {
console.log('here')
}
}
The addLink() function is called elsewhere in my javascript program several times
Using innerHTML to create content is usually slow and is usually discouraged, a more organic approach will be to create the element pragmatically and then adding event listener to that element. For example,
var elem = document.createElement('a');
elem.addEventListener('click', myClickHandler);
elem.innerText = 'My Tag';
paraHTML.appendChild(elem)
function myClickHandler(e) {
console.log('a is clicked')
}
This will not only fix your problem but will make your code more manageable
You can do something like this:
function callMe(){
}
var newLink = document.createElement('a');
newLink.href="javascript:callMe();";
newLink.innerHTML="this is a link";
paraHTML.appendChild(newLink);
Related
I am building a Modal dynamically. I want to make some buttons in this modal to open a SubModal. The buttons show up in html, but clicking these buttons does nothing.
Here is my code.
const subtaskList = document.getElementById('subtaskList');
for (const subtaskIndex in task.subtasks) {
const subtaskButton = document.createElement('button');
subtaskButton.classList.add('taskModalSubtaskButton');
subtaskButton.onclick = () => {
openSubTaskModal(task.subtasks[subtaskIndex], task);
}
subtaskButton.innerText = task.subtasks[subtaskIndex].name;
subtaskList.appendChild(subtaskButton);
subtaskList.innerHTML += '<br>';
}
While troubleshooting I made an array to hold the buttons and used console.log() to see its elements. They all had the onclick function. I've clicked the buttons from the dev console by getting their class name and nothing, so I know it's not a display issue. I feel like I am misunderstanding something and any help would be appreciated.
The problem is subtaskList.innerHTML += '<br>'; it is good idea to use subtaskList.appendChild(document.createElement("br")); instead.
Here is working snippet:
function doSomething(url) {
alert(url);
}
const subtaskList = document.getElementById('subtaskList');
for (var i = 0; i < 3; i++) {
const subtaskButton = document.createElement('button');
subtaskButton.classList.add('taskModalSubtaskButton');
subtaskButton.innerText = "name" + i;
subtaskButton.onclick = (function (url) {
return function () {
doSomething(url);
};
})("URL #" + i)
subtaskList.appendChild(subtaskButton);
subtaskList.appendChild(document.createElement("br"));
}
<div id="subtaskList"></div>
Also I change a bit onclick function to send correspond index to doSomething function
I am trying to make a little idle click game, but have a problem with my startIdle function.
I can't pass the id to which input progressbar that is needed to start counting.
I have one input field and one button foreach id from a obj.
function addRow(id) {
var div = document.createElement('div');
div.className = 'row';
div.innerHTML =
'<div class="w3-blue" name="idle" id="'+id+'" style="height:24px;width:20%"></div>\
<button onclick="startIdle('+id+')">Click me</button>';
document.getElementById('content').appendChild(div);
}
function startIdle(id) {
_counter = 1;
_timer = setInterval(function(){
document.getElementById(id).style.width = (_counter + "%");
_counter++;
if(_counter > 100) clearInterval(_timer);
}, 100);
}
function createIdles(){
for (var key in money) {
// skip loop if the property is from prototype
if (!money.hasOwnProperty(key)) continue;
var obj = money[key].id;
addRow(obj)
}
}
createIdles()
this is the console.log I get:
Uncaught ReferenceError: startIdle is not defined at HTMLButtonElement.onclick
Your problem is that startIdle is defined inside a scope. Move it out of document.ready. Unless you can call the function from console, it isn't available globally.
Alternatively, building on Andy Hoffmans solution, bind onClick programmatically inside scope of document.ready, e.g.
document.querySelectorAll('button[data-id]')
.forEach(elm => elm.addEventListener('click',
() => startIdle(elm.dataset.id)))
You can probably improve that a bit using jquery.
I removed the onclick attribute and perform binding separately. The binding and element lookup are done inside of a setTimeout to ensure the elements are present in the DOM when that code runs.
// Note: I'm using a data-id attribute on the <button> so as to not
// duplicate the id on the <div class="w-3">
function addRow(id) {
var div = document.createElement('div');
div.className = 'row';
div.innerHTML =
'<div class="w3-blue" name="idle" id="' + id + '" style="height:24px;width:20%"></div>\
<button data-id="' + id + '">Click me</button>';
document.getElementById('content').appendChild(div);
}
function startIdle() {
// Remember the data-id attribute from above?
alert('clicked ' + this.getAttribute('data-id'));
}
for (var i = 0; i < 5; i++) {
addRow(i);
}
// Bind click events in separate event loop to ensure elements are present in DOM
setTimeout(function() {
var els = document.querySelectorAll("button[data-id]");
els.forEach(function(el) {
el.addEventListener("click", startIdle);
})
});
<div id="content"></div>
http://jsfiddle.net/4mr02ktu/2/
I want to take a click event from 2nd page . 1st page have a link for 2nd page, there have a button when click the button it add a HTML row on 1st page. I am trying to use localStorage for passing data. My code don't work, take a look below:
1st Page.html
HTML
<div id="content">
</div>
JS
var output = document.getElementById('content');
addEvent(window, 'storage', function (event) {
if (event.key == 'StorageName') {
output.innerHTML = event.newValue;
}
});
2nd Page.html
HTML
<input id="data" type="button" value="+" onclick="addRow()">
JS
addEvent(dataInput, 'keyup', function () {
localStorage.setItem('StorageName', this.value);
});
var dataInput = dataInput = document.getElementById('data');
object.onclick = function(){
addRow() {
var div = document.createElement('div');
div.className = 'row';
div.innerHTML = '<button>GO</button>';
document.getElementById('content').appendChild(div);
}
};
You haven't defined your addRow() function properly. A function's name is defined with the keyword function, not inside of the function body. Your code:
object.onclick = function(){
addRow() {
var div = document.createElement('div');
div.className = 'row';
div.innerHTML = '<button>GO</button>';
document.getElementById('content').appendChild(div);
}
};
Should be changed to:
function addRow() {
var div = document.createElement('div');
div.className = 'row';
div.innerHTML = '<button>GO</button>';
document.getElementById('content').appendChild(div);
}
object.onclick = addRow;
I agree with skyline3000's answer the addRow() should be defined. Also there are a few other things that could/should change:
define dataInput before attaching an event to it
object.onclick should be dataInput.onclick since thats the element being clicked. (is click event what you really want? maybe onkeyup?)
when you set the localStorage you want to set the function definition being passed to Page 1 which appears to be addRow(). Simply remove the parenthesis to pass just the definition.(Should also be defined before using)
If you want to just pass the function you shouldn't set the onclick event on Page 2. What you should probably do is record how many times you want it to run when you go to Page 1.
You dont need to pass the function everytime if it isnt changing; Just set it once and record the number of times it was clicked.
page 1 can catch the load event and the check localStorage for the function definition and number of times it was run. Then it can loop and perform the function.
the code you have doesn't add a link back to page 2 if thats what you are looking for but you can add that into the addrow function when you know the file name and path.
Page 1
var output = document.getElementById('content');
addEvent(window, 'load', function (event) {
if (localStorage.getItem('StorageName') && localStorage.getItem('rowsToAdd')) {
for(var i = 0; i > rowsToAdd;i++){
var addNewRow = localStorage.getItem('StorageName');
addNewRow();
}
}
});
Page 2
var dataInput = document.getElementById('data');
function addRow() {
var div = document.createElement('div');
div.className = 'row';
div.innerHTML = '<button>GO</button>';
document.getElementById('content').appendChild(div);
};
localStorage.setItem('StorageName', addRow);
dataInput.onclick = function() {
if(localStorage.getItem('rowsToAdd')){
localStorage.setItem('rowsToAdd', localStorage.getItem('rowsToAdd') + 1);
}else{
localStorage.setItem('rowsToAdd',1);
}
}
I didn't test this code so it may not work copy+pasted but something pretty close hopefully.
I also answered this with the best understanding of what you wanted that I could manage but I dont fully see the desired result of what you seemed to be doing.
I have a function from icomoon that runs when the window loads (see below).
I would like to change it so that the function gets called once when the document loads, and then if there are any subsequent changes to the body - eg: from js/ajax (and preferably then only on the changed part of the dom, so as not to loop through the entire document again and again). Any suggestions on what jquery on events I should use for this, and then to only check the changes once the first execution on the entire document has been completed? Needs to be Ie7+ compatible too.
Thanks much.
$( window ).load(function() {
function addIcon(el, entity) {
$(el).addClass("iconed");
var html = el.innerHTML;
el.innerHTML = '<span style="font-family: \'icomoon\'">' + entity + '</span>' + html;
}
var icons = {
.....
};
function iconify() {
var els = document.getElementsByTagName('*'),
i, attr, c, el;
for (i = 0; ; i += 1) {
el = els[i];
if(!el) {
break;
}
attr = el.getAttribute('data-icon');
if (attr) {
if (!$(el).hasClass("iconed")) {
addIcon(el, attr);
}
}
c = el.className;
c = c.match(/icon-[^\s'"]+/);
if (c && icons[c[0]]) {
if (!$(el).hasClass("iconed")) {
addIcon(el, icons[c[0]]);
}
}
}
}
iconify();
$('body').on("contentchanged", function() { //some event that triggers ONCE the document has fully loaded, and is triggered when the DOM changes..
iconify(); //would prefer if this function only checked the modified part of the DOM - rather than the entire DOM each time (except on the 1st execution - when window loaded.
});
});
You can fire custom events when the content of body is changed by ajax or any other function which you are aware of . And then bind a custom function to that event.
Let's say in
function addIcon(el, entity) {
$(el).addClass("iconed");
var html = el.innerHTML;
el.innerHTML = '<span style="font-family: \'icomoon\'">' + entity + '</span>' + html;
$(document).trigger('contentchanged');
}
And then you can write a custom function handling this event like:
$(document).on('contentchange','selector',function(){
//Your code goes here.
});
You can also refer for DOM mutation events
I have a web site that gets links generated dynamically. I would like to see if I can add an onclick event handler to track external links. I am looking to see links that has target="new" ( which means external to our site) and add the event handler
html code
<a target="new" href="http://twitter.com/cnn">CNN</a>
The code I tried to test is not working. Let me know what is wrong in my code or should I some home append the onclick event to the external links?
Js code
var links = document.getElementsByTagName("a");
for (var i=0; <links.length; i++) {
if(links[i].target == 'new'){
links[i].onclick = function() {
alert("Added onClick: " + links[i].href);
}
}
}
Another answer here is what you should go with (using this) but it's worth addressing the issue of closures in for loops.
If you want to use a variable that changes for each iteration in a for loop in a closure that's created in that for loop, define and call an anonymous function that returns a function to be bound (binded?) to the onclick event.
var links = document.getElementsByTagName("a");
for (var i=0; i<links.length; i++) {
if(links[i].target == 'new'){
links[i].onclick =
function (obj) {
return function(event) {
alert("Added onClick: " + obj.href);
}
}(links[i]);
}
}
Since the parameter (obj) to the anonymous function is passed by value it won't change in subsequent iterations for the for loop. The returned function will have its own copy of the object.
A lot of stuff in Javascript starts making sense when you think of functions as objects that can be passed around.
You can use this in your onclick function and avoid the closure issue
var links = document.getElementsByTagName("a");
for (var i=0; i<links.length; i++) {
if(links[i].target == 'new'){
links[i].onclick = function(){
alert("Added onClick: " + this.href);
}
}
}
are you adverse to jQuery?
$("a[target='new']").click(function(){alert($(this).attr("href"));});