Skip to content
Advertisement

Javascript Dynamic Data binding code not working

I am writing code that uses data binding to change the innerHTML of an span to the input of the user, but I can’t get it to work. What it should do is show the input on the right side of the input field on both the input fields, but it doesn’t. Can someone please help me out.

HTML:

<html lang="en-US">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>My Frontend Framework</title>
    </style>
</head>
<body>
    <div>
        <label>Name:</label>
        <input type="text" bit-data="name"/>
        <span bit-data-binding="name" style="margin-left: 1rem;"></span>
    </div>

    <div>
        <label>Lastname:</label>
        <input type="text" bit-data="LastName"/>
        <span bit-data-binding="LastName" style="margin-left: 1rem;"></span>
    </div>
<script src="frontend-framework.js"></script>
</body>
</html>

Javascript:

const createState = (stateObj) => {
  return new Proxy(stateObj, {
    set(target, property, value) {
      target[property] = value;
      render();
      return true;
    }
  });
};

const state = createState({
  name: '',
  lastName: ''
});

const listeners = document.querySelectorAll('[bit-data]');

listeners.forEach((element) => {
  const name = element.dataset.model;
  element.addEventListener('keyup', (event) => {
    state[name] = element.value;
    console.log(state);
  });
});

const render = () => {
  const bindings = Array.from(document.querySelectorAll('[bit-data-binding]')).map(
    e => e.dataset.binding
  );
  bindings.forEach((binding) => {
    document.querySelector(`[bit-data-binding=${binding}]`).innerHTML = state[binding];
    document.querySelector(`[bit-data=${binding}]`).value = state[binding];
  });
}

https://jsfiddle.net/Mauro0294/g3170whc/4/

Advertisement

Answer

I made some changes to the fiddle to get the desired result. The problem was with your logic to refer the elements using the dataset attributes, so I tried to simplify it.

Some notable changes :

  1. Updated the data-bit to use lastName instead of LastName. Made it same as your state.
  2. Used getAttribute to get the value of the data-* properties to correctly get the reference.

I think this is what you’re looking for:

const createState = (stateObj) => {
  return new Proxy(stateObj, {
    set(target, property, value) {
      target[property] = value;
      render();
      return true;
    }
  });
};

const state = createState({
  name: '',
  lastName: ''
});

const listeners = document.querySelectorAll('[bit-data]');

listeners.forEach((element) => {
  const name = element.getAttribute('bit-data');
  console.log('here', element.getAttribute('bit-data'), JSON.stringify(element.dataset))
  element.addEventListener('keyup', (event) => {
    state[name] = element.value;
    console.log(state);
  });
});

const render = () => {
  const bindings = Array.from(document.querySelectorAll('[bit-data-binding]')).map((e) => {
   return e.getAttribute('bit-data-binding');
  });
  //console.log('bindings:', bindings, document.querySelectorAll('[bit-data-binding]'));
  (bindings ?? []).forEach((binding) => {
    document.querySelector(`[bit-data-binding=${binding}]`).innerHTML = state[binding];
    document.querySelector(`[bit-data=${binding}]`).value = state[binding];
  });
}
<html lang="en-US">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>My Frontend Framework</title>
</head>
<body>
    <div>
        <label>Name:</label>
        <input type="text" bit-data="name"/>
        <span bit-data-binding="name" style="margin-left: 1rem;"></span>
    </div>

    <div>
        <label>Lastname:</label>
        <input type="text" bit-data="lastName"/>
        <span bit-data-binding="lastName" style="margin-left: 1rem;"></span>
    </div>
</body>
</html>
Advertisement