I am making a simple web app. In one particular page, I have to dynamically generate a list and have a calendar after every item in the list.
Here is the code:
for (var i = 0; i < goalsObj.length; i++) {
var node = document.createElement("li");
node.setAttribute("draggable", "true");
node.setAttribute('id', 'g' + i);
node.addEventListener('click', function () {
viewGoal()
}, false);
var textnode = document.createTextNode(goalsObj[i]);
node.appendChild(textnode);
var cal = "<script>calendar()</script>";
var calen = document.createTextNode(cal);
document.getElementById("sortable").appendChild(node);
document.getElementById("sortable").appendChild(calen);
}
but the problem is that instead of the output of the calendar() function being computed and shown, I am getting just "script calendar() /script" everywhere. What's wrong? What should I do?
use
var calen = document.createElement("div");
document.getElementById("calen").innerHTML=calendar();
var scriptElement = document.createElement('script');
scriptElement.type = 'text/javascript';
scriptElement.appendChild(document.createTextNode('calendar();'));
You don't need to create a script element for this. If I understand you correctly, then you simply want to display the result of calendar(). So you can just call the function and pass the result to the createTextNode function:
var calen = document.createTextNode(calendar());
What you are doing right now is creating a string "<script>calendar()</script>" and then creating a textnode with this string as content. Nothing gets executed, because createTextNode just does that, it creates a TEXTnode.
Related
I've been browsing around for an answer to this question for a little while now, but haven't found a solution. I need to pass an object to a function which is being fired "onChange" when a select option is chosen by a user. The current code is:
selecter.onchange = function(){
var runScript = $("#actionSel option:selected").attr('script');
console.log(runScript);
eval("("+runScript+")();");
}
The intention here is to store a function within the "script" attr of the options, which will then be run when that option is selected. However, for one of my functions I need to pass a variable from the parent scope on in order to interact with the server via websockets.
The function stored in the "Script" attribute is :
function(){ popConfirm("Restore User","Do you really want to restore the selected users? This will un-delete the selected deleted users.",function(r){ if(r)restoreUser(r,io); });
Essentially this verifies with the user that they want to do what they've selected, then passes the result to my restore user function. It also needs to pass the "io" object on. However, I'm getting an error which states that io is undefined.
Any ideas would be extremely helpful. Thanks!
As requested, here are some additional relative pieces of code showing where IO is introduced.
AdminIO = new io(servPath);
AdminIO.on('send_users',function(rows){
toggleLoad();
appendUsers(rows,AdminIO);
});
Within appendUsers there's another function which compiles the select list and its options, dropActions(), wherein the selector.onchange and other piece I posted before are introduced. The selector.onchange is part of the function that creates the dropdown list. The function(){ popConfirm() } is added as the function to run on selection of that item. The function to build the list is :
dropActions = function(bActions, lActions, options){
// bActions = {id: myID, text: "this is my action", elem: document.getElementById('getDiv'), action: function(){ /*mycode here */}}
// lActions = {text: "select me to run an action", action: function(){ /*mycode here */}}
bActions = bActions || null;
lActions = lActions || null;
options = options || {elem: document.body, id: null};
if(!bActions && !lActions){ console.error("No actions added or available."); return; }
var
selID = options.id,
starter = (selID) ? document.getElementById(selID) : options.elem,
optsBar = document.createElement("header"),
selecter = document.createElement("select");
starterSel = document.createElement("option");
optsBar.id = "actionSelH";
starterSel.innerText = "More Actions";
starterSel.setAttribute('script','javascript:void(0)');
selecter.id = "actionSel";
selecter.appendChild(starterSel);
for(var i= 0; bActions.length > i; i++){
var
buttonText = bActions[i].text,
buttonID = bActions[i].id || 'ACT'+i,
buttonAction = bActions[i].action,
button = document.createElement('div');
button.id = buttonID;
button.classList.add("actionButton");
button.innerText = buttonText;
button.onclick = buttonAction;
optsBar.appendChild(button);
}
for(var i= 0; lActions.length > i; i++){
var selText = lActions[i].text,
selScript = lActions[i].action,
option = document.createElement('option');
option.innerText = selText;
option.setAttribute('script',selScript);
selecter.appendChild(option);
}
selecter.onchange = function(){
var runScript = $("#actionSel option:selected").attr('script');
console.log(runScript);
eval("("+runScript+")();");
}
optsBar.appendChild(selecter);
$(optsBar).insertBefore('#user_list_table');
//$('#user_list_table').after(optsBar);
//$(starter).prepend(optsBar);
},
Hopefully more context helps!
Instead of using eval, you could use the function constructor and pass your parameters directly to that function:
var scriptFunction = new Function(r, io, runScript);
scriptFunction(r, io);
Of course, this code assume that r and io will always be the variable you are looking for. If this ain't the case, you'll have to write your own logic to take the variable from the parent scope and then pass them to the scriptFunction.
Update
If you are able ton change the provided script, you could also try to implicitly declare the variables r and io:
function(r, io){ popConfirm("Restore User","Do you really want to restore the selected users? This will un-delete the selected deleted users.",function(r, io){ if(r)restoreUser(r,io); });
Im currently getting data from Google places and am dynamically creating the div to display the results. I am trying to add a mouseover event to each div yet am having no luck implementing it. Ive check the html source and it seems to not add the event for any of the created DIV's.
JS:
for (var i = 0; i < relatedProperties.length; i++) {
var div = document.createElement("div");
div.innerHTML = relatedProperties[i].formatted_address;
div.className = "item_holder";
div.onmouseover = PanToMarker(relatedProperties[i].formatted_address);
document.getElementById('relatedpropertyDIV').appendChild(div);
}
function PanToMarker(address) {
//Grabs the address and pans to it on the map.
}
I would imagine you need to wrap your onmouseover function like this:
div.onmouseover = function() {
PanToMarker(relatedProperties[i].formatted_address);
};
This is because when you click on the element, the onmouseover function gets called with no arguments. When you specify arguments to PanToMarker like in your question, instead of assigning the function as may be intuitive, instead it executes the function then and there, and then assigns the function's output. Wrapping the function like this assures that the function doesn't get called instead while you're trying to assign it.
When you add the onmouseover event handler in this manner, you will not see it in the dom.
I would recommend that you store the index as a data property in the DOM. Then you will be able to access it from the mouseover method ...
for (var i = 0; i < relatedProperties.length; i++) {
var div = document.createElement("div");
div.innerHTML = relatedProperties[i].formatted_address;
div.setAttribute('data-index', i);
div.className = "item_holder";
div.onmouseover = PanToMarker;
document.getElementById('relatedpropertyDIV').appendChild(div);
}
function PanToMarker() {
var selectedIndex = this.getAttribute('data-index');
map.panTo(relatedProperties[selectedIndex].geometry.location);
}
There may be performance implications since you will be appending i elements to the DOM, each of which may cause a re-draw. It might be better to create all the elements first, then append once.
var section = document.createElement('section');
for (var i = 0, length = relatedProperties.length; i < length; i++) {
var div = document.createElement("div");
div.innerHTML = relatedProperties[i].formatted_address;
div.setAttribute('data-index', i);
div.className = "item_holder";
div.onmouseover = PanToMarker;
section.appendChild(div);
}
document.getElementById('relatedpropertyDIV').appendChild(section);
function PanToMarker() {
var selectedIndex = this.getAttribute('data-index');
map.panTo(relatedProperties[selectedIndex].geometry.location);
}
So, I'm trying to have a button add another dropdown (DD in my code) to the page, and it works just dandy, except when I try to remove (which "works") the remaining node no longer has the parentNode set properly.
Here is my code:
function insertAfter(newNode, elem) {
elem.parentNode.insertBefore(newNode, elem.nextSibling);
}
function addSwitchMenu() {
var lastDD = dropdowns.switches.last();
var newDD = lastDD.cloneNode();
newDD.innerHTML = lastDD.innerHTML;
var oldButton = document.getElementById("add-switch");
var newButton = oldButton.cloneNode();
var newBR = document.createElement("br");
oldButton.value = '-';
oldButton.id = 'remove-switch';
oldButton.onclick = function() {
var index = dropdowns.switches.indexOf(newDD);
dropdowns.switches.splice(index,1);
lastDD.parentNode.removeChild(lastDD);
oldButton.parentNode.removeChild(oldButton);
newBR.parentNode.removeChild(newBR);
updateResults();
}
dropdowns.switches.push(newDD);
console.log(newDD);
console.log(lastDD.parentNode);
insertAfter(newDD, lastDD);
insertAfter(newButton, lastDD);
insertAfter(newBR, lastDD);
}
And basically I call this function, then I call the remove function of the first one, then I call this function once more using the node that was created with the first one. I'm guessing it's something to do with the referencing node being removed, but the new node has a parentNode up until the other node is removed. Why? And how can I fix this?
The program is supposed to be a live search using php and javascript... where as you type it searches below. I just recently started learning javascript so sorry if my knowledge is limited...
$(document).ready(function () {
$('#results').append('<p>Started</p>');
var getText = (function () {
return document.getElementById('year').value;
});
var text = getText;
var getText1 = (function () {
return document.getElementById('class').value;
});
var text1 = getText1;
setInterval(function () {
var newText = getText;
var newText1 = getText1;
var loading = "search.php?year=" + newText + "&class=" + newText1;
$('#results').append(newText1);
if (text !== newText || text1 !== newText1) {
$('#results').load(loading);
$('#results').append('somethinghappened');
};
text = newText;
text1 = newText1;
}, 100);
});
so it works fine when i append newText1, however if i try to append "loading" it returns:
search.php?year=function () { return document.getElementById("year").value; }&class=function () { return document.getElementById("class").value; }
Can anyone explain what the difference between the two cases is and why a difference occurs? and possibly how to fix it so that it loads the correct URL
i searched and found: JavaScript: When assigning an anonymous function to a variable, function return value is not passed, rather the function as a string however didn't quite understand completely what it meant by passing two arguments, and when i tried to do something similar, it didn't work as expected...
Any help is appreciated and thanks in advance.
var newText = getText;
var newText1 = getText1;
You are assigning the functions getText and getText1 to the variables instead of executing them and assigning their return values. Try this instead:
var newText = getText();
var newText1 = getText1();
Or just:
var newText = document.getElementById('year').value;
var newText1 = document.getElementById('class').value;
try simply with
var getText = document.getElementById('year').value;
var getText1 = document.getElementById('class').value;
otherwise you will have only a reference to the function
You're not calling the functions, you're just referencing them.
To call them you need parens, like getText(). But why make them functions in this case? They're short and don't take parameters. If you want functions, make a single function that takes the string ID.
I am having trouble with JS closures:
// arg: an array of strings. each string is a mentioned user.
// fills in the list of mentioned users. Click on a mentioned user's name causes the page to load that user's info.
function fillInMentioned(mentions) {
var mentionList = document.getElementById("mention-list");
mentionList.innerHTML = "";
for (var i = 0; i < mentions.length; i++) {
var newAnchor = document.createElement("a");
// cause the page to load info for this screen name
newAnchor.onclick = function () { loadUsernameInfo(mentions[i]) };
// give this anchor the necessary content
newAnchor.innerHTML = mentions[i];
var newListItem = document.createElement("li");
newListItem.appendChild(newAnchor);
mentionList.appendChild(newListItem);
}
document.getElementById("mentions").setAttribute("class", ""); // unhide. hacky hack hack.
}
Unfortunately, clicking on one of these anchor tags results in a call like this:
loadUserNameInfo(undefined);
Why is this? My goal is an anchor like this:
<a onclick="loadUserNameInfo(someguy)">someguy</a>
How can I produce this?
Update This works:
newAnchor.onclick = function () { loadUsernameInfo(this.innerHTML) };
newAnchor.innerHTML = mentions[i];
The "i" reference inside the closure for the onclick handlers is trapping a live reference to "i". It gets updated for every loop, which affects all the closures created so far as well. When your while loop ends, "i" is just past the end of the mentions array, so mentions[i] == undefined for all of them.
Do this:
newAnchor.onclick = (function(idx) {
return function () { loadUsernameInfo(mentions[idx]) };
})(i);
to force the "i" to lock into a value idx inside the closure.
Your iterator i is stored as a reference, not as a value and so, as it is changed outside the closure, all the references to it are changing.
try this
function fillInMentioned(mentions) {
var mentionList = document.getElementById("mention-list");
mentionList.innerHTML = "";
for (var i = 0; i < mentions.length; i++) {
var newAnchor = document.createElement("a");
// Set the index as a property of the object
newAnchor.idx = i;
newAnchor.onclick = function () {
// Now use the property of the current object
loadUsernameInfo(mentions[this.idx])
};
// give this anchor the necessary content
newAnchor.innerHTML = mentions[i];
var newListItem = document.createElement("li");
newListItem.appendChild(newAnchor);
mentionList.appendChild(newListItem);
}
document.getElementById("mentions").setAttribute("class", "");
}