How to add a dynamically created HTML element to a control

edited August 2013 in Newbie Questions
Hi!

I want to create HTML objects inside an enyo.Control using the usual syntax ilk of document.createElement('p')
and then insert them in a div in the same enyo.Control in a fashion similar to myobj.innerHTML = document.createElement('p')

In my complete HelloWorld example below, I create a paragraph and put the 'Hello World' text in it as follows:
var paragraph = document.createElement('p');
p.innerText = this.text;
However none of the following work to actually insert the dom element into the prescribed contentArea div:

This does not work:
this.$.contentArea.setContent(p);
Nor does this:
this.$.contentArea.innerHTML = p;
How is this actually done?

I've actually got a complex table dynamically rendering itself from json that is passed to the enyo.Control, however having done all of that, I can't find out how to render it, please help! :)

My Complete Hello World Example Code (not working hence requires a solution) is far below, but regarding my table ambition, I have also tried altering the following:
 { tag: "span", name: "contentArea", style: "background-color:red;" }
To

 { tag: "table", name: "contentArea", style: "background-color:red;" }
but when I go
var firstRow = this.$.contentArea.insertRow(0);
I get an error saying that insertRow is not defined.

If someone can solve the ExampleDOMCreation example below, I'll be able to run with that ~ or if they have a more complex example based upon the above tag = 'table' snippet above, I'd appreciate that,

Kind regards,

Anthony

HELLO WORLD EXAMPLE
enyo.kind({
    name: "ExampleDOMCreation",
    kind: enyo.Control,
    tag: "div",
    style: "border-style: solid; border-width: 2px; " +
            "padding: 10px; margin: 10px; min-height: 50px; border-color: red;",

    published: {
        text: "",
    },

    components: [
        { tag: "span", name: "contentArea", style: "background-color:red;" }
    ],

    create: function () {
        this.inherited(arguments);
        this.textChanged();
    },
    textChanged: function () {
        
        var paragraph = document.createElement('p');
        p.innerText = this.text;
        this.$.contentArea.setContent(p);
    }
});

var eg = new ExampleDOMCreation({
    text: "Hello World"
});
eg.renderInto(document.body);

Comments

  • any specific reason you can't do (you'd have to add an "allowHtml:true" to your first component):
    var myHtml = "This is a 
    ?

    If not, you may want to look into the hasNode() functionality. Perhaps add a function named "rendered" where you do something like var myNode = this.$.contentArea.hasNode(). myNode will contain the actual node to contentArea, to which you can add your elements.

    I believe insertRow won't work because the kind has no function called insertRow.

    If you set up a jsFiddle, we can tinker with and get something more concrete.
  • edited August 2013
    Hi pasrin, thanks for your comments - they have become my solution!

    The reason why I wanted to do the dom createElement method is that it's more elegant, however your method works very well indeed in it's absence. I'll post the solution here for the assistance of others.

    An example of the json passed to the component's text value (auto-generated on the server from a server-side object's columns, this example is 3 rows by 3 columns in dimension but it could be any amount of rows with any amount of columns) is:
    {"construct":{"columns":3,"rows":3},"rows":[{"cells":[{"value":"0-0"},{"value":"0-1"},{"value":"0-2"}]},{"cells":[{"value":"1-0"},{"value":"1-1"},{"value":"1-2"}]},{"cells":[{"value":"2-0"},{"value":"2-1"},{"value":"2-2"}]}]}
    
    The mission of the control itself is to auto-generate the table no matter how many columns or rows, and the fuller solution (not shown) adds to the json so that each row has it's css class assigned to it for proper rendering.

    The code (with minimal refactoring that only removes a little private business intelligence) is:
    
    
        enyo.kind({
            name: "AutoTableGenerator",
            kind: enyo.Control,
            allowHtml: true,
            content: "",
    
            published: {
                text: "",
                tableJson: "",
                columns: "",
                rows: ""
            },
    
            create: function () {
                this.inherited(arguments);
                this.textChanged();
            },
            textChanged: function () {
                this.setConstruct();
                this.buildTable();
            },
            setConstruct: function () {
                var tableJsonText = eval("(" + this.text + ")");
                this.tableJson = eval("(" + tableJsonText + ")");
                this.columns = this.tableJson.construct.columns;
                this.rows = this.tableJson.construct.rows;
            },
            buildTable: function () {
    
                var tabletxt = "";
    
                for (var rownumber = 0; rownumber < this.rows; rownumber++) {
                    tabletxt += "";
                    for (var columnnumber = 0; columnnumber < this.columns; columnnumber++) {
    
                        try
                        {
                            tabletxt += "" + this.tableJson.rows[rownumber].cells[columnnumber].value + "";
                        }
                        catch (err) {
    
                        }
                    }
                    tabletxt += "";
                }
                tabletxt += "";
                this.content = tabletxt;
            }
        });
    
    
    Implementation:
    var instance = new AutoTableGenerator({
        text: JSON.stringify(jsonFromServer)
    });
    instance.renderInto(document.body);
    
  • edited August 2013
    Instead of this.content = tableTxt, use this.setContent(tableTxt). That will trigger a DOM update if the control has already been rendered.

    Also, I'd favor using enyo.json.parse() instead of eval, since that uses the JS environment's JSON.parse call which is safer, since it won't actually run any JavaScript code.
  • Also, instead of html strings, you can dynamically add components (addComponent) in the appropriate structures.
Sign In or Register to comment.