skip to Main Content

I read about unobstrusive JavaScript and how Javascript should be not explicitly placed inside HTML code.
Fine! But I have these hundreds of search results where I placed click events in the HTML structure because the function is the same, but the arguments passed are totally different from one entry to the next. For example:

<button
  id="button_details_0"
  class="search_details__button" style="background-color:#ffffff;border:none"
  onclick="get_details('002124482_2242.jpg','4','0','Brasil, São Paulo, Atibaia, Inventários e Testamentos, Parte A')"
>
  <span id="search_details_span_0" style="color:rgb(0,102,204)">˅</span>
</button>

Also, when I open the details of a particular entry, the user has the option to get more information. Then, I call another function with even more different options.

The easy way of doing this is to add onclick in the HTML when the page is generated by Perl CGI. If I want to be true to unobstrusive Javascript, what do I place in the HTML to pass all this information to Javascript besides creating a form for each entry?

2

Answers


  1. You can use the data-* custom data attributes for creating the HTML markup and then access the attributes using the dataset property.

    The event listener for the click event on the form is just a general even listener. This will be called if any element in the form is clicked. The advantage is that we only need one event listener for the click event, the disadvantage is that we don’t know what element was clicked…
    But in this case with potentially many buttons I guess it is a good idea.
    Therefor I first test if a button is clicked, and if so, switch on the name of the button. There could be more button with the same name and with other names for calling other functions.

    document.forms.form01.addEventListener('click', e => {
      let button = e.target.closest('button');
      if (button) {
        switch (button.name) {
          case 'button_details':
            get_details(button);
            break;
        }
      }
    });
    
    function get_details(button) {
      console.log(button.dataset.img, button.dataset.place);
    }
    .search_details__button {
      background-color: #ffffff;
      border: none;
    }
    
    .search_details_span_0 {
      color: rgb(0, 102, 204);
    }
    <form name="form01">
      <button type="button" name="button_details" class="search_details__button"
        data-img="002124482_2242.jpg"
        data-id="4"
        data-something="0"
        data-place="Brasil, São Paulo, Atibaia, Inventários e Testamentos, Parte A">
      <span class="search_details_span_0">Buttom</span>
    </button>
    </form>
    Login or Signup to reply.
  2. I would recommend not using data attributes as a substitute; it wouldn’t change much. All it does is shuffle things around a bit, your data is still embedded in your HTML.

    It may be better separation of concerns to extract the data you want to assign to each button into an array (which is probably how you’re retrieving it from a database anyway), and to keep it all in your javascript instead of your html:

    // your function parameters, per button:
    const data = [
      ['002124482_2242.jpg', '4', '0', 'Brasil, São Paulo, Atibaia, Inventários e Testamentos, Parte A'],
      ['125y28512j4123.jpg', '3', '6', 'Lorem Ipsum'],
      ['and_so_on.jpg', 4, 0, 'somewhere']
    ]
    
    
    // add the click handlers for each button, using each entry in data as its params
    const buttons = document.querySelectorAll('.search_details__button')
    for (let i = 0; i < buttons.length; i++) {
      buttons[i].onclick = () => {
        get_details(...data[i])
      }
    }
    
    // just for demo
    const get_details = (a, b, c, d) => {
      console.log(a, b, c, d)
    }
    /* Note the CSS is also best kept out of the html */
    .search_details__button {
      background-color: #FFFFFF;
      border: none;
    }
    
    .search_details__button span {
      color: rgb(0, 102, 204)
    }
    <button id="button_details_0" class="search_details__button" style="background-color:#ffffff;border:none">
      <span>˅</span>
    </button>
    <button id="button_details_1" class="search_details__button" style="background-color:#ffffff;border:none">
      <span>˅</span>
    </button>
    <button id="button_details_2" class="search_details__button" style="background-color:#ffffff;border:none">
      <span>˅</span>
    </button>

    (In real life, for robustness against redesigns you’d probably want label each of those data elements with the corresponding button it belongs to, instead of just simply assigning them in document order, but this is good enough to demonstrate the idea.)

    All that said: only do this if it helps keep things simple.

    If you’re generating this via a CGI script, and the way you’re currently doing it works for you, there’s nothing wrong with the HTML being untidy — doing it the "correct" way would probably make your perl code more complex, and since that’s where you’re doing your maintenance work that may be the part you want to keep as simple as possible, not the HTML.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search