skip to Main Content

I’m writing a web app in which some contents are saved in a JavaScript object. The properties of the object can change at runtime, and I need to update the content of the element which display that property.

change data name:
<input id="text">

<button id="btn">change</button>
<div id="content"></div>
<script>
  const search = document.getElementById('text');
  const btn = document.getElementById('btn');
  const div = document.getElementById('content');

  const data = {
    id: '1',
    name: 'element name',
    inStock: true
  }

  div.innerHTML = `
        <div>id of the data: ${data.id}</div>
        <div>name of the data: ${data.name}</div>
        <div>is in stock: ${data.inStock}</div>
    `

  btn.addEventListener('click', () => {
    console.log(data.name);
    data.name = search.value;
    console.log(data.name);
  })
</script>

After clicking the button, I change the property of the object data, and I would like to update the content of the div, and get something like

id of the data: 1
name of the data: new element name
is in stock: true

By locking at the console I see that indeed the property of the object changes, but not the div content.

I tried to solve this issue by replacing the child element

btn.addEventListener('click', () => {
    const newDiv = document.createElement('div');
    newDiv.className = 'name';
    newDiv.innerHTML = `<div class="name">name of the data: ${data.name}</div>`;
    div.replaceChild(newDiv, document.getElementsByClassName('name')[0]);
})

and it works as expected, but I was wondering if it could be done in a more elegant way.

I hope I made myself clear enough, otherwise please ask more in the comments and I will update the question 🙂

2

Answers


  1. Instead of using a template, you can add the HTML to the page itself. And give each div an id and place an empty span in place of the content.

    Then have a single function that takes the data as input and changes the HTML accordingly.

    Then call that function on load and on click of the button.

      const search = document.getElementById('text');
      const btn = document.getElementById('btn');
      const dataID = document.querySelector('#dataID span');
      const stock = document.querySelector('#stock span');
      const name = document.querySelector('#name span');
      const data = {
        id: '1',
        name: 'element name',
        inStock: true
      }
      
      function showData(data){
        stock.innerText = data.inStock;
        dataID.innerText = data.id;
        name.innerText = data.name;
      }
    
      showData(data);
    
      btn.addEventListener('click', () => {
        data.name = search.value;
        showData(data);
      })
    change data name:
    <input id="text">
    
    <button id="btn">change</button>
    <div id="content">
      <div id="dataID">id of the data: <span /></div>
      <div id="name">name of the data: <span /></div>
      <div id="stock">is in stock: <span /></div>
    </div>
    Login or Signup to reply.
  2. Long story short you cant observe an object directly and have events for changes, react for example does it trough a setter function.
    What you can do to be as clean as possible is to put all your html update code in a render function that receives an object, make a needUpdate function that compares the object value with the previous and if needed then call render, and use them to update the object or after doing that.

    the render function you alleady have it, the trick might be in the needUpdate function, youu have 2 approach ways as I can see:

    • If you need to track just shallow changes to object properties, you
      can iterate through object properties (using Object.entries) and set
      them values to another object (aka lastValues), then you can do the
      same but comparing currentValues[prop]===lastValues[prop] to know if
      something changed, this is shallow because if the object eventually
      have a property that is indeed an object with its own properties and
      you change one of these, you wont notice since the object property is
      still the same.
    • If you need to track deep and more complex values (like a tree of
      objects), you colud use JSON.stringify to generate a string
      representation of all the hierarchy and compare it to the
      JSON.stringify(lastValues), this way looks a lot simpler and polish
      but at a cost os proccess that could outcome in hangs if you have a
      lot of changes and a big object

    Done this you will have to:

    1. apply the changes to the currentValues you have to
    2. if(needUpdate(currentValues,lastValues)) render(currentValues)
    3. Object.apply(lastValues,curentValues) //you need to have separated
      references on both objects.
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search