onchange event handler failing to call function - javascript

I have a function that uses:
name = "textBox" + (h) + (j);
id = "textBox" + (h) + (j);
value = hoursEachDay[j-1];
textBox = "<input type='text' maxlength='6' size='6' name='" + name + "'id='"+ id +"' value='" + value + "' onchange='updateHrs()'>";//or parent.updateHrs(j)
(h, i,and j being integers) to call another function that follows directly after the first function. That function is :
function updateHrs()// or updateHrs(dayOfMonth)
{
alert("This is the day changed ");
//or alert("This is the day changed " + dayOfMonth);
return;
}
I get a 'function not defined' error from firebug when I run this and trigger the onchange event handler. I have, on the suggestion of a coworker, changed updateHrs() to parent.updateHrs(), which actually works for some reason, until I try to pass a variable into the updateHrs() function (ass seen commented out above), at which point it declares that updateHrs(j) is not defined.
I am guessing that somehow the updateHrs function is being read as out of scope, although I'm not really sure how. Both of these functions are right after one another and both are right before the tag (yes there is a tag well above them as well), so they should not have a scope issue, not that I'm aware of anyway.
Thanks for any help that you can provide.

Related

Enable/Disable an HTML Element With Dynamically Generated Names/Tags

I have a table in HTML where the ID is dynamically generated from a row counter:
$(table).find('tbody').append("<tr>name=\"tableRow\"</tr>"
+ "<td>"
+ "<select id=\"shapeSelect_" + rowCount + "></td>"
+ "<option onclick=\"sphereSelect()\" value=\"sphere\">Sphere</option>"
+ "<option onclick=\"cylinderSelect()\" value=\"cylinder\">Cylinder</option>"
+ "</select>"
+ "</td>"
+ "<td><input type=\"text\" id=\"altitude" + rowCount + "\"</td>"
+ "<td><input type=\"text\" name=\"maxAlt\" id=\"maxAltitude_" + rowCount + "></td>"
+ "</tr>"
I need maxAltitude to become disabled for input when sphere is selected. When cylinder is selected, it should become enabled for input.
Every example I find is pretty simple but requires knowing exactly what the ID is, where in my code it is dynamically generated. This is an example of what I'm finding:
$(#maxAltitude).prop("disabled", true);
How can I do this when maxAltitude will be something more like: maxAltitude_10? There may be 1-n rows in a table, and I need to specifically disable the max altitude in the row where the dropdown select was changed.
I've tried jQuery and javascript but can't seem to find a good way to do this:
<option onclick="shapeSelect()" value="sphere">Sphere</option>
<option onclick="shapeSelect()" value="cylinder">Cylinder</option>
function shapeSelect() {
var shapeSelects = document.getElementsByName("shapeSelect");
var maxAlts = document.getElementsByName("maxAlt");
for(var i = 0; i < shapeSelects.length; i++) {
switch(shapeSelects[i].value) {
case "sphere":
maxAlts[I].disabled = True;
break;
case "cylinder":
maxAlts[i].disabled = False;
}
}
}
With the above code I get: SyntaxError: unexpected token: identifier whenever shapeSelect() is fired.
I've modified the code as follows:
<table class="myTable" id="myTable"></table>
$(table).find('tbody').append("<tr>name=\"tableRow\"</tr>"
+ "<td>"
+ "<select id=\"shapeSelect_" + rowCount + "></td>"
+ "<option value=\"sphere\">Sphere</option>"
+ "<option value=\"cylinder\">Cylinder</option>"
+ "</select>"
+ "</td>"
+ "<td><input type=\"text\" id=\"altitude_" + rowCount + "\"</td>"
+ "<td><input class=\"maxAltitudeInput\" type=\"text\" id=\"maxAltitude_" + rowCount + "\" disabled></td>"
+ "</tr>"
$('#myTable').on('change','.shapeSelector',function(){
var shouldDisableInput = $(this).val() === 'sphere';
$(this).closest('tr').find('.maxAltitudeInput').attr('disabled',shouldDisableInput);
}
And still nothing happens when I change the shape selector dropdown.
EDIT:
Apologies on the naming mismatches. My dev machine is on an airgapped network and I was hand jamming the post here on Stack Overflow. The rowCount variable was being created and incremented in another function. I was trying to only put relevant code in the post for brevity.
I was missing a class from shapeSelector. That was the missing link. It works now!
jQuery actually makes this really easy by binding this to whichever element triggered an event.
For instance, instead of writing a generic function for when that value changes, you could use jQuery to bind an event listener to them:
$('#myTable').on('change','.shapeSelector',function(){
var shouldDisableInput = $(this).val() === 'sphere';
$(this).closest('tr').find('.maxAltitudeInput').attr('disabled',shouldDisableInput);
}
You'll notice a few things in this snippet:
The element we are binding the listener to is the table, not the individual row. That's because the row is dynamic, and we don't want to have to keep adding listeners every time we add a row. Instead we add it to the parent which is stable, but then we specify that we are interested in its children that match ".shapeSelector"
The listener relies on class names, not IDs, since we want to match multiple copies of them, not just a specific one. So you'd need to add those class names or a similar way of matching more than one item
Inside the callback function that runs, you'll notice a couple uses of this. jQuery has bound that to the element that triggered the event listener, in this case, the <select> control. So when we use this, we have to think of it from that perspective. We can get its value by $(this).val(), we can find its parentt with $(this).parent(), etc. In this case, I'm travelling up to the nearest tr, then from there down to that tr's input that I want to disable. You'd need to adjust a little depending on your dom.
Also note that this is a DOM element, not a jQuery result. That's why when we want to run more jQuery commands on it, we have to put it in $() again.
That's how I'd approach it. We don't have your entire code here, so you'll have to adjust a bit, but hopefully that pushes you off in the right direction.
EDIT
To be honest, there were a lot of naming mismatches and things that didn't line up. For instance, you were attempting to append onto a tbody tag, but that tag didn't exist. You were using a rowCount variable, but didn' ever set that up or increment it. The select tag sill didn't have the class name you were trying to use.
I suggest you look at your code piece by piece, ask yourself what you're telling the browser to do, and then do that instruction in your mind to make sure the computer can do it.
HTML:
<table class="myTable" id="myTable"><tbody></tbody></table>
JavaScript:
var rowCount = 0;
function addRow(){
$('.myTable tbody').append(`<tr name="tableRow">
<td>
<select class="shapeSelector" id="shapeSelect_${rowCount}">
<option value="sphere">Sphere</option>
<option value="cylinder">Cylinder</option>
</select>
</td>
<td><input type="text" id="altitude_${rowCount}" /></td>
<td><input class="maxAltitudeInput" type="text" id="maxAltitude_${rowCount}" disabled></td>"
</tr>`);
rowCount++;
}
$('.myTable').on('change','.shapeSelector',function(){
var shouldDisableInput = $(this).val() === 'sphere';
$(this).closest('tr').find('.maxAltitudeInput').attr('disabled',shouldDisableInput);
});
addRow();
addRow();
addRow();
https://jsfiddle.net/32vnjq81/

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>`;

Getting values outside a HTML form

Inside my content.js I am writting a new HTML page with a pre polulated form, which contains var a and var b. Those 2 variables are created before, inside content.js, so I can easily use them inside my HTML page. Now I want to override those variables a and b as the user finishes editing the form and presses the button Accept. Is there anyway I can achieve this?
This is a part of the code
var a="FName";
var b="LName";
var myWindow = window.open("Accept", "myWindow", "width=450, height=300");
myWindow.document.write(
"<html>"+
"<head>"+
'<script> function closeWindow(){ var x = document.getElementById("firstname").value alert(x); window.close();}'+
"</script>"+
"</head>"+
"<body>"+
"<form>"+
"<div id=leadinformation>"+
"<p id=titleParagraph>You are about to create a new Lead:</p>"+
"First Name....."+ "<input type=text id=firstname value="+a+">" +"<br>"+
"Last Name....."+ "<input type=text id=lastname value="+b+">" +
"</div>"+
"<div>"+
"<button id=Accept onClick=closeWindow() >Accept</button>"+
"<button id=Close onClick=closeWindow() >Close</button>"+
"</div>"+
"</form>"+
"</body>"+
"<html>"
);
myWindow.document.getElementById('Accept').onclick=Accept;
myWindow.document.getElementById('Close').onclick=Close;
function Accept(){
alert(myWindow.document.getElementById('firstname').innerText);
}
function Close() {//do smthing
}
Sorry for bad formating.
Currently the output of the Accept(); is empty at the moment. How can I get first name input result?
What I want to achieve:
1) I am creating a button on a page
2) When I click on the button a new html page pops out (the one that I am hardcode writing it)
3) I pre populate the form with some variables that I created before
4) When Clicking The Accept button on the form the Accept() function is triggered where I would want to use those input values the user has written.
This should help you: Sharing global javascript variable of a page (...).
The question is about "How to share a variable to another page in an iframe", but this works for a new windows as well.
i.e.:
myWindow.document.write(
"<html>" +
"<head>" +
'<script>' +
'function closeWindow(){' +
'var x = document.getElementById("firstname").value;' +
'alert(x);' +
'// do something to parent.a and parent.b here, just because you can:' +
'parent.a = "Oh, would you look at it, it works!";' +
'parent.b = "And it is so pretty too!";' +
'window.close();' +
'}' +
"</script>" +
"</head>" +
" Your body code here, etc " +
"</html>"
);
Also, please note that your code lacks a semicolon (;) after inserting value to var x in your new window's JavaScript code. That will most probably make your code malfunction. The closing </html> tag lacks the slash, but I don't know if that's gonna break anything; you'd better fix that as well, just in case.

variable in onclick function of dynamically created button

Hy,
Basically, I have a number of dynamically generated list items with a button in them. When I prepend the list item to the ul list, I have access to a variable that I want to pass when I click the button in the list items. But when I add the variable in the line of code shown below, it gives me a Uncaught ReferenceError: challenger is not defined error. How can I pass these variable along?
JAVASCRIPT:
window.GLOBAL_socket.on('challenged', function(data) {
console.log("You have been challenged by the player " + data.challenger);
var challenged = getUrlVars()['user'];
var challenger = data.challenger;
$("#challengesList").prepend("<li><div id='newChallenge'><p id='challenge_header'>You have been challenged by: </p><p id='challenge_challenger'>" + data.challenger +
"</p><input type='button' value='ACCEPT' id='challenge_accept' onclick='acceptChallenge(challenger)'></input><input type='button' value='DECLINE' " +
"id='challenge_decline' onclick='declineChallenge(this)'></div></li>");
});
The onclick method is found on line 6.
Thanks for your responses,
Zeno
The reason why challenger is not defined is because it's a local variable and is not accessible globally when you actually trigger the function with a click.
So instead of using the variable, just place it's actual value in the onclick.
Change your code to:
$("#challengesList").prepend("<li><div id='newChallenge'><p id='challenge_header'>You have been challenged by: </p><p id='challenge_challenger'>" + data.challenger +
"</p><input type='button' value='ACCEPT' id='challenge_accept' onclick='acceptChallenge(\""+challenger+"\")'></input><input type='button' value='DECLINE' " +
"id='challenge_decline' onclick='declineChallenge(this)'></div></li>");
Change your code as I mentioned in comments.
var challenged = [];
var challenger = [];
var counter = 0;
window.GLOBAL_socket.on('challenged', function(data) {
console.log("You have been challenged by the player " + data.challenger);
counter++;
challenged[counter] = getUrlVars()['user'];
challenger[counter] = data.challenger;
$("#challengesList").prepend("<li><div id='newChallenge'><p id='challenge_header'>You have been challenged by: </p><p id='challenge_challenger'>"
+ data.challenger
+ "</p><input type='button' value='ACCEPT' id='challenge_accept'"
// change of code --> passing value directly into the function
+ " onclick='acceptChallenge(challenger["+counter+"]
+")'></input><input type='button' value='DECLINE' "
+ "id='challenge_decline' onclick='declineChallenge(this)'></div></li>");
});
I just modified code, hope it works for you. Let me know

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