Cannot create DocumentFragment storing td, tr or th?
Asked Answered
G

3

6

Is it possible to have DocumentFragments contain tr, th or td tags?

If I do this:

var template = document.createRange().createContextualFragment(
        '<table></table>'
    );

    console.log(template.childNodes);

I get the output of [table].

If I do this:

var template = document.createRange().createContextualFragment(
        '<td></td>'
    );

    console.log(template.childNodes);

I get the output of []!!!?!?

If I do this:

var template = document.createRange().createContextualFragment(
        '<td><p></p></td>'
    );

    console.log(template.childNodes);

I get [p]??!?!?!??!?!??!

And finally if I do this:

var template = document.createRange().createContextualFragment(
        '<span><td></td></span>'
    );

    console.log(template.childNodes);

I get [span] - where's the td gone??!

I don't understand the inconsistency here. Is it possible for document fragments to only hold certain elements? What I would like to do is do something akin to the second this above, and then retrieve the td using querySelector.

Thanks

Ginnie answered 29/3, 2017 at 19:54 Comment(3)
Why are you using document.createRange()… and not just document.createDocumentFragment()? The later can contain just <td>s perfectly well.Occupation
I wasn't awRe there was a difference to be honest.. I was using the former to allow me to specify xhtml direct. Is there a way of doing that with the latter method?Ginnie
@Occupation I just tried it with createDocumentFragment() and get the same result...Ginnie
S
7

Solution 1

Use createDocumentFragment(), create a <td> element, and add it to the DocumentFragment with appendChild():

var frag = document.createDocumentFragment()
frag.appendChild( document.createElement( 'td' ) )
console.log( frag.childNodes )  // output => [td]

Solution 2

Create a <template> element, add HTML content to innerHTML, then get the DocumentFragment from the content property:

var template = document.createElement( 'template' )
template.innerHTML = '<td></td>'
var frag = template.content
console.log( frag.childNodes )   // output => [td]
Swab answered 30/3, 2017 at 8:47 Comment(0)
L
1

I have written a library for doing just this (creating document fragments from an HTML string). It is called html-fragment.

This small library attempts to use the range API (as you are doing), but if the top level node is a node that needs a specific parent node (such as a td), it will attempt to try some other solutions, such as a template if it is supported, otherwise it does it the "old fashioned way" where it wraps it first with the correct parent tag, and then adds the nodes you wanted to the document fragment (without the temporary parent nodes).

You would use it like so:

var html = '<td><p>Hello World</p></td>';
var fragment = HtmlFragment(html);

console.log(fragment.firstChild) //td
<script src="https://unpkg.com/[email protected]/lib/html-fragment.min.js"></script>
Leisure answered 22/5, 2017 at 2:22 Comment(0)
S
-1
const range = new Range()
const tableRange = new Range()

const table = document.createElement('table')
const tbody = document.createElement('tbody')
const tr = document.createElement('tr')
const colgroup = document.createElement('colgroup')

/**
 * https://developer.mozilla.org/en-US/docs/Web/HTML/Element#Table_content
 */
const tableTags = [
  'tbody',
  'thead',
  'tfoot',
  'caption',
  'colgroup',
  'col',
  'tr',
  'td',
  'th'
]


export function createFragment(str: string) {
  const firstTag = str.match(/^<(([a-z]|-)+)/)?.[1]
  if (firstTag && tableTags.includes(firstTag)) {
    switch (firstTag) {
      case 'tbody':
      case 'thead':
      case 'tfoot':
      case 'caption':
      case 'colgroup':
        tableRange.selectNodeContents(table)
        break
      case 'tr':
        tableRange.selectNodeContents(tbody)
        break
      case 'td':
      case 'th':
        tableRange.selectNodeContents(tr)
        break
      case 'col':
        tableRange.selectNodeContents(colgroup)
        break
      default:
        break
    }
    return tableRange.createContextualFragment(str)
  }
  return range.createContextualFragment(str)
}
Stapleton answered 11/9, 2020 at 6:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.