Is there a way to determine if a kind is instantiated or constructed?

edited November 2013 in Enyo 2.4
I was wondering if there's a way to determine at kind level if it's instantiated or if its constructed, so we can determine onership of some of it's components.

Use case: Let's say you create a kind using enyo.kind() on which you can set a variable that defines part of the kind's ui:
enyo.kind({
	name: "myKind",
	otherComponents: null,
	tools: [{
		name: "client"
	}, {
		name: "anotherClient"
	}],
	initComponents: enyo.inherit(function(sup) {
		return function() {
                        this.createChrome(this.tools);
                        sup.apply(this, arguments);
			this.otherComponentsChanged();
		};
	}),
	otherComponentsChanged: function() {
		this.$.anotherClient.destroyClientControls();
		this.$.anotherClient.createComponents(this.otherComponents);
		this.hasNode() && this.$.anotherClient.render();
	}
});
The ownership of those buttons should be different if you use that kind in another kind's components array:
enyo.kind({
	name: "otherKind",
	components: [{
		kind: "myKind",
		otherComponents: [{
			kind: "Button",
			content: "Hello"
		}]
	}]
});
or as a constructed kind:
enyo.kind({
	name: "derivedKind",
	kind: "myKind",
	otherComponents: [{
		kind: "Button",
		content: "Hello"
	}]
});
In the last case, the owner of those otherComponents controls should be the "derivedKind", but in the first case, it should be "otherKind". Of course, you can overwrite otherComponentsChanged to modify ownership, but if there's a way to determine the correct ownership in each case on otherComponent's creation it would be much easier.

There's a way to determine that?

Comments

  • I haven't quite followed all of this, but since you are dynamically creating the components in anotherClient, they will always be owned there. I think you might want to pass the owner property when doing that create:
    otherComponentsChanged: function() {
    	this.$.anotherClient.destroyClientControls();
    	this.$.anotherClient.createComponents(this.otherComponents, {owner: this.getInstanceOwner() || this});
    	this.hasNode() && this.$.anotherClient.render();
    }
    That will make sure that the components are owned by myKind's owner or myKind itself. I THINK, then, that when declaring a new instance of myKind the ownership will be correct.

    Again, I haven't followed this perfectly, let me know if it isn't working for you and we'll puzzle it out some more.
  • Thanks, @sugardave, I was aware of getInstanceOwner(), but I think it's not behaving like I'm expecting, and that's why I'm asking.

    Going back to my previous example, let's say I define the following (working) code:
    enyo.kind({
    	name: "derivedKind",
    	kind: "myKind",
    	otherComponents: [{
    		kind: "Button",
    		content: "Hello",
    		ontap: "helloTap"
    	}],
    	helloTap: function(inSender, inEvent) {
    		alert("hello");
    	}
    });
    But:
    enyo.kind({
    	name: "otherKind",
    	components: [{
    		kind: "myKind",
    		otherComponents: [{
    			kind: "Button",
    			content: "Hello",
    			ontap: "helloTap"
    		}]
    	}],
    	helloTap: function(inSender, inEvent) {
    		alert("hello");
    	}
    });
    Doesn't work, ontap event never get's fired. One would expect that the receiver of the ontap event in the second code should be "otherKind", but it's "myKind", no matter if getInstanceOwner() is used or not. Digging into it, getInstanceOwner is defined as follows:
    getInstanceOwner: function() {
    	return (!this.owner || this.owner.notInstanceOwner) ? this : this.owner;
    },
    Seems that, for whatever reason, it always returns this; maybe because of the "notInstanceOwner" flag?

    In fact, If you look at ContextualPopup.js in the onyx library, you're using a bit hacky solution to workaround this on the popup's action buttons, and it should be easier than that.
  • Okay, I will play around with this, but the first question I have is: Why not just use the components block?
  • It's a pretty complex view that I need to reuse several times, with minor differences and in both mentioned scenarios.

    It has two client areas, one of them is in the toolbar (within other fixed controls, that have associated interactions with other controls in the view) and the other one is the "standard" client area.

    The cleanest way to manipulate this view is having two separate "client areas", and that's why I'm asking
  • There's a couple ways to do this, I think. The first is to test the instance otherComponents with the prototype's otherComponents for equality.
    this.ctor.prototype.otherComponents === this.otherComponents
    If true, then otherComponents came from a derived kind versus the config block of a instance.

    Fiddle: http://jsfiddle.net/s6q9U/

    Another way is to use the subclass feature to "copy" the otherComponents array when a subclass is defined. This is what enyo.Component uses to manage instance components versus kind components.
    myKind.subclass = function(ctor, props) {
    	var proto = ctor.prototype;
    	if (props.otherComponents) {
    		proto.kindOtherComponents = props.otherComponents;
    		delete proto.otherComponents;
    	}
    }
    Fiddle: http://jsfiddle.net/s6q9U/1/
  • Oh, thanks, @theryanjduffy!

    Anyways, I had to make a little change to your second code to make it work, don't now why, as your code works on jsfiddle:
    otherComponentsChanged: function() {
    this.$.anotherClient.destroyClientControls();

    if(this.otherComponents) {
    this.$.anotherClient.createComponents(this.otherComponents, {
    owner: this.getInstanceOwner()
    });
    } else {
    this.$.anotherClient.createComponents(this.kindOtherComponents, { owner: this }); } this.hasNode() && this.$.anotherClient.render(); }
  • Yup. That's what it should have been. Copy/paste error on my part.
Sign In or Register to comment.