cyberlp
cyberlp

Reputation: 27

Javascript optimization: repetition of a same function

I want to use a getElemendbyId function several times, just by passing the name of the ID as a variable.

I guess there is a more elegant way to do it than:

<div id="1" onclick="myFunction2()"></div>
<div id="2" onclick="myFunction3()"></div>
<div id="3" onclick="myFunction4()"></div>
<div id="4" onclick="myFunction5()"></div>
<script>
function myFunction2() { document.getElementById("2").innerHTML = "test2"; }
function myFunction3() { document.getElementById("3").innerHTML = "test3"; }
function myFunction4() { document.getElementById("4").innerHTML = "test4"; }
</script>

Thanks!

Upvotes: 1

Views: 88

Answers (6)

zer00ne
zer00ne

Reputation: 43920

Event Delegation

Event delegation is a pattern that optimizes event handling by registering an ancestor element of a group of descendant elements. By controlling what is ignored and what is triggered by an event, you can have a single element (ancestor in demo is <ul>/ event.currentTarget) listen for an event (click event in demo) for all of its descendant elements (all of the <li> in demo event.target).


Demo

Details are commented in demo

// Reference an ancestor element
var list = document.querySelector('ul');
// Register click event on ancestor element
list.onclick = clicker;
// Callback function pass the Event Object
function clicker(event) {
  // Reference the clicked element (<li>...)
  var clicked = event.target;
  // Reference the element registered to the event (<ul>)
  var ancestor = event.currentTarget;
  // if the clicked element is NOT the registered element
  if (clicked !== ancestor) {
    // if the clicked element is an <li>...
    if (clicked.matches('li')) {
      // ...toggle the .on class 
      clicked.classList.toggle('on');
    }
  }
}
li {
  cursor: pointer;
}

.on {
  color: gold;
  background: black;
}
<ul>
  <li>ITEM 1</li>
  <li>ITEM 2</li>
  <li>ITEM 3</li>
  <li>ITEM 4</li>
</ul>

Upvotes: 0

Isaac Vidrine
Isaac Vidrine

Reputation: 1666

Here is a solution without using Ids

function myFunction(el, content) {
   el.innerHTML = content; 
}
<div onclick="myFunction(this, 'test2')">Click Me</div>
<div onclick="myFunction(this, 'test3')">Click Me</div>
<div onclick="myFunction(this, 'test4')">Click Me</div>
<div onclick="myFunction(this, 'test5')">Click Me</div>

Upvotes: 0

Tom O.
Tom O.

Reputation: 5941

A more elegant solution than inline on<...> event handlers is to call addEventListener on the parent element (read about event delegation here). Once the listener is registered you can use the event argument to determine what target the user has clicked and what action to be taken, if any.

For example, in the scenario below we evaluate the event to determine if one of our <div> elements were clicked - if so, call myFunction with the appropriate data passed in:

document.addEventListener('click', handleClick)

function handleClick(event) {
  if (event.target.tagName === 'DIV') {
    myFunction(event.target);
  }
}

function myFunction(el) {
  el.innerHTML = `test${el.id}`;
}
<div id="1">Click Me</div>
<div id="2">Click Me</div>
<div id="3">Click Me</div>
<div id="4">Click Me</div>

Upvotes: 1

molamk
molamk

Reputation: 4116

You can use the getElementById and addEventListener functions. It looks like this

[1, 2, 3, 4].forEach(id => {
  document.getElementById(id).addEventListener('click', () => {
    const el = document.getElementById(id + 1);
    if (el) el.innerHTML = `test${id+1}`;
  });
});
<div id='1'>a</div>
<div id='2'>b</div>
<div id='3'>c</div>
<div id='4'>d</div>

Upvotes: 0

Scott Marcus
Scott Marcus

Reputation: 65796

There are a couple of ways to go about this, but in all scenarios you really should not use inline event handling attributes (onclick). There are many reasons not to use this 20+ year old technique that just will not die the death it deserved to almost 10 years ago. Additionally, don't use .innerHTML to get/set values that don't contain any HTML as it is wasteful, in terms of performance and it opens up security holes in your application. Instead, use .textContent to get/set non-HTML values.

For each element to have its own handler:

  1. Get all the elements that need a similar handler into an array
  2. Loop over the array
  3. Assign a handler to the current array element

// Get all the elements that need the same handler into an Array
let divs = Array.prototype.slice.call(document.querySelectorAll("div"));

// Iterate the array
divs.forEach(function(div){
  // Set up the handler
  div.addEventListener("click", function(){
    div.textContent = "test" + div.id;
  });
});
<div id="1">click me</div>
<div id="2">click me</div>
<div id="3">click me</div>
<div id="4">click me</div>

To set up just one handler and use event delegation:

  1. Assign a common handler to an ancestor of all the elements in question
  2. In the handler, act upon the specific element that triggered the event.

// Set up an event handler on the container element
document.querySelector(".parent").addEventListener("click", function(event){
  // Act upon the target of the event (the element that triggered the
  // event in the first place).
  event.target.textContent = "test" + event.target.id;
});
<div class="parent">
  <div id="1">click me</div>
  <div id="2">click me</div>
  <div id="3">click me</div>
  <div id="4">click me</div>
</div>

Upvotes: 1

Sinisa Bobic
Sinisa Bobic

Reputation: 1311

<div id="1" onclick="myFunction(2, 'test2')"></div>
<div id="2" onclick="myFunction(3, 'test3')"></div>
<div id="3" onclick="myFunction(4, 'test4')"></div>
<div id="4" onclick="myFunction(5, 'test5')"></div>
<script>
    function myFunction(id, content) {
        document.getElementById(id).innerHTML = content; 
    }
</script>

Upvotes: 3

Related Questions