How do I write a mouse down event in JavaScript? - javascript

This is very basic I'm sure to JavaScript but I am having a hard time so any help would be appreciated.
I want to call a function within a for loop using the mouseDown event occurring within an object's second child node. The part italicized is my attempt to do this. The swapFE function is still a work in progress by the way. And one more thing is when I put the italicized part in the swapFE function everything works properly but when I put it in the for loop it doesn't all show up. I don't know why. I am basically trying to swap French phrases for English ones when I click the phrase with my mouse.
function setUpTranslation() {
var phrases = document.getElementsByTagName("p");
var swapFE = document.getElementsByTagName("phrase");
for (i = 0; i<phrases.length; i++) {
phrases[i].number = i;
phrases[i].childNodes[1].innerHTML = french[i];
*phrases[i].childNodes[1].onMouseDown = swapFE;*
}
}
/* see "function_swapFE(phrase,phrasenum);" below. The expression to call function swapFE
is located underneath "function swapFE(e)" because although the directions said to put the
"run swapFE" within the for loop it did not work properly that's why I put it beneath the
"function swapFE(e)".*/
function swapFE(e) {
var phrase = eventSource(e);
var phasenum = parseInt(1) = [1].innercontent.previousSibling;
phrase.node.previousSibling.onmousedown=swapFE
function_swapFE(e)(phrase,phrasenum);
}
}
If you have questions let me know.
Thanks for your help.

With this, you are creating a local variable named swapFE;
var swapFE =
document.getElementsByTagName("phrase");
Then with this you are setting this var as a mouseDown
phrases[i].childNodes[1].onMouseDown =
swapFE;*
That's not right... onMouseDown should be set to a function name, not a local variable of that name. So you should probably rename the local var to something else. That will at least get you closer to a solution.

I can only make a couple of guesses at what might be failing with your source code. Firstly, the following code assumes that all <p> tags have at least 2 child elements:
for (i = 0; i<phrases.length; i++) {
phrases[i].number = i;
phrases[i].childNodes[1].innerHTML = french[i];
*phrases[i].childNodes[1].onMouseDown = swapFE;*
}
If any <p> tags on your page have less than 2 child elements, an error will be thrown and script execution will halt. The best solution for this would be to add a class attribute to each <p> tag that will contain the elements you're looking for. Alternatively, you could just check for the existence of the second childnode with an if statement. Or you could do both.
Secondly, like all events, onmousedown should be declared in lowercase. Setting onMouseDown will not throw an error, but instead create a custom property on the element instead of attaching an event handler.
Finally, the following code:
var swapFE = document.getElementsByTagName("phrase");
will locally override the global function swapFE for that function, replacing it with a variable instead.
This is how I might write your setupTranslation function:
function setUpTranslation() {
var phrases = document.getElementsByTagName("p");
// rename the swapFE var as outlined below
var swapFENodes = document.getElementsByTagName("phrase");
var cNode; // set up an empty variable that we use inside the loop
for (i = 0; i<phrases.length; i++) {
/* Check for the existence of the translationPhrase class
in the <p> tag and the set the cNode var to childNodes[1]
and testing for its existence at the same time */
if (cNode.className != "translationPhrase"
|| !(cNode = phrases[i].childNodes[1]))
continue; // skip to the next iteration
phrases[i].number = i;
cNode.innerHTML = french[i];
cNode.onmousedown = swapFE; // Changed onMouseDown to onmousedown
}
}

Related

im trying to make a quiz for my bootcamp and i cant figure out what is wrong with the code

I'm trying to make a quiz game for a class and I can't seem to find the problem.
function askQuestions(random) {
var random = math.floor(math.random() * testQuestions.length);
var start = document.getElementById(testStart);
start.addEventListner('click', askQuestions);
if (start) {
document.write(random);
}
return;
}
This is the function and I have an array of objects, which is referenced in the "random" variable. I'm totally lost and I know I'm missing something simple. The purpose of this function is to display a random question from the array testQuestions.
Math is a global object and it starts with a capital M
Math.floor
You are adding the event listener inside the function. The function will only run if you call it, so the event listener will never be added. Additionally, document.write() will overwrite the entire page. I changed it to use document.createElement() and document.body.appendChild(). Change your code to this:
function askQuestions(random) {
var random = Math.floor(Math.random() * testQuestions.length);
var el = document.createElement('p');
el.textContent = random.toString();
document.body.appendChild(el);
}
var start = document.getElementById(testStart);
start.addEventListner('click', askQuestions);

I used js to create my command syntax, now how can I use it?

I have a Google Sheet with .gs script that is successfully generating dynamicnewRichTextValue() parameters which are meant to be injected into a Sheet cell that will contain multiple lines of text each with their own URL. I do not know all of the parameters in advance (might be one text and one link, or two each, or more) which is why I am dynamically generating the parameters.
Let's say the end-state should be this (in this case there are only two line items, but there could be more or less:
var RichTextValue=SpreadsheetApp.newRichTextValue()
.setText("mailto:fred#abcdef.com,mailto:jim#abcdef.com")
.setLinkUrl(0,6,"mailto:fred#abcdef.com")
.setLinkUrl(7,19,"mailto:jim#abcdef.com")
.build();
In my script I don't know how many "setText" parameters or "setLinkUrl" statements I will need to generate, so I am doing it dynamically.
This is simple to handle for "setText" because I can just pass a single variable constructed during an earlier loop that builds the "setText" parameters. Let's call that variable setTextContent, and it works like this:
var RichTextValue=SpreadsheetApp.newRichTextValue()
.setText(setTextContent)
So up to this point, everything is great. The problem is that I have another variable that generates the URL portion of the newrichtextvalue() parameters up to the ".build();" statement. So let's call that variable setUrlContent and it is built in an earlier loop and contains the string for the rest of the statement:
.setLinkURL(0,22,"mailto:fred#abcdef.com").setLinkURL(23,44,"mailto:jim#abcdef.com")
I am stumped trying to figure out how to attach it to the earlier bit. I feel like this is something simple I am forgetting. But I can't find it after much research. How do I hook up setUrlContent to the code above so that the command executes? I want to attach the bits above and get back to assigning it all to a variable I can put into a cell:
var emailCell=SpreadsheetApp.newRichTextValue()
.setText("mailto:fred#abcdef.com,mailto:jim#abcdef.com") // I can dynamically create up to here
.setLinkUrl(0,6,"mailto:fred#abcdef.com") // ...but these last couple lines are
.setLinkUrl(7,19,"mailto:jim#abcdef.com") // stuck in a string variable.
.build();
sheet.getRange(1,1,1,1).setRichTextValue(emailCell)
Thanks!
I believe your goal and situation as follows.
You want to use your script by dynamically changing the number of emails.
Modification points:
When your following script is run, I think that the links are reflected to mailto and fred#abcdef..
var emailCell=SpreadsheetApp.newRichTextValue()
.setText("mailto:fred#abcdef.com,mailto:jim#abcdef.com")
.setLinkUrl(0,6,"mailto:fred#abcdef.com")
.setLinkUrl(7,19,"mailto:jim#abcdef.com")
.build();
sheet.getRange(1,1,1,1).setRichTextValue(emailCell)
I thought that you might have wanted the linked email addresses like below.
fred#abcdef.com has the link of mailto:fred#abcdef.com.
jim#abcdef.com has the link of mailto:jim#abcdef.com.
In this answer, I would like to propose the modified script for above direction.
Modified script:
var inputText = "mailto:fred#abcdef.com,mailto:jim#abcdef.com"; // This is your sample text value.
var ar = inputText.split(",").map(e => {
var v = e.trim();
return [v.split(":")[1], v];
});
var text = ar.map(([e]) => e).join(",");
var emailCell = SpreadsheetApp.newRichTextValue().setText(text);
var start = 0;
ar.forEach(([t, u], i) => {
var len = t.length;
emailCell.setLinkUrl(start, start + len, u);
start += len + 1;
});
SpreadsheetApp.getActiveSheet().getRange(1,1,1,1).setRichTextValue(emailCell.build());
In this modification, inputText is splitted to the hyperlink and the text (for example, when your sample value is used, it's fred#abcdef.com and mailto:fred#abcdef.com.), and the text including the hyperlink are put to the cell.
In this case, for example, even when var inputText = "mailto:fred#abcdef.com,mailto:jim#abcdef.com" is modified to var inputText = "mailto:fred#abcdef.com" and var inputText = "mailto:fred#abcdef.com,mailto:jim#abcdef.com,mailto:sample#abcdef.com", each hyperlink are reflected to each text.
Note:
When you want to the hyperlink of mailto:fred#abcdef.com to the text of mailto:fred#abcdef.com, you can also use the following modified script.
var inputText = "mailto:fred#abcdef.com,mailto:jim#abcdef.com"; // This is your sample text value.
var ar = inputText.split(",").map(e => e.trim());
var emailCell = SpreadsheetApp.newRichTextValue().setText(inputText);
var start = 0;
ar.forEach((t, i) => {
var len = t.length;
emailCell.setLinkUrl(start, start + len, t);
start += len + 1;
});
SpreadsheetApp.getActiveSheet().getRange(1,1,1,1).setRichTextValue(emailCell.build());
References:
newRichTextValue()
Class RichTextValueBuilder
Class RichTextValue

traverse of tree in javascript

I have a javascript variable like below:
var treeNode= [{"id":"T1"},{"id":"T2","children":[{"id":"T3"},{"id":"T4"},{"id":"T5","children":[{"id":"T6"}, {"id":"T7"},{"id":"T8"}]},{"id":"T9"},{"id":"T10"}]},{"id":"T11"},{"id":"T12"}];
node t3,t4,t5,t6,t7,t8,t9,t10 are the child of node t2
i have a link of deactivate on each node.on click on deactivate link make active and delete link .mentioned in image.
now i want to make same active and delete link on all child node of parent node.
for example T3,T4,T5,T6,T7,T8,T9,T10 are the child of T2.
if i click on T5 then this will work on T6,T7,T8.
I tried below recursive code.may be my approach is not right.please advice.
var objTreeNode = eval(treeNode);
trav(objTreeNode);
function trav(TreeNodeObj){
var i=0;
for (i=0;i<TreeNodeObj.length;i++){
if(!TreeNodeObj[i].children){
if(objID==TreeNodeObj[i].id){ // will get T2 if click on deactivate link of Item T2
document.getElementById('span_'+TreeNodeObj[i].id).innerHTML = 'Activate <a href="javascript:deleteNode(\'' + objID
+'\');">Delete</a>';
}
}
else{
childObj = TreeNodeObj[i].children;
trav(childObj)
}
}
}
There are a few silly things in your code, let me fix them:
1. "Eval is evil!"
var treeNode= [{"id":"T1"},{"id":"T2","children":[{"id":"T3"}]}];
var objTreeNode = eval(treeNode);
trav(objTreeNode);
Why would you call eval()?
Let's see what MDN has to say about this:
Don't use eval! It's dangerous and slow. There are safe (and fast!) alternatives to eval() for common use-cases.
So what is your "use-case"? Why do you call eval here? What is the "better" solution? If you read the whole documentation on MDN you can read that:
If the argument of eval() is not a string, eval() returns the argument unchanged.
So unless treeNode is a string var objTreeNode = eval(treeNode); basically equals to var objTreeNode = treeNode;
You can drop that whole eval() line and just use treeNode. It's already an object.
2. camelCase
function trav(TreeNodeObj) {
This is not an error just a convention: In JavaScript (and also in most languages with C-like syntax) the parameters of a function are written with lower camel case (first letter is lowercase, and every other word's first letter is uppercase).
function trav(treeNodeObj) {
3. objID is undefined
There is no objID variable defined in your code. Although it is possible that you have a global defined elsewhere at the given time, it is much safer to introduce it as a parameter in your function.
function trav(treeNodeObj, objID) {
4. What your code does with what and when
Let me just figure out what your code currently does:
Iterates over a given object's children property (which is hopefully an array).
If an element has no children
Check if the array item has a desired ID property, and change it's innerHTML
Else
Call the function on the children
So what it does: Changes the element with the given ID if it has no children.
What you need is: Change the element with the given ID and also it's children.
I just modified your function like this:
function trav(treeNodeObj, objID, activate) {
var i = 0;
for (i = 0; i < treeNodeObj.length; i++) {
var childrenActive = false;
if (objID === treeNodeObj[i].id || activate) { // will get T2 if click on deactivate link of Item T2
childrenActive = true;
document.getElementById('span_' + treeNodeObj[i].id).innerHTML = 'Activate Delete';
}
if (treeNodeObj[i].children) {
childObj = treeNodeObj[i].children;
trav(childObj, objID, childrenActive);
}
}
}
Since you need to change all the child elements I needed to introduce a cut. This is the activate parameter. If the activate parameter is true you don't need to check the ID anymore you know that we are iterating over the subelements of the element with the given ID, and therefore change the element anyway.
Also you need to change the elements even if they have child nodes, so I restructured the if-s.
I have also made a jsfiddle for you to test: http://jsfiddle.net/JZ52g/3/
You can change the id parameter at the function call.

About a loop that creates dynamic buttons, but cannot give proper values [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Javascript infamous Loop problem?
I am having a small issue, and it would be very nice if some of you could realize about what kind of logic is missing here, since I cannot seem to find it:
I have an array with the results of some previous operation. Let's say that the array is:
var results = [0, 1];
And then I have a bunch of code where I create some buttons, and inside a for loop I assign a different function to those buttons, depending on the position of the array. The problem is that for some reason, all the buttons created (two in this case) come out with the function assigned to the last value of the array (in this case, both would come out as one, instead of the first with 0 and the second with 1)
This is the code:
for (var i = 0; i < results.length; i++) {
var br2 = b.document.createElement("br");
var reslabel = b.document.createTextNode(Nom[results[i]].toString());
var card = document.createElement("input");
card.type = "button";
id = results[i]; // this is the problematic value.
card.onclick = newcard; // this function will use the above value.
card.value = "Show card";
divcontainer.appendChild(br2);
divcontainer.appendChild(reslabel);
divcontainer.appendChild(card);
}
As it is, this code produces as many buttons as elements in the array, each with its proper label (it retrieves labels from another array). Everything is totally fine. Then, I click the button. All the buttons should run the newcard function. That function needs the id variable, so in this case it should be:
First button: runs newcard using variable id with value 0
Second button: runs newcard using variable id with value 1
But both buttons run using id as 1... why is that?
It might be very simple, or maybe is just that in my timezone is pretty late already :-) Anyways, I would appreciate any comment. I am learning a lot around here...
Thanks!
Edit to add the definition of newcard:
function newcard() {
id = id;
var toerase = window.document.getElementById("oldcard");
toerase.innerHTML = "";
generate();
}
the function generate will generate some content using id. Nothing wrong with it, it generates the content fine, is just that id is always set to the last item in the array.
Your id is a global variable, and when the loop ends it is set to the last value on the array. When the event handler code runs and asks for the value of id, it will get that last value.
You need to create a closure to capture the current results[i] and pass it along (this is a very common pitfal, see Javascript infamous Loop problem?). Since newcard is very simple, and id is actually used in generate, you could modify generate to take the id as a parameter. Then you won't need newcard anymore, you can do this instead:
card.onclick = (function(id) {
return function() {
window.document.getElementById("oldcard").innerHTML = "";
generate(id);
};
}(results[i]));
What this does is define and immediately invoke a function that is passed the current results[i]. It returns another function, which will be your actual onclick handler. That function has access to the id parameter of the outer function (that's called a closure). On each iteration of the loop, a new closure will be created, trapping each separate id for its own use.
Before going on, a HUGE thank you to bfavaretto for explaining some scoping subtelties that totally escaped me. It seems that in addition to the problems you had, you were also suffering from scoping, which bit me while I was trying to craft an answer.
Anyway, here's an example that works. I'm using forEach, which may not be supported on some browsers. However it does get around some of the scoping nastiness that was giving you grief:
<html>
<body>
<script>
var results = [0,1];
results.forEach( function(result) {
var card = document.createElement("input");
card.type = "button";
card.onclick = function() {
newcard( result );
}
card.value = "Show card";
document.body.appendChild(card);
});
function newcard(x) {
alert(x);
}
</script>
</body>
</html>
If you decide to stick with a traditional loop, please see bfavaretto's answer.

Trying to change all the numbers in an onchange - onchange.replace doesn't work?

I have an xsl page which uses
<xsl:variable name="pos" select="Position()"/>
in the onchange events
onchange="updateDropdown({$pos});someElement_{$pos}.value = {$pos}";
When evaluated on page p=load this will be read as
onchange="updateDropdown(1);someElement_1.value = 1";
onchange="updateDropdown(2);someElement_2.value = 2";
onchange="updateDropdown(3);someElement_3.value = 3";
When I add a row to the bottom of this using a button which copies the entire first row to the bottom it had to go through and update these numbers because it is not handled
I do
lastRowEl = rowEls[rowEls.length-1];
then
lastRowEl.id = "element_" + rowEls.length
lastRowEl.value = "";
finally,
lastRowEl.onchange = lastRowEl.onchange.replace(/\d/g, rowEls.length)
id gets changed to element_4
value gets modified to blank
but onchange.replace does not work and so onchange remains as
onchange="updateDropdown(1);someElement_1.value = 1";
instaead of
onchange="updateDropdown(4);someElement_4.value = 4";
How can I replace all numbers in an onchange function and reset the onchange function with the numbers modified for the element in the last row?
Thanks
This seems a bit weird and I wonder why it works at all, since the value returned by your lastRowEl.onchange is most likely a Function and not a String. Some automatic toString() call seems to happen on your platform (doesn't work when I test this in Safari). However, the result will most likely be a multiline string and you will probably need to use multiline RegExps, e.g. /\d/mg.
Even if this works it is pretty ugly. What about defining a function which does all the calls you put into your handler?
function onchangeHandler(index) {
updateDropdown(index);
window["someElement_" + index].value = index;
}
You would then assign these handler functions in HTML
< ... onchange="onchangeHandler(1);" .... />
and update them in Javascript
(function() {
var index = rowEls.length;
lastRowEl.onchange = function() {onchangeHandler(index);};
})();
Note that the closure around the assignment is may not be necessary depending on your surrounding code. You will most likely need the explicit index variable definition, though.
Try the following solution
var onch = new String(lastRowEl.onchange);
onch = onch.replace(/\d/g, rowEls.length);
lastRowEl.onchange = new Function(onch);
This will work as you expect.
Hope this solves your problem.

Categories

Resources