Problem/Motivation

in attributesToOptions function there is some code to transform attributes names to camelcase, instead we can use dataset directly as it is supported everywhere we support.

https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/dataset

Steps to reproduce

Proposed resolution

Remaining tasks

User interface changes

API changes

Data model changes

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

nod_ created an issue. See original summary.

nod_’s picture

nod_’s picture

for testing you can use


const div = document.createElement('div');
div.innerHTML = `<input 
  type="text" 
  data-autocomplete-input
  data-autocomplete='{"maxChars":3,"path":"http://path"}' 
  data-autocomplete-separator-char="," 
  data-autocomplete-auto-focus="true">`;
const input = div.querySelector('input');
document.body.append(div);

function attributesToOptions() {
  const options = {};
  // Any options provided in the `data-autocomplete` attribute will take
  // precedence over those specified in `data-autocomplete-(x)`.
  const dataAutocompleteAttributeOptions = input.getAttribute(
    'data-autocomplete',
  )
    ? JSON.parse(input.getAttribute('data-autocomplete'))
    : {};

  // Loop through all of the input's attributes. Any attributes beginning with
  // `data-autocomplete` will be added to an options object.
  for (let i = 0; i < input.attributes.length; i++) {
    if (
      input.attributes[i].nodeName.includes('data-autocomplete') &&
      input.attributes[i].nodeName !== 'data-autocomplete' &&
      // Unwanted side effect.
      input.attributes[i].nodeName !== 'data-autocomplete-input'
    ) {
      // Convert the data attribute name to camel case for use in the options
      // object.
      let optionName = input.attributes[i].nodeName
        .replace('data-autocomplete-', '')
        .split('-')
        .map((w) => w.charAt(0).toUpperCase() + w.slice(1))
        .join('');
      optionName = optionName.charAt(0).toLowerCase() + optionName.slice(1);
      const value = input.attributes[i].nodeValue;
      if (['true', 'false'].includes(value)) {
        options[optionName] = value === 'true';
      } else {
        options[optionName] = value;
      }
    }
  }

  return { ...options, ...dataAutocompleteAttributeOptions };
}

in the browser console run this code and then execute attributesToOptions() to see the result of the transformation of the data attributes into an option object. Or you can add that code to a html file and open it might be easier than using the console all the time.

yash.rode’s picture

Status: Active » Needs review
const div = document.createElement('div');
  div.innerHTML = `<input
  type="text"
  data-autocomplete-input
  data-autocomplete='{"maxChars":3,"path":"http://path"}'
  data-autocomplete-separator-char=","
  data-autocomplete-auto-focus="true">`;
  const input = div.querySelector('input');
  document.body.append(div);

  function attributesToOptions() {
    const options = {};
    // Any options provided in the `data-autocomplete` attribute will take
    // precedence over those specified in `data-autocomplete-(x)`.
    const dataAutocompleteAttributeOptions = input.dataset.autocomplete
      ? JSON.parse(input.dataset.autocomplete)
      : {};
    var dataset = input.dataset;
    // Loop through all of the input's attributes. Any attributes beginning with
    // `data-autocomplete` will be added to an options object.
    for( var d in dataset) {
      if(d.includes('autocomplete') &&
        d !== 'autocomplete' &&
        d !== 'autocompleteInput'
       ) {
      var optionName = d.replace('autocomplete', '')
      optionName = optionName.charAt(0).toLowerCase() + optionName.slice(1);
        const value = dataset[d];
        if (['true', 'false'].includes(value)) {
          options[optionName] = value === 'true';
        } else {
          options[optionName] = value;
        }
      }
    }
  return options;
  }

check data type of dataset and d, currently it is var can be changed to let if needed.

nod_’s picture

Status: Needs review » Needs work

There are tests to check the behavior of this function so please update the merge request and make sure the tests are passing :)

yash.rode’s picture

Status: Needs work » Needs review
nod_’s picture

Status: Needs review » Needs work

a few details and it'll be ok to merge.

yash.rode’s picture

Status: Needs work » Needs review
nod_’s picture

Status: Needs review » Needs work

Need to change do the let -> const change in the for loop also

yash.rode’s picture

Status: Needs work » Needs review
yash.rode’s picture

nod_’s picture

Status: Needs review » Reviewed & tested by the community

all good :)

Main change is that using dataset allow us to get rid of this piece of code:

        let optionName = this.input.attributes[i].nodeName
          .replace('data-autocomplete-', '')
          .split('-')
          .map((w) => w.charAt(0).toUpperCase() + w.slice(1))
          .join('');

because with dataset this is done automatically by the browser.

  • nod_ committed 95b66b2 on 1.0.x
    Issue #3229110 by yash.rode, nod_: use dataset instead of getattribute
    
nod_’s picture

Status: Reviewed & tested by the community » Fixed

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.