Pass Element ID from one function to another in the same closure

Certainly not. :joy: Kind of you to say though

1 Like

That sounds like a lot of calls to a function that may or may not be needed. There’s an event listener set for the entire Container. Is there really no way to call function (e) when and only when someone was to click on click me

No the opposite is true. My method attaches only one event listener but you are adding multiple listeners. It is better practice to just add the one event listener to the parent. All events bubble up through every element anyway.

The main point of adding the event listener to the parent is that it will work with newly created elements also. Your method means that you have to create the element and then add an event listener each time you create it which is awkward.

button id=“1” onClick=“reply_click(this.id)”>

Inline event handlers like the above are very bad practice and should be avoided at all costs. You should use event listeners from the js file and not dirty the html with your js. (Notwithstanding the above points you requested that you wanted the id of a different element to the one clicked as well so that approach is not going to work for you anyway. You’d still have to find the other element(s).)

Both of what I suggest above are accepted best practices for js so it makes sense to use those methods.

There is no benefit in your this.id argument anyway because you can get that in my version from the function with the event target id.

I believe what I have given you does everything you want so I’m not sure what is troubling you? I would advise you try to follow the approaches mentioned to achieve your goal.

Of course the code offered by @rpg_digital is much better and worth pursuing just for the learning curve. :slight_smile:

I will also (later today) tidy up my code to use better variable names which is something I have mentioned a couple of times now.

2 Likes

Just for example only I created an event listener each time you add the element and it would look like this.

The difference being from my other example is that if you are adding loads of elements then you are also loading loads of event listeners which is wasteful when one could do the job.

However it may help in you understanding how it works.

The event listener is created when you create the element.
z2.addEventListener("click", z2Handler, false);

The z2Handler is run when that element is clicked.

function z2Handler(e) {
    var index = e.target.id.slice(-1);
    var theInput = d.querySelector("#" + textDescription + index);
    theInput.classList.add("highlight");
    e.target.classList.add("highlight");
  }

The (e) is the event that was triggered when the element was clicked and e.target will tell you what element that was and you can retrieve the id or whatever from that element.

Hope that makes it a little clearer to understand :slight_smile:

It would also be worth noting that the html you create is created in the correct manner so that you can do what you want more easily. If you are grouping things that go together then they should have a common container rather than just adding stuff here, there and everywhere. Also note that a lot of the highlighting could most likely be done with css in the right structure and just a little js.

That’s the reason why you should build the template in pure html and css first before you break it down into JS. In that way you can make sure it does all you want before you event start programming :slight_smile:

1 Like

I concur :slight_smile:

I think a good idea would be for @cssissimple to layout in HTML a complete before and after. The brief is a bit unclear right now.

1 Like

Yes, it seems like the goalposts move a little at each twist and turn and I probably don’t help a lot with my basic js approach :slight_smile:

1 Like

let nodes = document.getElementById('container').childNodes;
nodes is live.
This means that as elements are added as children of the container element it is updated and includes the added element.
Depending upon how each element is added it should be easy to find the added element in the nodeList and do whatever you want with it.
Even attaching an onchange event listener to the nodelist.

1 Like

Which way do you think is better for performance?

I can see the value of using a template string. I wonder if one is better than the other?

I.e. can the browser parse and generate the HTML faster with the variable and append technique or the template string technique you used in your example.

I can see how a template string could be easier to read.

Performance is only relevant when a human will notice the difference, which is usually a difference of 300 miliseconds or more. Anything less than that is smaller than the space between a double click, and won’t be noticed.

I would estimate that if there is any performance difference at all, it’s closer to the 1 millisecond mark than 300, and in favour of the single parent event rather than potentially hundreds of others on the page.

That the inline events also clutter up the HTML code is only another downside against that technique too.

However, if you’re really keen about performance we can run up some comparative measurements for you if you like.

2 Likes

If we had 10,000 lines of code for each is there a real difference?

I’m just trying to figure out if the only difference is the readability factor.

I think when you are at that point you may need to be considering optimization.

I found this test online set up by someone else. I don’t know if it is a decent test or not, but my results in firefox and chrome came in with insertAdjacentHTML in the lead over createElement. In firefox by some margin.

1 Like

Templates are just such a nice way to work. Here’s an example I have just been playing with to make a mock football stats table.

The big advantage is you can create and style your html and css first. Then once you are happy it is simply a case of copying and pasting that html into your javascript.

Player stats table row template:

const playerStats = ({name, goals, assists, apps}) => (`   
  <tr>
    <td class='name'>${name}</td>
    <td>${goals}</td>
    <td>${assists}</td>
    <td>${apps}</td>
  </tr>
`)

Main table template:
This is the main table and for the table body it will loop through the passed in players using the above playerStats table row template to output the html — One template within another.

// table
const teamTable = (team, players) => (`
  <table>
    <caption>${team} Player Statistics</caption>
    <thead>
      <tr>
        <th>Player</th>
        <th>Goals</th>
        <th>Assists</th>
        <th>Appearances</th>
      </tr>
    <thead>
    <tbody>
      ${
        players.map(playerStats).join('')
      }
    </tbody>
  <table>
`)

Players data:
Some data to pass into the main table template

const squad = [
    { name: 'Emile Smith Rowe', goals: 9, assists: 2, apps: 15 },
    { name: 'Bukayo Saka', goals: 7, assists: 4, apps: 21 },
    { name: 'Gabriel Martinelli', goals: 4, assists: 2, apps: 11 },
    { name: 'Martin Ødegaard', goals: 4, assists: 3, apps: 17 }
]

And finally output

document
  .querySelector('#container')
  .insertAdjacentHTML('afterbegin', teamTable('Arsenal', squad))

codepen

Modules
I think the nice thing as well is that these templates can be exported and imported as modules. So for instance you could work like this instead.

playerStats.js

export const playerStats = (props) => ( `
    ...
`)

teamTable.js

import playerStats from './playerStats.js' 

export const teamTable = (team, players) => (`
    ...
    ${ players.map(player => playerStats(player)).join('') }
    ...
`)

mainScript.js

import teamTable from './teamTable.js' 

document
  .querySelector('#container')
  .insertAdjacentHTML('afterbegin', teamTable('Arsenal', squad))

I would say from what little I know so far — albeit minus the clever optimizations — not a million miles away from working with React components and JSX.

1 Like