How to create components at runtime

I am having trouble creating components at runtime for my kind. The code for this is below. I must be thinking about this all wrong, but I need to add components dynamically as some of the commented code below shows. But I cannot do any of that outside of the create function. Unfortunately due to how everything is set up I will not have access to a variable I need after create is called. Any help on how to add components dynamically outside of the create function would be most helpful!

```
enyo.kind({
	name: "grid",
	kind: "Control",
	published: {
		"align":"",			
		"background-color":"",
		"background-image":"",
		"background-type":"",
		"cols":"",			
		"colWidths":"",		
		"height":"",		
		"margin-bottom":"",	
		"margin-left":"",	
		"margin-right":"",		
		"margin-top":"",		
		"valign":"",		
		"visibility":"",		
		"width":""				
	},
	components: [
		{name: "table", kind:"moo.Table", components: [
			{name:"tablebody", kind:"moo.Tbody"}
		]}
	],
	
/*
 * enyJS Functions
 */
	create: function() {
		this.inherited(arguments);
		
		//Instantiate properties
		this.set("align","left");
		this.set("background-color","");
		this.set("background-image","");
		this.set("background-type","none");
		this.set("cols","");
		this.set("colWidths","");
		this.set("height","");
		this.set("margin-bottom","");
		this.set("margin-left","");
		this.set("margin-right","");
		this.set("margin-top","");
		this.set("valign","none");
		this.set("visibility","true");
		this.set("width","");
		
		// Object to hold all properties
		this.properties = {};



		this.addClass("grid");
	},
	rendered: function() {		
		this.inherited(arguments);
	},
	
	

	// Called bindData to refresh controls with new data and styles
	bindData: function() {
		var countControls = this.getClientControls().length;
		for(var i=0; i < countControls; i++){
			var comp = this.$.tablebody.createComponents([{kind: "moo.Row"}], {owner: this.$.tablebody});
			var comp2 = comp[0].createComponents([{kind:"moo.Data"}], {owner:comp[0]});
			this.getClientControls()[0].setContainer(comp2[0]);
		}
		this.properties = moo.ui.GetProperties(this);
		this.buildStyle();

	},
	
	// Handles application of styles for components
	buildStyle: function() {



		var style = moo.ui.BuildStyle(this.properties,
			"background-type","background-color","background-image",
			/*"height",*/"width",
			"margin-bottom","margin-left","margin-right","margin-top");
					
		var styleThis = moo.ui.BuildStyle(this.properties,"height");
		
		this.addStyles(styleThis);
		// this.$.div.addStyles(style);
		this.setColumnWidths();
		this.handleCustomProperties();

	},
	
	// Handles custom object and style settings based on logical conditions for this control
	handleCustomProperties: function(){
		for(var property in this.published)
		{
			var value = this.properties[property];
			if(value == undefined)
				continue;
			
			if(value == "")
				continue;
				
			switch(property)
			{
				case "align":
					this.addStyles("text-align:" + value);
					break;
					
				case "valign": //top, center, bottom, none 
					this.addStyles(moo.ui.GetValignStyle(value,this.getParent(),this));
					break;
				
				case "visibility":
					moo.ui.Visibility(value,this);
					break;
						
				case "colWidths":

					var colWidths = value.split(",");
					// var totalLen = this.$.div.getClientControls().length;
					// var counter = 0;
					for(var i = 0; i < colWidths.length; i++){
						//for(var i = 0; i < this.cols; i++) {
						//var comp = this.$.colgroup.createComponent({kind:"moo.Col"});
						//}
						//this.$.colgroup.getClientControls()[i].addStyles("width:" + colWidths[i] + "%");	

					}

				break;
			}
		}
	},
	
	setColumnWidths: function() {

		//If columnWidth was not set then we must determine it proportionately
		// var pct = (100/this.cols);
		// if(this.colWidths == "" || this.colWidths == undefined) {
		// 	for(var i = 0; i < this.cols; i++) {
		// 		this.$.colgroup.getClientControls()[i].addStyles("width:" + pct + "%");
		// 	}
		// }

	}
});
enyo.kind({
	name: "moo.Table",
	tag: "table"
});

enyo.kind({
	name: "moo.ColGroup",
	tag: "colgroup"
});

enyo.kind({
	name: "moo.Col",
	tag: "col"
});

enyo.kind({
	name: "moo.Tbody",
	tag: "tbody"
});
	
enyo.kind({
	name: "moo.Row",
	tag: "tr"
});

enyo.kind({
	name: "moo.Data",
	tag: "td"
});

Comments

  • You can certainly make instances dynamically, and my current app does it extensively. I even put in place code to build the instance dynamically by wrapping an existing DOM node.

    I think I understand, but can you put it in a fiddle other can fork. It might be easier to help if the code can be worked with.
  • I am having trouble creating a fiddle (getting it working at least). The code is mostly working though. I just need to know how to add a kind dynamically while not in the create function. While debugging I noticed that the objects were in the this.$.colgroup, but when it outputted it did not appear.
  • after your createComponents code, do a this.render() and see if that works.

    btw, your code seems a bit complicated for what you're trying to accomplish
  • I know it may look that way pasarin, but there is more going on than this one kind. I am only showing this kind because its where i need this special case. But I didn't set up the base framework unfortunately, so I am sure things could have benefited from some more efficient work. It looks like your advice may have helped. My code is a mess right now because I've been working on this all day. But I'll get back to you and let you know if I was able to accomplish what I needed.
  • It worked pasrin! This was annoying the hell out of me.I should probably look at the source, but I assume that render() is called by the parent's create function. This was just something I've been missing about enyo. I really appreciate your time. I know it wasn't very pleasant to sift through my messy code haha.
  • edited November 2013
    render() isn't automatically called after createComponent as an optimization -- you might be creating a lot of components at one time, so we have you manually call render() when you're done instead of wasting time rerendering the control over and over.

    In looking at the API docs, this isn't clear -- http://enyojs.com/api/#enyo.Component::createComponent doesn't mention that because that's describing createComponent at the level of enyo.Component which doesn't know about rendering.

    Our old tutorial has info on it -- https://github.com/enyojs/enyo/wiki/Tutorial -- but it doesn't work since Twitter changed their API.

    (I just filed a bug for us to clarify this)
Sign In or Register to comment.