6

Hi so I created this code that works great.

document.getElementById("file").addEventListener('click', 


function () {

var textArea = document.getElementById("newTextArea");

//Retrieve the selected text :
var selText = window.getSelection();
var text = textArea.innerHTML;
// I need to make a condition here.  If the text doesn't have a span tag then do this: 
if (document.querySelector('.test') === null) {
    textArea.innerHTML = text.replace(selText, '<span class="test">'+selText+'</span>');
// if the text does have a span tag then remove the span tag
} else if (document.querySelector('.test') !== null) {
    var deSelText = document.querySelector('.test');
    var highlightedText = deSelText.innerHTML;
    var parent = deSelText.parentNode;
    var newNode = document.createTextNode(highlightedText);
    parent.insertBefore(newNode, deSelText);
    parent.removeChild(deSelText);
  }
}, false);

But I would like to make the anonymous function into a named function so it looks like this:

document.getElementById("file").addEventListener('click', classAndSpan(test), false);

here is the named function:

function classAndSpan(addClass) {

var textArea = document.getElementById("newTextArea");

//Retrieve the selected text :
var selText = window.getSelection();
var text = textArea.innerHTML;
// I need to make a condition here.  If the text doesn't have a span tag then do this: 
if (document.querySelector('.' + addClass) === null) {
    textArea.innerHTML = text.replace(selText, '<span class="' + addClass + '">'+selText+'</span>');
  // if the text does have a span tag then remove the span tag
} else if (document.querySelector('.' + addClass) !== null) {
    var deSelText = document.querySelector('.' + addClass);
    var highlightedText = deSelText.innerHTML;
    var parent = deSelText.parentNode;
    var newNode = document.createTextNode(highlightedText);
    parent.insertBefore(newNode, deSelText);
    parent.removeChild(deSelText);
  }
} 

I'm missing something because this named function is not working. Do I return something in the function and if so what do I return?

Thanks for the help, very much appreciated.

Ajoy2w
  • 79
  • 1
  • 6
  • Possible duplicate of [How to pass parameter to function using in addEventListener?](http://stackoverflow.com/questions/12024483/how-to-pass-parameter-to-function-using-in-addeventlistener) – Sebastian Simon Jan 26 '17 at 20:18

3 Answers3

8

In order to reference a function (which is what you do with a callback), you simply say the name of the function:

foo

In order to invoke a function, you use parenthesis:

foo();

So, when you write:

document.getElementById("file").addEventListener('click', classAndSpan(test), false);

You are actually invoking classAndSpan right away (even before the addEventListener() method call is invoked) instead of referencing classAndSpan.

Event handling functions (callbacks) are automatically called by the browser, so you can't supply arguments to them. However, if you want to pass an argument to a callback function when the event takes place, you can accomplish this by wrapping your named function inside of an anonymous function or another named function. Then, when the event occurs, the anonymous function (that doesn't have any parameters) will be invoked and it will execute your function call (that does have parameters).

Solution #1 (anonymous function calls named function with arguments):

document.getElementById("file").addEventListener('click', function(){
  // Because you want to pass arguments, you need to wrap this call inside of another fucntion
  classAndSpan(test);
}, false);

var test = "SOME VALUE";

function classAndSpan(addClass) {
  console.log("You called classAndSpan with a value of: " + addClass);
}
<input type="button" id="file" value="Click Me">

Solution #2 (named function calls named function with arguments):

document.getElementById("file").addEventListener('click', wrapper, false);

var test = "SOME VALUE";

function wrapper(){
  // Because you want to pass arguments, you need to wrap this call inside of another fucntion
  classAndSpan(test); 
}


function classAndSpan(addClass) {
  console.log("You called classAndSpan and passed: " + addClass);
}
<input type="button" id="file" value="Click Me">
Scott Marcus
  • 64,069
  • 6
  • 49
  • 71
1

You do not need to invoke the function while you are adding it as an callback for the event Handler. Instead, you need to just reference the function declaration by the function name.

So you need to replace classAndSpan(test) to classAndSpan in the event handler.

document.getElementById("file").addEventListener('click', classAndSpan, false);

Also note that the callback function would receive the arguments from the Event. So, you can access the arguments like the event.Target.yourPropertyName , provided you add the yourPropertyName to the event Target.

Abhinav Galodha
  • 9,293
  • 2
  • 31
  • 41
  • That won't work for the OP because the OP wants to pass an argument to `classAndSpan`. – Scott Marcus Jan 26 '17 at 20:25
  • data can be passed using the `event.Target`, why wouldn't it work if the property is assigned? If an event needs the arguments, it should come from the event arguments. – Abhinav Galodha Jan 26 '17 at 20:28
  • *"provided you add the yourPropertyName to the event Target"*. And, what if the argument has no connection to the `event.target`? This is a brittle solution that limits the scale of the code and doesn't really address the actual question being asked. – Scott Marcus Jan 26 '17 at 20:37
  • *" If an event needs the arguments, it should come from the event arguments."* Says who? There is a difference between "event" arguments and "event handler" arguments. Event arguments are usually provided automatically on the `event` object, not the `event.target`. Event handler arguments have no restrictions whatsoever as to where they come from. That's business logic. – Scott Marcus Jan 26 '17 at 20:58
  • Your answer might be more relevant to the OP question. But in terms of design, the event handler/callback function/Subscriber needs to know minimal details of the Publisher. If the information needs to be passed it should be encapsulated in an abstraction like the Event Arguments object. – Abhinav Galodha Jan 26 '17 at 21:09
  • Your explanation is not accurate for JavaScript. As I said, if the argument is intrinsically related to the actual event or the DOM object, then your suggestion could be valid, but there are a myriad of reasons why the callback argument would not be tied to the event or the event target. JavaScript and the DOM offer a flexibility that is not matched in traditional compiled architectures. Design patterns like publisher/subscriber have many variants. – Scott Marcus Jan 26 '17 at 21:21
  • I would also say that your solution forgets the Open/Closed and the DRY principles. What if the callback will also be needed to be called in non-event situations where the argument must come from other sources. As I said, you suggestion makes a brittle, hard to scale solution. – Scott Marcus Jan 26 '17 at 21:22
  • If it is brittle solution, why does different programming languages and frameworks provide the concepts of Event Arguments? It is an abstraction, if you use it the right way. – Abhinav Galodha Jan 26 '17 at 21:24
  • You just answered your own question. *different* languages and frameworks suggest it. JavaScript is different from just about every other language. This isn't a class-based OO language and classes are where that concept would most likely be applied without a second thought. In those environments, the handler would be part of the class written to describe the event.target in the first place. In JavaScript, there is no such restriction. – Scott Marcus Jan 26 '17 at 21:30
  • Handler is decoupled (open principle), any class can subscribe to the event, that is the basic of Observer design pattern. – Abhinav Galodha Jan 26 '17 at 21:41
  • You are thinking in terms of classes - JavaScript does not use classes. Your suggestion creates a coupling between an object and a callback. The fact that you can couple the callback to other objects simply means that other objects would need to be written in a more brittle way. Also, you forget that since we don't have classes, the argument could be coming from literally anywhere (user input, the result of another function, a DOM element, etc.). I'm just saying that class-based OO design patterns need to be rethought in JavaScript. – Scott Marcus Jan 26 '17 at 21:55
0

What you want to do is pass the function classAndSpan to addEventListener. Currently, you're not passing the function, but rather calling the function immediately and passing what it returns to addEventListener.

Change to this:

document.getElementById("file").addEventListener('click', classAndSpan, false);
Matt Mokary
  • 717
  • 6
  • 13