Join two events that have the same function

Asked

Viewed 1,315 times

4

I am new to programming and I was creating an html code, in which I am calling JS functions in my own input.

Anyway, I have this excerpt, in my input code:

<input type="text" onclick="setTimeout(funcaojs, 1)" onkeydown="setTimeout(funcaojs, 1)">

Note that I repeat a part of the code twice. As I am in search of learning and improving my code, I decided to turn to vcs.

Is there any way I can join the two events together to not repeat the code? something like:

<input type="text" (onclick, onkeydown)="setTimeout(funcaojs, 1)">

I know this example of mine is dumb and it wouldn’t work this way, but I’d just like to know if there’s any way to do it, and if so, how.

I thank everyone who can contribute.

  • I believe that this is not possible if you want to call the same function, but by grouping two events, you have to create an event in the same way for the element and put the function you want to call.

  • @Leandronascimento, can give an example?

  • The first code you wrote on top is what I’m referring to. It’s not possible that you want!

5 answers

4

You can do it like this:

HTML:

<input type="text" onclick="funcao()" onkeydown="this.click()">

JS:

const funcao = _ => alert(1);

But I would do so:

const funcao = _ => alert(1),
input = document.querySelector('input[name="meuinput"]');

['click', 'keydown'].forEach(i => input.addEventListener(i, funcao));
<input name="meuinput" type="text" /">

  • Thanks for the answer, but I think it doesn’t help much, I’m looking for a way to decrease my tag, bringing less code.

4


Cannot do what you want. The sample syntax you demonstrated in the question is invalid.

What you can do is create a function that will encapsulate the entire block of code that you need to execute. After that just reuse the function in several places.

Something like that:

function eventHandler(message) {
  console.log('Hello! From ' + message)
}
<input onclick="eventHandler('Focou')" onblur="eventHandler('Desfocou')" />

Try to focus and blur the input. You are now using the same function for two separate events.


PS: As your code grows, it becomes bad to set events directly in HTML. Apis like addEventListener are recommended, since with them you can set the event directly in the Javascript code.

And it is important to point out that the addEventListener does not accept multiple events at the same time. You need to create the Listener individually for each event.

const el = document.querySelector('button');

function handler(type) {
  console.log('Evento! ->', type);
}

el.addEventListener('mouseenter', () => handler('Entrou'));
el.addEventListener('mouseleave', () => handler('Saiu'));
<button>Passe o Mouse!</button>

  • And with the addEventListener I get something like id.addEventListener('click change mouseup', funcaojs())?

  • No. I edited the question adding more details.

3

I know the question doesn’t have the Jquery tag, but I’ll answer it anyway because I think it’s useful information. Through Jquery you can record multiple events for the same code with the function on. This function takes as its first parameter a string with events to be captured, separated by space.

See an example capturing the event click and keydown in the text box:

$("#texto").on("click keydown", function(){
  console.log("evento lançado");
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type="text" id="texto">

  • Although not Vanilla thought it cool, I did not know this ;)

3

What you can do and take the function out of the tag and make a script associating the element that will have the interaction, so vc can assign several eventListners to the same element.

inserir a descrição da imagem aqui

Below I add several listeners to the same btn, it is not a usual example, but for you to understand how to have several interactions with the element using the same function.

var btn = document.getElementById('btn');
function minhaFunk(){
    document.body.classList.toggle('ativo');
}
btn.addEventListener('mouseover', minhaFunk);
btn.addEventListener('mouseleave', minhaFunk);
btn.addEventListener('click', minhaFunk);
.ativo {background:red}
<button id="btn">clicar</button>

  • Is not possible btn.addEventListener('mouseover mouseleave click', minhaFunk);, how is it possible $(id).on('mouseover mouseleave click', minhaFunk()) in jQuery no?

  • @Edro jQuery is useful precisely at these times when you want to save some lines of code, but underneath the cloths it is very likely that it is creating a Planner for each type of interaction. ES6 has already absorbed a lot of jQuery, but as far as I know it is not possible to do it simply, but here are some guidelines for you to study https://stackoverflow.com/questions/11845678/adding-multiplevent-listeners-to-one-element

2

With HTML syntax it is not possible as it is static. You can even create a preprocessor that does what you want, which would facilitate maintenance, but in the final code would end up being the same thing.

With Javascript, using attributes data

Without breaking the syntax of HTML, with the help of Javascript you could do something like:

<input type="text" data-events="(click, keydown)=funcaojs" />

The code to analyze this could be quite simple or quite elaborate, depending on your needs. In this case, it could be something like:

const elements = document.querySelectorAll('[data-events]')
const pattern = /^\((.*)\)=(.*)$/

for (let element of elements) {
  let config = element.dataset.events
  let groups = config.match(pattern)
  
  if (groups) {
    let events = groups[1].split(',').map(event => event.trim())
    let handler = groups[2]
    
    for (let event of events) {
      console.log(`Adicionando a função ${handler} ao evento ${event}`)
      element.addEventListener(event, window[handler])
    }
  }
}

// Função que tratará os eventos
function funcaojs(event) {
  console.log(`Evento ${event.type} disparado em um ${event.target.tagName}`)
}
<input type="text" data-events="(click, keydown)=funcaojs" />

It is a very simple example and perhaps it is not completely functional to put into production, because my intention was just to make the proof of concept of the solution. You can (and should) adapt it to your needs.

But it is important to note that although it is a simple code it adapts to the amount of elements you have on the page. That is, you can use the same attribute data-events in any element you wish:

const elements = document.querySelectorAll('[data-events]')
const pattern = /^\((.*)\)=(.*)$/

for (let element of elements) {
  let config = element.dataset.events
  let groups = config.match(pattern)
  
  if (groups) {
    let events = groups[1].split(',').map(event => event.trim())
    let handler = groups[2]
    
    for (let event of events) {
      console.log(`Adicionando a função ${handler} ao evento ${event}`)
      element.addEventListener(event, window[handler])
    }
  }
}

// Função que tratará os eventos
function funcaojs(event) {
  console.log(`Evento ${event.type} disparado em um ${event.target.tagName}`)
}
<input type="text" data-events="(click, keydown)=funcaojs" />
<button data-events="(click)=funcaojs">Pressione-me</button>

<h1 data-events="(mouseenter, mouseleave)=funcaojs">Passe o mouse</h1>

Note: I used the function in all events funcaojs to simplify the code and already display the log message on the console, but you can change and define the function you want.

With Javascript, using the prototype

As shown in the other responses, it is possible to add a function to an event through the addEventListener, but it does not accept more than one event, so you need to call the function for each event you want to treat. Or you can benefit from the prototype Javascript, because with it you can define new methods to its elements without necessarily interfering in the natural behavior of the same.

So we can create the function addEventsListener (understand Events plural) so that you accept a list of events for the same function, basically doing what you need:

HTMLElement.prototype.addEventsListener = function (events, listener) {
  for (let event of events) {
    this.addEventListener(event, listener)
  }
}

And with that, we can call the method addEventsListener in any HTML element we wish to pass the event list:

input.addEventsListener(['click', 'keydown'], funcaojs)

It would look something like this:

// Define a função no prototype
HTMLElement.prototype.addEventsListener = function (events, listener) {
  for (let event of events) {
    this.addEventListener(event, listener)
  }
}

// Define a função que tratará os eventos
function funcaojs(event) {
  console.log(`Evento ${event.type} disparado em um ${event.target.tagName}`)
}

// Atribui a função aos eventos
const input = document.querySelector('input')

input.addEventsListener(['click', 'keydown'], funcaojs)
<input type="text" />

Note: the native function addEventListener accepts more than two parameters, so it would be interesting that the defined function addEventsListener treated the same parameters to maintain all types of compatibility between calls. To simplify, I only implemented the first two, which are the event and the function that deals with the same.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.