I am programming a web frontend for a database application. I have several function calls in the html body, like:
<input type=button value="Set 1" id="btn1" onClick=edit_entry(this,"edit","title")>
<input type=button value="Set 2" id="btn2" onClick=edit_entry(this,"edit","name")>
<input type=button value="Set 3" id="btn3" onClick=edit_entry(this,"edit","gender")>
function edit_entry(src, action, arg1) {
alert(src.onclick);
src.onclick = function () { edit_entry( src, action, arg1 };
alert(src.onclick);
}
When clicked on "btn1", the first alert returns the hardcoded function definition: function onclick(event) { edit_entry(this,"edit","title") }
But the second alert returns the function definition with variables function onclick(event) { edit_entry(src, action, arg1) }
So when these variables change later the function does get the wrong values. How can I apply the content of the variables to the function definition instead of the variables itself so that the definition is again function onclick(event) { edit_entry(this,"edit","title") } ?
P.S.: I know that this code snippet makes no sense as it shall only describe my problem as simple as possible.
Here is my code I was referring to. I hope this all makes more sense now. Sorry for the inconvenience.
HTML Body:
<input type="button" value="Edit" id="group_1_button_edit" class="action_element" onClick=edit_entries(this,"edit","artnr","artalt","bez1","bez2","bez3")>
<input type="button" value="Edit" id="group_9_button_edit" class="action_element" onClick=edit_entries(this,"edit","dok1","dok2","dok3","dok4","dok5")>
The values behind "edit" are the IDs of the input textboxes the content will be read from.
function edit_entries(caller,action,opt1,opt2,opt3,opt4,opt5,opt6,opt7,opt8,opt9,opt10,opt11,opt12) {
caller_id = caller.id.split("_");
id = caller_id[1];
switch(action) {
case "edit":
//Making textboxes writeable for changing values
//[...]
document.getElementById("group_"+id+"_button_edit").value="Save";
document.getElementById("group_"+id+"_button_edit").onclick=function(){ edit_entries(this,"save",opt1,opt2,opt3,opt4,opt5,opt6,opt7,opt8,opt9,opt10,opt11,opt12); };
break;
case "save":
if (confirm("Datensatz wirklich aktualisieren?")) {
artnr_key = XML_OBJ.getElementsByTagName("artnr")[0].textContent;
string = "";
//Building the AJAX Request String: textbox id = value
url = 'mysql_req_n1.php?type=edit_entries&'+string;
send_request(url);
}
break;
}
}
//called by AJAX handler
function edit_entries_unlock() {
//Getting "id" by value check
counter_a = 1;
while (counter_a <= 9) {
if (document.getElementById("group_"+counter_a+"_button_edit").value == "Save") id = counter_a;
counter_a++;
}
//Getting textbox IDs located in the AJAX response
opts = XML_OBJ.getElementsByTagName("opts")[0].textContent;
options = opts.split(",");
//Making textboxes readonly again
//[...]
document.getElementById("group_"+id+"_button_edit").value="Edit";
document.getElementById("group_"+id+"_button_edit").onclick=function(){ edit_entries(this,"edit",options[0],options[1],options[2],options[3],options[4],options[5],options[6],options[7],options[8],options[9],options[10],options[11]); };
}
And that is what happens:
I click on the first button (group_1_button_edit). It jumps to the switch block "edit" making the textboxes writable and changing the edit button to a save button. Works fine.
I click on save. The switch block "save" builds the request string and starts the ajax request.
The ajax handler starts edit_entries_unlock() when the response is there. Part of the XML Response are the textbox IDs I have used before. The onclick function gets changed again to an "edit" function with the corresponding textbox IDs from the XML object.
Now I click on the second button "group_9_button_edit". Everything is working like mentioned above. No problems. The textboxes of group 9 unlock, get saved und locked again as wanted.
But now the bug: I click on the first button again "group_1_button_edit" which now uses the changed function definition. It starts the switch block "edit" but with the values of the textbox IDs of GROUP 9 (which I edited before) and not GROUP 1.
I guess it has something to do with the variables opt1-opt12. They always contain the values of the last "edit_entries_unlock()" run. And as all the edited function definitions uses opt1-opt12 as well they start with the values of the last run and not with the values I used when recreating the function definition.
For that reason I asked how to build a function definition with the content of variables during the function creation process instead of the content during the execution process.
I hope that makes a lot more sense now. Sorry for the wall of text.
This is a very bad way to pass data.
You should avoid using inline code
<input type=button value="Set 1" id="btn1" onClick=edit_entry(this,"edit","title")>
<input type=button value="Set 2" id="btn2" onClick=edit_entry(this,"edit","name")>
<input type=button value="Set 3" id="btn3" onClick=edit_entry(this,"edit","gender")>
Should be
<input type=button value="Set 1" id="btn1" data-field-name="title">
<input type=button value="Set 2" id="btn2" data-field-name="name">
<input type=button value="Set 3" id="btn3" data-field-name="gender">
<script>
(function(){ // or use on load event
// define the click function
var clickFunction = function(event){
// get the element data
var fieldName = event.target.attributes["data-field-name"].value;
// do what you need to do.....
}
// query the DOM to get the elements you are after.
var el = document.getElementsByTagName("input");
// iterate them and add the event handler to each.
for(var i = 0; i < el.length; i++){
el[i].addEventListener("click",clickFunction,false);
}
})();
</script>
As for what you are trying to do in the example you gave I have no clue so maybe this will help you.
You onclick handler creates a closure. So, the values src, action and arg1 in the below (from your edit_entry function) will be what it was at the time this function was created / recreated (the latter for when you click it the next time)
src.onclick = function () { edit_entry( src, action, arg1 };
You'd be able to modify these only within the same method (or it's child methods). Note that since you set the onclick to the above you are basically passing around the same variables into the handler the next time it is clicked.
Any changes you are seeing for these variables would be from within your onclick handler (and not external to it)
Finally with the help of T.J.Crowder I was able to fix the code.
The line that I needed to fix was
options = opts.split(",");
to
var options = opts.split(",");
I didn't know that declaring variables inside a function without var would make them a part of the window object and therefore making it a global variable. So my closure was accessing a global variable instead a local one.
One small word, but with big impact.
Related
I have a JS function that is called on click that passes a string, and the first button works, however all subsequent buttons give me the error
action is not a function (In 'action("upvote")', 'action' is "")
Where action is the name of the function and upvote is the passed variable.
Using inspect element shows me the two buttons are identical, here is what they look like
<button type="button" onclick="action('upvote')">Like</button>
The weirdest thing is the button right before it calls a function as well and that work properly for all buttons not just the first one
<button type="button" onclick="fun(84)">Reply</button>
I checked and I am not forgetting to close any divs or buttons
The only thing I can think of is that I am echo these through a recursive php function, I don't think JS functions have scope, but I don't see why the first button work but not subsequent
Please let me know if more code is needed
The below code is my print function for the parent divs
echo
"<div class='parent' style='margin-left:".$width."px'>".$x['comment']."
<div class='actions'>
<button type='button' onclick='fun($ran)'>Reply</button>
<button type='button' onclick='action(\"upvote\")'>Like</button>
<button type='button'>Dislike</button>";
//Reply Like and Dislike are all actions every user gets, here I check which user it is to see if they can see the edit/delete
//Normally I would check for admin rather than id == 2, but there is only 1 admin and he id 2
if(($comment['userid'] == $_SESSION['id']) || $_SESSION['id'] == 2){
echo "<button type='button'>Edit</button>
<button type='button'>Delete</button>
</div>";//Close of actions div
}
else{
echo"</div>";//Close of actions div
}
$uname = mysqli_fetch_assoc($db->query("SELECT username FROM users WHERE id = ".$comment['userid']." "));
echo"
<div class='info'>
Score: ".$comment['score']." Posted By- ".$uname['username']."   At-".$x['created']." ";
if($x['edited'] != NULL){
echo" Edited Last-".$x['edited']." </div>";
}
else{
echo"</div>";
}?>
</div> //Close of parent div
Here is still part of the function me checking if the comment has any reply comments and if so I recursively call the same function,
$check = $db->query("SELECT * FROM user_comment WHERE replyid = ".$x['id']." ");
if(!$check || mysqli_num_rows($check) == 0){
return;
}
else{
$working = mysqli_fetch_assoc($check);
$new_reply = mysqli_fetch_assoc($db->query("SELECT * FROM comments WHERE id = ".$working['commentid']." "));
print_comment($new_reply,$db,$width+20,$working);
}
action in the inline event handler refers to the action property of the form containing the clicked element. It shadows your global action function, use a different name for the function, or rather use addEventListener to attach events. You can see the value in the snippet.
function foo(a) {
console.log(a);
}
<form>
<button type="button" onclick="foo(action);">
Click
</button>
</form>
The reason behind this is, that the code in an inline handler is scoped to the event target element using with (event.target) {...} (or similar internal scoping mechanism), and when the given variable (property actually) is not found from the element itself, with looks up the ancestor elements until the property is found. If it's not found from the elements, the last object to search is window, and this way it finds the global function which was meant to be executed, providing there wasn't naming conflict on the way up to window.
I have a JavaScript function which is used to copy data in my HTML page.
After clicking a button in the same HTML, a function is getting called. Till this everything is fine. But when I again click on same button, the same thing was getting copied twice. This should not happen. I want to copy content only one time.
<script language="JavaScript">
var x=1;
function h1b_cnslr() {
if (x===1){
x=2
some code
}
}
function h1b_nocnslr() {
if (x===1){
x=2
some code }
}
}
</script>
<BUTTON id ="btn_h1b_cnslr" class="copy" onClick="h1b_cnslr();" value="Copy" >Copy</BUTTON>
<BUTTON id ="btn_h1b_nocnslr" class="copy" onClick="h1b_nocnslr();" value="Copy" >Copy</BUTTON>
I am using variable x. The logic I used is, globally x=1 and when the user clicks for the first time x will get assigned 2. For the second click the value of x will be checked and if x===1, only then will it enter into the loop. But everytime x is assigned as 1 as I declared x as a global variable. Is their any other way to do this?
Put another var to check if you already have copied the content else skip copy
Sorry for unclear title but I couldn't find anything that could suit my problem.To better explain what it is let me show you my javascript code:
function askForIDForCommand()
{
var content;
$.post("Somepage.aspx", function (data)
{
content = $(data).find("#myDiv").html();
});
var myFunc = function () { }
var buttons = [{ text: 'OK', click: myFunc}];
ui_window("Hi", 630, content, buttons);
}
As you can see I declare a variable called content. Then I assign the html of a specified div to it. And then I send it to ui_window function which just displays a jquery dialog with the specified content. The problem is I don't get that html content in the dialog. When I look up the value of "content" with Firebug I can see that it contains html content. What makes me desperate is if I change the above function to the below one the html content gets displayed in the dialog:
function askForIDForCommand()
{
var content;
$.post("Somepage.aspx", function (data)
{
content = $(data).find("#myDiv").html();
var myFunc = function () { }
var buttons = [{ text: 'OK', click: myFunc}];
ui_window("Hi", 630, content, buttons);
});
}
In case you can't notice the difference, I just put the call of ui_window inside the $.post() method. And it works. Why's that?
And here's the html content in case you need it:
<table>
<tr>
<td align="right">
<label>
Enter the ID:</label>
</td>
<td>
<input id="txtID" type="text" onkeydown="return onlyNumbers(event);" maxlength="8"/>
</td>
</tr>
</table>
You're not assigning to content before you call ui_window. That assignment happens inside your anomyous function and therefore is not executed until someone calls that function (that is, once the post to Somepage.aspx is completed).
In contrast, you're calling ui_window() as soon as you have started the post to Somepage, but without waiting for that operation to finish. At that time your completion function still hasn't been called, and therefore content still contains undefined.
The problem is that the inner function is called when you recieve response from server. Then in the first case the variable is not assigned yet when those lines are executed and in the second one you are sure that ui_window is called with available data.
The problem is the AJAX call to the server. In the first case, you send a request and go straight to the next command, ie myFunc and so. Therefore your content variable isn't initialized at this moment.
I wish to show out other objects when the onclick function is clicked. When i click that button, it will hide one object and show two other objects. I have already set the style.visibility to visible. But the show two object does not works.
Update Sample:
<input type="submit" id="show" name="show" value="show" onclick="RemoveDoc(); document.getElementById('docname').style.visibility='hidden'; document.getElementById('browse').style.visibility='visible'; return false;" />
//browse input
<input type ="file" name="browse" id="browse">
Method 2:
//Using my RemoveDoc() function, I want the button of browse being show out.
function RemoveDoc(Doc)
{
xmlhttp1=new XMLHttpRequest();
xmlhttp1.open("GET","functions/remove.php?Doc="+Doc,true);
xmlhttp1.onreadystatechange=function()
{
if (xmlhttp1.readyState==4 && xmlhttp1.status==200)
{
//when i run debugging, it says that the style of null..
document.getElementById("browse").style.visibility='visible';
}
}
xmlhttp1.send();
return false;
}
</script>
I tried two methods which both also cant show the browse button.
It should call out my visible on browse object as it's visible.. kindly advise.
http://jsfiddle.net/y3Bad/
A few things: you should include the visibility code inside of your removeDoc function, and bind the handler from javascript, not in markup. Also, your variable xmlhttp1 is an implicit global. Your removeDoc function takes a parameter, Doc, but you never pass anything to it. Finally, removeDoc makes an ajax call, which is asynchronous, so your line of code to show the browse button will not execute immediately, and may never execute at all if your ajax calls fails.
HTML:
<input type="button" id="show" name="show" value="show" />
JS:
document.getElementById('show').onclick = function () {
// use display instead of visibility if you don't want the hidden element to take up space
// setting visibility to empty string will show the element
document.getElementById('browse').style.visibility = '';
};
I use these two functions:
function hide(objId) {
document.getElementById(objId).style.display="none";
}
function show(objId) {
document.getElementById(objId).style.display="";
}
Maybe you can try to use jQuery, something like this:
http://jsfiddle.net/7fJuu/
I have a function that executes on page load. The function executes every 30 seconds using setTimeout. I want to be able to enable and disable setTimeout onclick I have the following code below...
<input id="vw" value="" type="hidden">
<a href="#" onclick="document.getElementById('vw').value='0';>click here</a>
<script>
/* JAVASCRIPT BELOW */
function mPb(){
var vw = escape(document.getElementById('vw').value);
if(vw == ''){//DO NOT SWITCH VIEW IF EMPTY
var sTo = setTimeout("mPb()", 30000);
} else {
clearTimeout(sTo);
}
}//END VIEW MY FEED
//ON SERVICE LOAD DISPLAY SHITE INSTEAD OF ONLOAD
window.addEventListener ?
window.addEventListener("load",mPb,false) :
window.attachEvent && window.attachEvent("onload",mPb);
</script>
Your code works if you properly close your onclick attribute with a double quote:
click here
Also, here go two little suggestions to improve your code:
If you're checking for an empty string inside your function, why setting the input value to 0 when you click the link? It works, but it would be more clear if you set the value to ''.
When using setTimeout (and setInterval), do not pass a string containing a function call. It works too, but it's dangerous. Use this instead:
var sTo = setTimeout(mPb, 30000);
sTo needs to go outside of the mPb function, that way you can reference it from you onclick.