1

I am looking to call a function that was originally just an anonymous function, but it turned out I need this function 3 times in my code. So I defined a function like this:

function saveButton() {
  this.parentElement.parentElement.querySelector('h3').innerHTML = this.parentElement.querySelector('input[name="task-title"]').value;
  this.parentElement.parentElement.querySelector('p').innerHTML = this.parentElement.querySelector('textarea').value;
  this.parentElement.parentElement.querySelector('.popup').className = 'popup hidden';
  this.parentElement.parentElement.querySelector('.overlay').className = 'overlay hidden';
  saveWork();
};

I want to call this function in an anonymous function like this :

confirmButton.onclick = function()
    saveButton();
};

But afterwards I realized that I couldn't use the this in the anonymous function. How can I call confirmButton() in the anonymous function?

nook
  • 1,729
  • 1
  • 12
  • 34
  • 1
    Don't use onclick and use addEventListener which exposes the element acted on inside the callback – charlietfl Dec 12 '17 at 23:46
  • Possible duplicate of [How does the "this" keyword work?](https://stackoverflow.com/questions/3127429/how-does-the-this-keyword-work) – Michael Dec 13 '17 at 01:41

3 Answers3

2
confirmButton.onclick = saveButton;

or

confirmButton.onclick = function(){
    saveButton.call(this);
};

although it's not a good practice to have the same name for DOM node and a function that you want to call. rename your function into something that makes more sense like buttonClick

fila90
  • 1,439
  • 11
  • 11
  • Both of them tell me that `this` is undefined. On the second snippet, I wrote `confirmButton().call(this);` I think this is what you meant. And yes, I'll think about renaming my functions. (I have the same thing somewhere else) – nook Dec 12 '17 at 23:54
  • have you renamed your function into something else?? as it's right now confirmButton DOM node will be overwritten by confirmButton function or vice versa – fila90 Dec 12 '17 at 23:57
  • I renamed my function's name – nook Dec 13 '17 at 00:01
  • 1
    `confirmButton().call(this);` won't work. it will invoke `confirmButton()` function, then it will try to invoke `.call(this)` on the return value and we don't return anything there. `call` will invoke the function for you and bind `this` that you want to it. – fila90 Dec 13 '17 at 00:01
  • 1
    can you post full fidle with html and js? – fila90 Dec 13 '17 at 00:03
  • It actually works. I didn't know you could call function with the same syntax than an object. I never called a function without the `()` – nook Dec 13 '17 at 09:32
  • mind opening http://javascriptissexy.com/javascript-apply-call-and-bind-methods-are-essential-for-javascript-professionals/ :D – fila90 Dec 13 '17 at 23:17
1

Have you tried using function expressions? Essentially it means assigning a function to a variable. Read this answer to learn about the differences between function expressions and function declarations.

As for your question, most of the time it's this case:

You want to use the parent scope of a given anonymous function.

If thats the case, I would recommend this neat little trick:

var self = this;

this.saveButton = function() { // or self.saveButton...
  this.parentElement.parentElement.querySelector('h3').innerHTML = this.parentElement.querySelector('input[name="task-title"]').value;
  this.parentElement.parentElement.querySelector('p').innerHTML = this.parentElement.querySelector('textarea').value;
  this.parentElement.parentElement.querySelector('.popup').className = 'popup hidden';
  this.parentElement.parentElement.querySelector('.overlay').className = 'overlay hidden';
  saveWork();
};

confirmButton.onclick = function() {
    self.saveButton();
}

This trick can be used in any level of scope depth, just don't pollute the global namespace :)

tehabstract
  • 529
  • 6
  • 14
0

By looking at the code fragment you posted, and guessing a few things, I suggest the following refactoring:

function saveButton(parentElem) {
  var myParent = parentElem || this.parentElement;
  myParent.parentElement.querySelector('h3').innerHTML = myParent.querySelector('input[name="task-title"]').value;
  myParent.parentElement.querySelector('p').innerHTML = myParent.querySelector('textarea').value;
  myParent.parentElement.querySelector('.popup').className = 'popup hidden';
  myParent.parentElement.querySelector('.overlay').className = 'overlay hidden';
  saveWork();
}

confirmButton.onclick = function() {
  // I suppose when this function is called somewhere else,
  // you actually know who is the parent element, so:
  saveButton(document.querySelector('.theParentElement'));
};

// If you calling it somewhere where "this" is available,
// then simply call the function with no arguments:
saveButton();

Maybe some variation of the example above can help you. Other than that, I can't think of a better answer without looking at a greater portion of your code.

rodrigocfd
  • 6,450
  • 6
  • 34
  • 68
  • Well it actually does not. I am generating HTML elements with plain Javascript, and I can't use the querySelector on the parent element anywhere. I really need to select the parent of the freshly created object, and this is the only way I found with plain Javascript. Somewhere else in my code, I want to remove a parent Element, it's ugly, but I have to do `parentElement.parentElement.removeChild(this.parentElement)` ... So it's a little bit more complicated. But with the few I showed you, you couldn't guess it. – nook Dec 13 '17 at 09:36