Do I need a parameter in this function? - javascript

In this homework assignment, I'm having issues with this part of the problem.
window.onload=setup;
function setup()
{
var questions = document.querySelectorAll('ol li');
for (var i= 0; i < questions.length ; i++)
{
questions[i].id = i + "phrases";
questions[i].onmousedown = showEnglish;
//questions[i].onmouseup = showFrench;
questions[i].style.cursor = "pointer";
}
}
function showEnglish()
{
var phraseNumber = parseInt(question[i].id)
document.getElementById(phraseNumber).innerHTML = english[phraseNumber];
english[phraseNumber].style.font = "italic";
english[phraseNumber].style.Color = "rgb(191,22,31)";
}
a) Using the id property of the list item experiencing the mousedown event, extract the index number with the the parseInt() function and store that value in the phraseNumber variable.
I get an error, saying questions is not defined in the showenglish().
Am I supposed to be referencing another object?

You need to pass the question as a parameter:
for(i=0;i<question.length;i++){
let a=i;//important for scoping
question[a].onmousedown=function(){
showEnglish(question[a]);
}
}
function showEnglish(question){
document.getElementById(question.id).style.font="italic";
...
}
(Note: this answer contains ES6. Do not use it in real productional environment. The let a=i; defines that a is kept for being used inside of the listener, while i will always be question.length, because the event is probably clicked after the loop occured...)
Alternatively, the event listener binds this as the clicked element:
question[i].addEventListener("click",showEnglish,false);
function showEnglish(){
document.getElementById(this.id).style.font="italic";
...
}

The mousedown event is raised when the user presses the mouse button. Look at the documentation for the mousedown event.
Your event handler function will be passed an Event object, which has a target property, which is a reference to the element that the mouse clicked on.
You can access this inside your event handler function with event.target.
window.onload = setup;
function setup() {
var questions = document.querySelectorAll('ol li');
for (var i = 0; i < questions.length; i++) {
questions[i].id = i + "phrases";
questions[i].onmousedown = showEnglish;
//questions[i].onmouseup = showFrench;
questions[i].style.cursor = "pointer";
}
}
function showEnglish(event) {
var phraseNumber = parseInt(event.target.id);
// etc
};

Related

Can't detach javascript event after it fires

I'm using this structure to create one-time click events:
function structure() {
this.elements = document.getElementsByClassName('className');
this.numElements = this.elements.length;
for(var i = 0; i < this.numElements; i++) {
this.elements[i].addEventListener('click', this.elementClicked.bind(this));
}
}
The handler of those events is implemented as follows:
structure.prototype.elementClicked = function(e) {
// ... processing event
for(var i = 0; i < this.numElements; i++) {
this.elements[i].removeEventListener('click', arguments.callee);
}
};
The idea is to fire the handler once if any of the registered elements gets clicked, and then unregister the event from each of those elements
Unfortunately the handler still gets fired everytime I click on one of the registered items
I'm aware anonymous functions can't be used to reference the same object, but specifying arguments.callee or the entire name of the referenced function still didn't help the cause
An alternative is to make your objects implement the EventListener interface. You can do this by adding a handleEvent method to the .prototype of the constructor, and then passing the object itself in place of the event handler.
function Structure() {
this.elements = document.getElementsByClassName('className');
this.numElements = this.elements.length;
for(var i = 0; i < this.numElements; i++) { // v-- pass the object
this.elements[i].addEventListener('click', this);
}
}
// Implement the interface; gets invoked when an event occurs
Structure.prototype.handleEvent = function(e) {
// Used a switch statement in anticipation of other event types
switch (e.type) {
case "click":
this.elementClicked(e);
break;
}
};
Structure.prototype.elementClicked = function(e) {
// ... processing event
for(var i = 0; i < this.numElements; i++) { // v-- pass the object
this.elements[i].removeEventListener('click', this);
}
};
Now there's no longer any need to use .bind(). Instead the value of this in handleEvent will be the bound object. You can still get the element to which the handler was bound via e.currentTarget.
Each time you call...
this.elements[i].addEventListener('click', this.elementClicked.bind(this));
... bind creates another instance of a method. It uses this.elementClicked, true, but otherwise is a completely different function. That's why you won't drop it with remoteEventListener called on this.elementClicked.
What's the workarounds? One possible option - passing { once: true } as addEventListener param - has been given in the comments, but it's not supported by IE and Edge (and most likely won't be supported by the Safari you encounter in the nearest future). Here's another approach:
function Structure() {
this.elements = document.getElementsByClassName('className');
this.numElements = this.elements.length;
// reassign a bound method onto instance:
this.elementClicked = this.elementClicked.bind(this);
for(var i = 0; i < this.numElements; i++) {
this.elements[i].addEventListener('click', this.elementClicked);
}
}
Structure.prototype.elementClicked = function(e) {
// ... processing event
for(var i = 0; i < this.numElements; i++) {
this.elements[i].removeEventListener('click', this.elementClicked);
}
};
Now you create a bound elementClicked method for each instance of structure object, having its context set permanently.

Can you attach a handler function with arguments to an onclick event for a number of elements in a loop?

I am trying to set an onclick event for thumbnails that are dynamically populated from a database. I need to set the function to handle an argument, which is the id of the bigger picture the thumbnail represents. The code I have now sets all the thumbnails to point to #18. If you see in the for-loop, it is supposed to die at 17:
for (var i = 0; i < 18; i++) {
document.getElementById('tat' + i).onclick = function() { display(i); };
}
(My thumbnail <img />s all have id="tat0", id="tat1", id="tat2", id="tat3" etc.)
(display() loads the larger pic that the thumbnail represents into a separate element)
Each thumbnail gets this onclick function, so I know the for loop is accessing each one by its ID properly (stepping through for each i) so why are all the display(i) being assigned to 18? Can you assign an onclick function to handle parameters?
You need a closure function to generate your handlers.
function genHandler( param ) {
return function() {
// use all params in here
display( param );
}
}
and then assign your events similarly
for (var i = 0; i < 18; i++) {
document.getElementById('tat' + i).onclick = genHandler( i );
}
It might also work, if you just add 'i' as a parameter to your function.
Wrapping your onclick handler in a function will create a closure that carrys the current scope with it.
for (var i = 0; i < 18; i++) {
document.getElementById('tat' + i).onclick = (function(a) {
return (function() {
display(a);
});
})(i);
}​

Handling onclick events

I have a list which contains links . I am using this code to access them:
function initAll() {
var allLinks = document.getElementById("nav").getElementsByTagName("a");
for (var i=0; i< allLinks.length; i++) {
allLinks[i].onmouseover = showPreview;
allLinks[i].onmouseout = function() {
document.getElementById("previewWin").style.visibility = "hidden";
allLinks[i].onclick=mainProcess;
}
}
}
function mainProcess(evt){
alert(this.value);
false;
}
This is not the exact code, what I am trying to do is that I need to identify link is clicked and perform some function on the basis of link clicked. I don't know where code needs to be modified... Page is giving error on the allLinks[i].onclick=mainProcess(this); line.
Now the problem is that I don't know how I should handle all the three events?
1) You're setting the onclick property of each of the links to be the value returned by mainProcess() - which always returns false. So, in effect, you're writing allLinks[i].onclick = false;
2) When you define an event handler directly, the argument that gets passed to it when the event fires, is the event object - not the element it was fired on.
To figure out the element, you can either look in the event object, or (since the handler has been added to the element itself) simply use this, as that will refer to the link element
for (var i = 0; i < allLinks.length; i++) {
allLinks[i].onclick = mainProcess;
}
function mainProcess(event) {
{
alert(this.value);
return false;
}
You do need to pass this to mainProcess(link). As stated in http://www.quirksmode.org/js/events_tradmod.html "No parentheses!" and "this" chapters. Check it out, there's an example there too. Should be everything you need.
Try changing to this:
for (var i = 0; i < allLinks.length; i++) {
allLinks[i].onclick = mainProcess;
}
function mainProcess(event) {
{
alert(this.value);
return false;
}

In JQGrid add onclick event on img

I'm very new to JQuery, and I'm having some trouble
function Clients(guid)
{
var that = this;
this.guid = guid;
this.container = $("#Clients_" + that.guid);
this.LoadClients = function () {
var ids = that.container.find("#clients-tbl").getDataIDs();
for (var i = 0; i < ids.length; i++) {
var row = that.container.find("#clients-tbl").getRowData(ids[i]);
var imgView = "<img src='../../Content/Images/vcard.png' style='cursor:pointer;' alt='Open case' onclick=OnClickImage(" + ids[i] + "); />";
that.container.find("#clients-tbl").setRowData(ids[i], { CasesButtons: imgView });
}
}
this.CreateClientsGrid = function () {
var clientsGrid = that.container.find("#widget-clients-tbl").jqGrid({
.....
ondblClickRow:function(rowid)
{
---
}
loadComplete: function () {
that.LoadClients();
}
}
this.OnClickImage=function(idClient){
....
}
this.Init = function () {
that.CreateClientsGrid();
};
this.Init();
}
The problem is with onclick, because OnClickImage is not global function.
How can I use OnClickImage function?
You can bind to the click event in different ways. For example you can follow the way from the answer. By the way, it works much more quickly as getRowData and setRowData. Moreover you should save the result of that.container.find("#clients-tbl") operation in a variable outside of the loop and use use the variable inside the loop. JavaScript is dynamic language and every operation even ids.length will be done every time.
One more way would to use onCellSelect event without click event binding. See the answer which describe the approach and gives the corresponding demo.

JavaScript closures and variable scope

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", "");
}

Categories