Question

I need to make a data table for an enyo project I am working on that will ultimately display the result of an Ajax call. This (Blatantly stolen from ryanjduffy here)seems to be a good starting point, but when I try to call setData() from a button event (rather than in the constructor) as I have here I get the following error:

InvalidCharacterError: String contains an invalid character @ http://enyojs.com/enyo-2.1/enyo/source/dom/Control.js:681

I looked at the Control.js code and it seems that it tries to create a new node, but the this.tag property is set to null and things break.

I feel like I am missing something really simple, but I just can't see the problem yet...

Can someone tell me what I am doing wrong?

Thanks!

EDIT 1:

Apparently calling render() is not needed. Here is the original working version with render() commented out. Everything looks great. However, if I try to remove render() from the version that requires a button click, the repeater starts creating div's above the table instead of tr td's inside the table...

EDIT 2:

Basically, from what I can tell, the Repeater inside of a table will lose it's parent once the table is rendered (or something like that). The result is the Repeater will start rendering its new items outside of the original table and because a td tag without a table makes no sense, it just renders a div. The solution I have come up with is to give the Repeater itself a table tag so its children always wind up in the right spot. This adds the challenge of needing to recreate the header line each time, but it is not that big of a deal. I have a working example if anyone is interested.

Was it helpful?

Solution

I'm sure you're not looking for a solution any longer but since I was mentioned in the post, I thought I'd let you know what I figured out. In short, my code shouldn't have worked but since browsers are forgiving, it did ... sort of.

When the code run at create time, it renders something like this:

<table>
  <tr> <!-- header row --> </tr>
  <div> <!-- repeater tag -->
     <tr> <!-- repeater row --> </tr>
  </div>
</table>

The browser looks at that and says, "Hey, dummy! No <div>s in a <table>" and kicks it out but leaves the <tr>s.

In your example, since you're delaying the render of the rows, Enyo renders:

<table>
  <tr> <!-- header row --> </tr>
  <div></div>
</table>

And the browser ejects the <div> and you're left with an empty table. When you later set the data, those rows are rendered into the div. Unfortunately, since you're rendering <tr> and <td>, those aren't valid outside a table so you just get text.

I found a couple solutions. The simplest was to set the tag of the Repeater to be TBODY which is allowed inside a table. The slightly more involved solution was to make the DataTable inherit from Repeater and set the header row to be chrome so they're not removed when updating the data.

Option #2 Fiddle

enyo.kind({
    name:"DataTable",
    tag: "table",
    kind: "Repeater",
    published:{
        map:0,
        data:0
    },
    handlers: {
        onSetupItem: "setupItem"
    },
    components:[
        {name:"row", kind:"DataRow"}
    ],
    create:function() {
        this.inherited(arguments);
        this.mapChanged = this.dataChanged = enyo.bind(this, "refresh");

        this.refresh();
    },
    refresh:function() {
        if(this.map && this.data) {
            this.buildHeader();
            this.setCount(this.data.length);
        }
    },
    buildHeader:function() {
        if(this.$.header) {
            this.$.header.destroyClientControls();
        } else {
            this.createComponent({name:"header", tag:"tr", isChrome: true});
        }

        for(var i=0;i<this.map.length;i++) {
            this.$.header.createComponent({content:this.map[i].header, tag:"th"});
        }

        this.$.header.render();
    },
    setupItem:function(source, event) {
        for(var i=0;i<this.map.length;i++) {
            event.item.$.row.createComponent({content:this.data[event.index][this.map[i].field]});
        }

        event.item.render();

        return true;
    }
});
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top