Famous/framework

$repeat does not play nice with HTML elements

Opened this issue · 4 comments

It is not possible to $repeat a component that has a HTML element as an ancestor.

Example tree:

<node>
  <section id="i-will-break-you">
    <node>
      <node id="please-repeat-me"><span>Never!</span></node>
    </node>
  </section>
</node>

Results in error:
Uncaught Error: ParentNode with UIDnulldoes not exist. Unable to process $if/$repeat


Similarly, it is not possible to $repeat a HTML element.

behaviors: {
  '.item': {
    '$repeat': '[[identity|products]]'
  }
},
states: {
  products: [1,2,3,4]
},
tree: `
<node>
  <div class="item"></div>
</node
`

Will result in this error: Uncaught Error: No dependencies found fordiv (null)`

My instinct is we will need to do some refactoring to address this in full. We have very basic support for targeting DOM elements directly with behaviors, but there many are cases like this one that will result in an error.

The workaround for the time being would either be to: (a) wrap the element you want to $repeat in a <node> (although that obviously isn't ideal as it adds superfluous nesting) or (b) use a content behavior and repeat by returning a string with the accumulated elements, e.g.:

behaviors: {
    '#listing': {
        content: function(products) {
            var out = '';
            for (var i = 0; i < products.length; i++) {
                out += `<div class="item">${products[i].name}</div>`;
            }
            return out;
        }
    }
},
tree: `
    <node id="listing"></node>
`

For posterity it's worth noting that that example will only work with
inner-html as the behavior.
On Jul 2, 2015 8:17 AM, "Matthew Trost" notifications@github.com wrote:

My instinct is we will need to do some refactoring to address this in
full. We have very basic support for targeting DOM elements directly with
behaviors, but there many are cases like this one that will result in an
error.

The workaround for the time being would either be to: (a) wrap the element
you want to $repeat in a (although that obviously isn't ideal as
it adds superfluous nesting) or (b) use a content behavior and repeat by
returning a string with the accumulated elements, e.g.:

behaviors: {
'#listing': {
content: function(products) {
var out = '';
for (var i = 0; i < products.length; i++) {
out += <div class="item">${products[i].name}</div>;
}
return out;
}
}
},
tree: <node id="listing"></node>


Reply to this email directly or view it on GitHub
#42 (comment).

^ 'content' will work when applied to a <node> component, as shown in my snippet. But you are correct in noting that if you are targeting a DOM element, you would use 'inner-html' to render raw HTML.

A major downside of this approach is that Framework does not register events to HTML inserted by content or inner-html. It's only really useful for inserting static content.