JavaScript: variable name unresolved - javascript

I wrote the following JS code:
function downloadFile(dataItem) {
....
}
....
for (var r = 0; r < dataItems.length ; r++) {
table += '<tr>';
var listOfAttributes = ['CarModel', 'BusMapping', 'Date_', 'Location_', 'Comments', 'AttackTraffic', 'IsTagged']
**table +='<td> <a onclick="downloadFile(dataItems[r])" href="#">' + dataItems[r]['FileName']['S'] +'</a></td>';**
for (var c = 0; c < Object.keys(dataItems[0]).length-1 ; c++) {
table +='<td>' + dataItems[r][listOfAttributes[c]]["S"] +'</td>';
}
table+= '</tr>'
}
I get an error for the line:
table +='<td> <a onclick="downloadFile(dataItems[r])" href="#">' + dataItems[r]['FileName']['S'] +'</a></td>';
It seems that JS can't resolve the variable 'dataItems' inside the -tag:
<a onclick="downloadFile(dataItems[r])" href="#">.
However, later in the same line, JS resolves successfully the same name for the part:
+ dataItems[r]['FileName']['S'] +
What do you think can be the problem? How can I make dataItems be resolved inside the -tag ?

Your variable is inside a string. Try changing the code to:
table +='<td> <a onclick="' + downloadFile(dataItems[r]) + '" href="#">' + dataItems[r]['FileName']['S'] +'</a></td>';**

As you're placing a string inside the element's attribute it is not recognized as a JavaScript code or a JavaScript function so place the JavaScript function itself.
So you can do, var anchor = '';
A sample example illustrating the problem, in this example if you write the function name as a string in the onclick property the function won't be called.
var container = document.getElementById('container');
var element = document.createElement('a');
element.href = '#';
element.text = 'Fire!';
element.onclick = fire; // this invokes the fire function
// element.onclick = 'fire'; // this won't invoke the fire function
container.appendChild(element);
function fire() {
console.log('fired');
}
<div id="container">
</div>

In this line
<a onclick="downloadFile(dataItems[r])" href="#">
unless dataItems is a global variable, it won't be available to the environment which will make this call downloadFile(dataItems[r]), since onclick event will be invoked in a global scope.
You need to bind the event less intrusively this way
//you need to update the selector as per your markup
document.querySelector ( "tr td a" ).addEventListener( "click", function(){
downloadFile(dataItems[r]);
})

Related

Call javascript function through dynamically generated href tag (the js function has one paramter)

I need to call getStandards() function from the dynamically generated href tag.All the code is in .js file. I went through many stackoverflow questions but I couldn't find the solution. The function has one parameter(classId) as shown below:
var ul = $('<ul></ul>');
var li = $('<li></li>');
for (var i = 0; i < classes.length; i++) {
var classId = classes[i].classId;
var html = "";
html = "<li><a href='#' id='" + classId + "' onClick='getStandards(" +
classId + ")' >" + classes[i].className + "</a></li><br/>";
li.append(html);
}
ul.append(li);
function getStandards(classId) {
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Can someone help me !! thank you.
Rather than making multiple inline bindings, I would suggest using a data attribute and a delegate event binding for this logic.
var ul = $('<ul></ul>');
ul.append(
classes.map( aClass => {
return `
<li>
<a href="#" class="class-entry"
data-class-id="${aClass.classId}">
${aClass.className}
</a>
</li>
`;
} )
);
ul.on( 'click', '.class-entry', event => {
let $link = $( event.target );
getStandards( $link.data( 'classId' ) );
} );
function getStandards(classId) {
}
You can use a template literal to make your html construction more readable
Mapping all the classes to html and appending them all and once, reduces the number of appends to the ul you are doing
Attaching a delegate event listener to the ul lets you handle the click for all the children of it, and you can grab the class id from the data attribute
I would hazard a guess that you aren't appending your ul to the body and that the classId is a string. With a few modifications this code can work:
<head>
<script src="https://code.jquery.com/jquery-3.4.1.slim.min.js"> .
</script>
</head>
<body>
<script>
// This code is copyright by nobody and may be used freely without attribution
var ul = $('<ul></ul>');
var li = $('<li></li>');
const classes = [
{ classId: 'id1', className: 'name1'}
];
for (var i = 0; i < classes.length; i++) {
var classId = classes[i].classId;
var html = "";
html = "<li><a href='#' id='" + classId + "' onClick='getStandards(\"" +
classId + "\")' >" + classes[i].className + "</a></li><br/>";
li.append(html);
}
ul.append(li);
$('body').append(ul);
function getStandards(classId) {
alert('get standards! ' + classId);
}
</script>
</body>
Note the appending to the body as well as the extra quotes by the onclick. If you don't have those quotes, it will look like this: onclick="getStandards(id1)" which is invalid since id1 is a string

Anonymous function in dynamically generated list producing SyntaxError

I want to place an onclick event inside a dynamically generated list. I can't use it as it is, like updateRoomID(arg), because it would fire immediately. So I placed it inside an anonymous function, as advised by various sources online: function (){updateRoomID(arg)}. But this results in: "Uncaught SyntaxError: Unexpected token (". Developer tools says the problem is at function().
The section of code it's in:
socket.onmessage = function(event) {
var msg = JSON.parse(event.data);
for (let i = 0; i < msg.length; i++) {
if (msg[i].beingserved == false) {
listRooms.innerHTML += '<li id=' + msg[i].roomid +
// Problem on following line.
' onclick=' + function () { updateRoomID(msg[i].roomid) } +
'>' +
'<a href="#">' +
msg[i].roomid +
'</a></li>';
} else {
document.getElementById(msg[i].roomid).remove();
};
};
};
I've tried it with the function as a string inside quotations marks: <li id=' + msg[i].roomid +' onclick="function(){updateRoomID(msg[i].roomid)}">'. I've tried placing the onclick handler in href link instead, and also replaced it with addEventListener. But I got the same error with these attempts.
If I try function(){updateRoomID(arg)}() with the parentheses behind, it fires immediately as expected.
I've been looking through it all day and can't figure out where the syntax error is. I'm quite unfamiliar with JavaScript. What am I doing wrong?
You can't put a function in the onclick attribute. It contains JavaScript source code that should be executed.
What you should do in this case is put the function call as a string, but substitute in the value of the argument.
Using a template literal makes this easier.
listRooms.innerHTML += `
<li id="${msg[i].roomid}" onclick="updateRoomId(${msg[i].roomid})">
${msg[i].roomid}
</li>`;

__doPostBack trigger on html render from javascript(before real click)

I'm trying to create some new buttons from js like:
var nextYearList ="";
...
nextYearList += "<button type='button' customparam='" + newCatalogList[l].code + "|" + newBaseName + "' ><span class='catName'>" + newCatalogList[l].name + "</span><span class='catYears'>" + newCatalogList[l].startDate + " - " + newCatalogList[l].endDate + "</span></button>";
...
ok('#YearNavigation .panelNextYear')[0].innerHTML = nextYearList;
var xListYears = ok('.panelNextYear button[customparam]');
for (var f = 0; f < xListYears.length; f++)
{
xListYears[f].addEventListener('click', changeCatalogPostback(xListYears[f].getAttribute('customparam'),true));
}
Where ok is my document.querySelectorAll wrapper;
ok = function (model)
{
return document.querySelectorAll(model);
};
changeCatalogPostback= function (parameter,checker)
{
if(checker)
__doPostBack('changeCatalog',parameter);
};
The main problem is that my __doPostBack is triggered on html rendering... so bye bye current page...
So how can I avoid a __doPostBack trigger on html render from javascript? I really need it to be there but working on click and not on render...
When you are adding an event listener you are actually calling the function which returns undefined and makes a postback. So if you will remove a __doPostBack call from changeCatalogPostback function the line with addEventListener call would evaluate to the end and will be equal to:
xListYears[f].addEventListener('click', undefined);
Instead addEventListener should accept a function as a second parameter. Use a bind call:
xListYears[f].addEventListener(
'click',
changeCatalogPostback.bind(this, xListYears[f].getAttribute('customparam'), true));

Issue while passing a value from a link to a JS file

I have the table data which is displyaed like below, where Dispute Number has a link.
I have generated the html code using the function below
getMessage(result){
for (var j = 0; j < result.invocationResult.resultSet.length; j++) {
var tmp = "<tr>";
var resSet = result.invocationResult.resultSet[j];
for(res in resSet){
if(res=="DISP_NUMBER")
var ab = resSet.DISP_NUMBER;
tmp += "<td><a href="+"#"+" data-role="+" button"+" id="+" button-mainpage" +" onclick="+ " changeToSomePage("+ab+");>"+ab +"</a></td>";
$("#mytable").append(tmp+"</tr>");
When the user clicks on the dispute number link, the below js function gets called.
I am passing the dispute number with the variable 'ab'. When i alert this value in the function changeToSomePage(ab),
it works sometimes, sometimes it giving incorrect number.
function changeToSomePage(ab) {
alert(ab);
$('#pagePort').load("pages/disputedetails.html");
}
Do you see anything wrong with the above code ? Is this the right apporach to retrieve the value from a link & send it to a JS function when clicked ??
Thanks..Johnson
It looks like ab is a string. You need to wrap it with quotes.
"<td><a href="+"#"+" data-role="+" button"+" id="+" button-mainpage" +" onclick="+ " changeToSomePage(\""+ab+"\");>"+ab +"</a></td>";
Of course inline handlers are not the best way. You can use event delegation instead: bind single onclick handler on the table itself.
$('#mytable').on('click', '.change-to-some-page', function() {
var num = $(this).data('num');
});
And when generating rows.
tmp += '<td><a href="#" data-role="button" class="change-to-some-page" ' +
'data-num="' + ab + '">' +ab +'</a></td>';
rewrite this
"<td><a href="+"#"+" data-role="+" button"+" id="+" button-mainpage" +" onclick="+ " changeToSomePage("+ab+");>"+ab +"</a></td>"
using double and single quotes - much easier to read. and create unique ids ith the j value
"<td><a href='#' data-role='button' id='button-mainpage-" + j + "' onclick=' changeToSomePage("+ab+");'>"+ab +"</a></td>"

Uncaught ReferenceError: function is not defined with onclick

I'm trying to make a userscript for a website to add custom emotes. However, I've been getting a lot of errors.
Here is the function:
function saveEmotes() {
removeLineBreaks();
EmoteNameLines = EmoteName.value.split("\n");
EmoteURLLines = EmoteURL.value.split("\n");
EmoteUsageLines = EmoteUsage.value.split("\n");
if (EmoteNameLines.length == EmoteURLLines.length && EmoteURLLines.length == EmoteUsageLines.length) {
for (i = 0; i < EmoteURLLines.length; i++) {
if (checkIMG(EmoteURLLines[i])) {
localStorage.setItem("nameEmotes", JSON.stringify(EmoteNameLines));
localStorage.setItem("urlEmotes", JSON.stringify(EmoteURLLines));
localStorage.setItem("usageEmotes", JSON.stringify(EmoteUsageLines));
if (i == 0) {
console.log(resetSlot());
}
emoteTab[2].innerHTML += '<span style="cursor:pointer;" onclick="appendEmote(\'' + EmoteUsageLines[i] + '\')"><img src="' + EmoteURLLines[i] + '" /></span>';
} else {
alert("The maximum emote(" + EmoteNameLines[i] + ") size is (36x36)");
}
}
} else {
alert("You have an unbalanced amount of emote parameters.");
}
}
The span tag's onclick calls this function:
function appendEmote(em) {
shoutdata.value += em;
}
Every time I click a button that has an onclick attribute, I get this error:
Uncaught ReferenceError: function is not defined.
Update
I tried using:
emoteTab[2].innerHTML += '<span style="cursor:pointer;" id="'+ EmoteNameLines[i] +'"><img src="' + EmoteURLLines[i] + '" /></span>';
document.getElementById(EmoteNameLines[i]).addEventListener("click", appendEmote(EmoteUsageLines[i]), false);
But I got an undefined error.
Here is the script.
I tried doing this to test if listeners work and they don't for me:
emoteTab[2].innerHTML = '<td class="trow1" width="12%" align="center"><a id="togglemenu" style="cursor: pointer;">Custom Icons</a></br><a style="cursor: pointer;" id="smilies" onclick=\'window.open("misc.php?action=smilies&popup=true&editor=clickableEditor","Smilies","scrollbars=yes, menubar=no,width=460,height=360,toolbar=no");\' original-title="">Smilies</a><br><a style="cursor: pointer;" onclick=\'window.open("shoutbox.php","Shoutbox","scrollbars=yes, menubar=no,width=825,height=449,toolbar=no");\' original-title="">Popup</a></td></br>';
document.getElementById("togglemenu").addEventListener("click", changedisplay,false);
Never use .onclick(), or similar attributes from a userscript! (It's also poor practice in a regular web page).
The reason is that userscripts operate in a sandbox ("isolated world"), and onclick operates in the target-page scope and cannot see any functions your script creates.
Always use addEventListener()Doc (or an equivalent library function, like jQuery .on()).
So instead of code like:
something.outerHTML += '<input onclick="resetEmotes()" id="btnsave" ...>'
You would use:
something.outerHTML += '<input id="btnsave" ...>'
document.getElementById ("btnsave").addEventListener ("click", resetEmotes, false);
For the loop, you can't pass data to an event listener like that See the doc. Plus every time you change innerHTML like that, you destroy the previous event listeners!
Without refactoring your code much, you can pass data with data attributes. So use code like this:
for (i = 0; i < EmoteURLLines.length; i++) {
if (checkIMG (EmoteURLLines[i])) {
localStorage.setItem ("nameEmotes", JSON.stringify (EmoteNameLines));
localStorage.setItem ("urlEmotes", JSON.stringify (EmoteURLLines));
localStorage.setItem ("usageEmotes", JSON.stringify (EmoteUsageLines));
if (i == 0) {
console.log (resetSlot ());
}
emoteTab[2].innerHTML += '<span style="cursor:pointer;" id="'
+ EmoteNameLines[i]
+ '" data-usage="' + EmoteUsageLines[i] + '">'
+ '<img src="' + EmoteURLLines[i] + '" /></span>'
;
} else {
alert ("The maximum emote (" + EmoteNameLines[i] + ") size is (36x36)");
}
}
//-- Only add events when innerHTML overwrites are done.
var targetSpans = emoteTab[2].querySelectorAll ("span[data-usage]");
for (var J in targetSpans) {
targetSpans[J].addEventListener ("click", appendEmote, false);
}
Where appendEmote is like:
function appendEmote (zEvent) {
//-- this and the parameter are special in event handlers. see the linked doc.
var emoteUsage = this.getAttribute ("data-usage");
shoutdata.value += emoteUsage;
}
WARNINGS:
Your code reuses the same id for several elements. Don't do this, it's invalid. A given ID should occur only once per page.
Every time you use .outerHTML or .innerHTML, you trash any event handlers on the affected nodes. If you use this method beware of that fact.
Make sure you are using Javascript module or not?!
if using js6 modules your html events attributes won't work.
in that case you must bring your function from global scope to module scope. Just add this to your javascript file:
window.functionName= functionName;
example:
<h1 onClick="functionName">some thing</h1>
I think you put the function in the $(document).ready.......
The functions are always provided out the $(document).ready.......
I got this resolved in angular with (click) = "someFuncionName()" in the .html file for the specific component.
Check the casing of your functions.
onclick="sillyLongFunctionName"
and
function sillylongFunctionName() { ...
Are not identical. Hard to spot sometimes!
If the function is not defined when using that function in html, such as onclick = ‘function () ', it means function is in a callback, in my case is 'DOMContentLoaded'.
See that your function is not in a callback function if you are using an external js file.
Removing the callback function would do the trick
(function() { //comment this out
//your code
})(); //comment this out

Categories