Как вы клонируете NamedNodeMap элемента в пустой объект?

#javascript #html #object #clone

#javascript #HTML #объект #клонировать

Вопрос:

У меня есть массив объектов JavaScript, где объекты называются text, где каждый элемент объекта содержит информацию об элементе HTML, который выглядит следующим образом, используя область просмотра inspect Source браузера Chrome:

 text:
  attributes: NamedNodeMap
                0: baseURI: "file:.../awesomplete_textarea.html"
                   childNodes: NodeList []
                   firstChild: null
                   isConnected: false
                   lastChild: null
                   localName: "label"
                   name: "label"
                   namespaceURI: null
                   nextSibling: null
                   nodeName: "label"
                   nodeType: 2
                   nodeValue: "Alternative Rock"
                   ownerDocument: document
                   ownerElement: li
                   parentElement: null
                   parentNode: null
                   prefix: null
                   previousSibling: null
                   specified: true
                   textContent: "Alternative Rock"
                   value: "Alternative Rock"
                   __proto__: Attr }
              length: 1
              label: { same content as 0, above }
              __proto__: NamedNodeMap }
  label: "Alternative Rock"
  tagName: "LI"
  value: "Alternative Rock (Alternative)"
  length: 16
  __proto__: String
 

Примечание: Хотя элемент атрибутов текстового объекта (выше) содержит только информацию для атрибута label, он также может содержать другие элементы атрибутов, такие как стиль и / или класс, которые были скопированы из набора <li> тегов на моей веб-странице, и в этом случае будут дополнительные записи в элементе текстовый объект и атрибуты для элементов этих атрибутов.

Когда информационные <li> теги собраны, атрибуты тега копируются в текстовый объект с помощью функции copyAttributes, показанной ниже, которая работает нормально.

Однако, когда позже я попытаюсь использовать ту же функцию copyAttributes для копирования text.attributes в переменную attr, чтобы затем создать новый HTML-элемент, я получаю эту ошибку:

 mycode.js:98 Uncaught TypeError: to.setNamedItem is not a function
  at copyAttributes (mycode.js:98)
  at Function._.ITEM (mycode.js:940)
  at _.item (mycode_textarea.html:625)
  at mycode.js:826
  at Array.forEach (<anonymous>)
  at _.evaluate (mycode.js:825)
 

Следующий код показывает, как выполняется этот вызов, и что я пытаюсь сделать с информацией, скопированной в переменную объекта attr.

 function copyAttributes( from, to ) {
  var attr;

  for( const [ key, value ] of Object.entries( from ) ) {

    if( !isNaN( key ) ) {  // Only add the named attributes ...

      let name = from[ key ].name;;  // get the attribute's name

      if( to[ name ] === undefined ) {

        attr       = document.createAttribute( name ); // Create the attribute.
        attr.value = value.value;                      // Assign its value.

        to.setNamedItem( attr );                       // Add it to to

      }

    }

  }

}

var tagName = 'li';
var attribute = {};

// Copy the text.attributes from the text object to attributes.

copyAttributes( text.attributes, attributes );

// Add the information in the {...} object to the attributes object ...

Object.assign( attributes,
               attributes,
               { innerHTML: label,             // Add these to those just copied.
                 'role':    'option',
                 'id':      'list_'   this.count  
                            '_item_'   item_id,
                 'value':   value } );

// Create the new `<li>` with the original tag's attributes and those added, above.

$.create( tagName, attributes );
 

Проблема, по-видимому, заключается в том, что to параметр функции copyAttributes не является типом NamedNodeMap, поэтому он не поддерживает setNamedItem метод.

Как я могу создать пустую переменную атрибутов этого типа?

Или есть лучший / более простой способ заполнить переменную attributes информацией test.attributes?

Спасибо.

Комментарии:

1. Это звучит как проблема XY . Какова ваша цель? Забудьте о копировании атрибутов и расскажите нам, чего вы пытаетесь достичь.

2. Моя веб-страница использует теги <li>, чтобы указать возможные варианты выбора для пользователя в скрытом списке тегов <ul>, а атрибуты этих тегов <li> копируются в массив объектов. Затем, когда пользователь вводит значения, разделенные запятыми, в текстовое поле, чтобы найти подмножество исходных <li>, отдельные значения, разделенные запятыми, сравниваются со значениями в объектах массива, и совпадения используются для создания новых тегов <li> в другом списке <ul>. Разница между этими двумя списками заключается в том, что второй добавляет дополнительную информацию и атрибуты форматирования к тому, что было найдено в исходных тегах <li>.

3. Я затронул тему копирования атрибутов, потому что я использую библиотеку awesomplete, которая создает выпадающий список с возможностью поиска, из которого пользователь может выбирать значения, вводя значения, разделенные запятыми, в элемент textarea или щелкая по соответствующим значениям в выпадающем списке. Он создает массив из списка тегов <li>, выполняет поиск в них и создает новый список тегов <li>. Однако я хочу изменить эти теги <li>, объединив дополнительную информацию и атрибуты форматирования с тем, что было найдено в исходных тегах <li> .

4. Я вряд ли смогу убедить вас, но ваш подход ошибочен по разным причинам. Например, var attribute = {} вы никогда не создадите NamedNodeMap с помощью метода с именем setNameId , в вашем вызове Object.assign() вы устанавливаете add a value , в то время как вы уже клонировали его для объекта attributes, который вы только что создали. Было бы намного проще создавать li теги в заводской функции. Почему? namedNodeMap Для начала два из них LI практически идентичны.

5. True для ‘var attribute = {}’ . Именно поэтому я спросил о создании такого объекта. Что касается value, это атрибут, который awesomplete ищет для поиска совпадений, но клонированное значение может быть не тем, которое я хочу, поэтому я устанавливаю для него нужное мне значение. Что касается NamedNodeMap двух <li>, которые почти идентичны, это возможно, но не обязательно в каждом <li> . Некоторые добавили информацию и форматирование, которых не будет у других, также у каждого <li> есть уникальное значение и значение метки, из которых пользователь может выбирать. Кстати, как вы выделяете серым свои примеры кода в своих комментариях? фабричная функция?

Ответ №1:

Вот codepen рабочей версии выпадающего списка, который правильно создал элементы тега li и копирует в него нужные атрибуты.

Эта функция создания из плагина Awesomplete, но она была изменена, чтобы не устанавливать фокус на вновь созданный элемент.

 $.create = function( tag, o ) {
  var element = document.createElement( tag );

  for( var i in o ) {
    var val = o[ i ];

    if( i === 'inside' ) {
      $( val ).appendChild( element );
    }
    else if( i === 'around' ) {

      var ref = $( val );

      ref.parentNode.insertBefore( element, ref );
      element.appendChild( ref );

      if( ref.getAttribute( 'autofocus' ) != null ) {
        ref.focus();
      }
    }
    else if( i in element ) {
      element[ i ] = val;
    }
    else {
      element.setAttribute( i, val );
    }
  }

  return element;
};
 

Это мой модифицированный код, который вызывает указанную выше функцию create и присваивает атрибуты.

 if( tagName === 'LI' ) {

  matched = ( inputValue = ( ', '  
                             me.input.value.trim().toLowerCase()  
                             ',' ) )    // Normalize input.value so that the first item can be found.
                           .includes( ', '   value.toLowerCase()   ',' ) ||         // Find the normalized value in the normalized input.value ...
                           inputValue.includes( ', '  
                                                label.toLowerCase()   ',' );        // Find the normalized label in the normalized input.value ...

  Object.assign( attributes,
         attributes,
         { 'role':          'option',
           'id':            'awesomplete_list_'  
                            this.count  
                            '_item_'   item_id,
           'value':         value,                          // Give every option ( li ) a value attribute.
           'aria-selected': matched.toString() } );                 // If a match was found then set aria-selected to 'true'
                                                // else set area-selected to 'false'.

}
else {

  matched = false;

}

newTag = $.create( tagName );

    newTag.innerHTML = label;

if( text.attributes.length ) {

  // Now copy the attributes ...

  copyAttributes( text.attributes, newTag.attributes );

  // Add the rest of the attributes ...

  copyAttributes( attributes, newTag.attributes, true );

}

return newTag;