user3696118
user3696118

Reputation: 353

how to pass argument in function for this.setattribute?

so i am learning javascript(?), and i came across this situation i cannot really find a straight answer for.

so i have these paragraphs in an html page that i want to change the background color for, and the code I have working is this:

var colors=['red','pink','blue'];

var div2paragraphs = document.querySelectorAll('#div2 p')

for (let paragraph = 0; paragraph < div2paragraphs.length; paragraph++) {
    (function(paragraph) {
    div2paragraphs[paragraph].onmouseover = function(){
    this.setAttribute('style', `background-color: ${colors[paragraph]}`)}
    div2paragraphs[paragraph].onmouseout = function(){
    this.setAttribute('style', 'background-color: white')}
    })(paragraph);
}

I don't quite understand what is going on here either, I was just trying to do this with the whole "function(){}" thing (supposedly called an anonymous function?), but apparently there is something called an IIFE in javascript, so you have to WRAP the function and pass a unique variable to make it run each time within a loop, though i still don't understand why i have to end this with "(paragraph)".

I was thinking whether it is possible to do the same thing by just creating a function for each of these setAttribute actions, so i tried to write it this way:

var colors=['red','pink','blue'];

var div2paragraphs = document.querySelectorAll('#div2 p')

function changeToColor(color) {
    this.setAttribute('style', 'background-color: ' + color);
}

function changeBackWhite() {
    this.setAttribute('style', 'background-color: white');
}

for (let paragraph = 0; paragraph < div2paragraphs.length; paragraph++) {
    div2paragraphs[paragraph].onmouseover = changeToColor('red');
    div2paragraphs[paragraph].onmouseout = changeBackWhite;
}

but no matter what i do, it always pretty much comes up with the error:

Uncaught TypeError: this.setAttribute is not a function

or something along those lines. i think it has something to do with in these situations, if you add the parenthesis, it calls the function before it does anything else? so it doesn't know what "this" is? i don't quite understand, but in any case I haven't the slightest clue on how to write the same thing i did above with separate functions. would someone be able to shed some light into this...?

I am more used to Python so obviously there are fundamental concepts that are different...

PS: what are the difference between these two examples below?

for (let paragraph = 0; paragraph < div2paragraphs.length; paragraph++) {
    div2paragraphs[paragraph].onmouseover = function() {
        this.style['background-color'] = colors[paragraph];
    }
    div2paragraphs[paragraph].onmouseout = function() {
        this.style['background-color'] = 'white';
    }
}

and this

for (let paragraph = 0; paragraph < div2paragraphs.length; paragraph++) {
    div2paragraphs[paragraph].onmouseover = function(){
        this.setAttribute('style', `background-color: $(colors[paragraph]`)
    }
    div2paragraphs[paragraph].onmouseout = function(){
        this.setAttribute('style', 'background-color: white')
    }
}

and why does the first one (provided by ibrahim mahrir) work and the second one does not?

Upvotes: 2

Views: 707

Answers (2)

MaxC
MaxC

Reputation: 41

https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Event_handlers

While assigning on-event handlers, you must assign handler functions to the placeholders.

div2paragraphs[paragraph].onmouseover = changeToColor('red');

The TypeError occurs here. The result (returned value) of the invoked changeToColor function with the parameter "red" is a variable. This is not a function. Assigned handlers must fit the prototype function(Event e){...} where e is an object of the Event class as defined in https://developer.mozilla.org/en-US/docs/Web/API/Event

div2paragraphs[paragraph].onmouseout = changeBackWhite;

This line however, is correct because you are assigning the ID of a defined function to the placeholder, which can then be used as the real handler function.

What you need to do is, rewrite the function changeToColor and assign its ID to the placeholer

div2paragraphs[paragraph].onmouseover = changeToColor

Or, if you want to immediately invoke the function, you can wrap it within another function that has this reference to the context where it's belong to (if the calling function needed this), using either call or apply.

div2paragraphs[paragraph].onmouseover = function () {
  changeToColor.call(this, 'red');
}

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this

Upvotes: 0

ibrahim mahrir
ibrahim mahrir

Reputation: 31692

In the first code example, the IIFE inside the loop is totally useless as you are already using let which respects the block scope, so this problem won't happen. The following code will work just fine:

for (let paragraph = 0; paragraph < div2paragraphs.length; paragraph++) {
    div2paragraphs[paragraph].onmouseover = function() {
        this.style['background-color'] = colors[paragraph];
    };
    div2paragraphs[paragraph].onmouseout = function() {
        this.style['background-color'] = 'white';
    };
}

Note: You don't need to use setAttribute to set the style properties. Just do it directly.

Demo:

var colors=['red','pink','blue'];

var div2paragraphs = document.querySelectorAll('#div2 p');

for (let paragraph = 0; paragraph < div2paragraphs.length; paragraph++) {
    div2paragraphs[paragraph].onmouseover = function() {
        this.style['background-color'] = colors[paragraph];
    };
    div2paragraphs[paragraph].onmouseout = function() {
        this.style['background-color'] = 'white';
    };
}
<div id="div2">
    <p>AAAA</p>
    <p>BBBB</p>
    <p>CCCC</p>
</div>


As for the second code example, your functions need to return other functions to be assigned as event listeners. For example changeColor should be defined like so:

function changeToColor(color) {
    return function() {
        this.style['background-color'] = color;
    }
}

The anonymous function returned by changeColor will be assigned to the event listener. In your code changeColor returned nothing, so undefined is attached to the event listener. Furthermore, changeColor is not the event listener itself (it's just a function that creates the event listener and returns it), so this inside it will be the global object window. window don't have a method called setAttribute, hence the error.

Also, you don't need changeBackWhite, you can use changeColor for both (courtesy of closures), like so:

for (let paragraph = 0; paragraph < div2paragraphs.length; paragraph++) {
    div2paragraphs[paragraph].onmouseover = changeToColor(colors[paragraph]);
    div2paragraphs[paragraph].onmouseout = changeToColor('white');;
}

Demo:

var colors=['red','pink','blue'];

var div2paragraphs = document.querySelectorAll('#div2 p');

function changeToColor(color) {
    return function() {
        this.style['background-color'] = color;
    }
}

for (let paragraph = 0; paragraph < div2paragraphs.length; paragraph++) {
    div2paragraphs[paragraph].onmouseover = changeToColor(colors[paragraph]);
    div2paragraphs[paragraph].onmouseout = changeToColor('white');;
}
<div id="div2">
    <p>AAAA</p>
    <p>BBBB</p>
    <p>CCCC</p>
</div>

Upvotes: 1

Related Questions