Opened 13 years ago

Closed 12 years ago

Last modified 12 years ago

#1378 closed defect (invalid)

when referencing this.parent it skips a level inside widgets - BUG?

Reported by: ole_ersoy@… Owned by: dylan
Priority: high Milestone: 0.9
Component: Parser Version: 0.3
Keywords: Cc:
Blocked By: Blocking:

Description

I have two widgets. One child and one parent.

<div dojoType="ParentWidget?" id="parent">

<div dojoType="ChildWidget?" id="child">

</div>

</div>

Both widgets have their template string set like this:

templateString: "<div dojoAttachPoint='containerNode'></div>"

Now, if I do this inside postCreate of

the child widget

I get the parent widget:


Inside Child Widget:

postCreate() {

alert(this.parent);

}


However, if I set a reference to the parent widget like this:


dojo.widget.defineWidget(

"ChildWidget?",

Widget,

{

isContainer: true, templateString: "<div dojoAttachPoint='containerNode'></div>",

parentWidget: this.parent, ...


And now do

alert(this.parentWidget);

inside postCreate I get


Alert Box Result:

[object Window]


Attachments (3)

Config.js (3.4 KB) - added by guest 13 years ago.
testViewHandler.html (25.0 KB) - added by guest 13 years ago.
ViewHandler.js (20.6 KB) - added by guest 13 years ago.

Download all attachments as: .zip

Change History (18)

comment:1 Changed 13 years ago by ole_ersoy@…

Additional Notes:

It seems like defineWidget is setting the parent reference to window initially, and then later on in the initialization lifecycle, it sets it to the correct widget parent.

So if I do this inside the postCreate method of the childWidget


postCreate() {

parentWidgetReference = this.parent;

}


I get the result I expect.

comment:2 Changed 13 years ago by ole_ersoy@…

More Notes:

However, it turns out postCreate is called on the child, before it is called on the parent.

Initially I was thinking that I could get properties from the parent that would be fully initialized (Post postCreate), however this is no longer true.

Since postCreate is called on the kid first, I have to call a method on the parent custom method on the parent to make sure the kid is good to go, after the parent's postCreate method has initialized it to the state that I need it to be in.

This could be more sexy.

The parser could first parse the parent.

Call postCreate on the parent, so that the parent's lifecycle is complete before kids are added.

Then call addChild on the parent to add kids. That way the kids get a fully initialized parent, and they can go about their business without the parent being directly involved, only indirectly in that the kids get stuff they need from the parent (IoC pattern / Injection Pattern).

Now the parent does not need to iterate through their children on postCreate to do additional kid processing. (See another enhancement I posted - Just search for ole ersoy)

comment:3 Changed 13 years ago by ole_ersoy@…

I tried looking through the source to see if I could better the parser real quick, but it's written somewhat cryptically, with lots of abbreviations like ltn, etc. which are very easy for initial developer to understand, but requires additional deciphering time by anyone else trying to improve the code base.

It would be great if Dojo had a standard around variable and function naming with the primary goal being easy recognition of what something does/is. Dojo is pretty good at this with functions, but variables could be made a lot clearer. This would do a lot for maintainability and the speed at which dojo could be developed. The dojo compressor optimizes the code anyways right?

comment:4 Changed 13 years ago by ole_ersoy@…

Priority: normalhighest

Just a quick recap of what I wish I could do / Dojo Did vs. what I need to do:

(Note that container, items, and widgets are all Widgets):

A have a container (Widget).

The container has several items(Widgets).

Each item has some widgets in it.

The widgets get information from the container.

So,

Ideally, the parser would call addChild on the container, to add items and at the same time setting a reference to itself as the parent.

This way each item has a parent reference before it starts any of its method calls / initialization.

Then when an item is done initializing, it calls addChild to add widgets and sets itself as a parent reference on each widget.

That way when defineWidget(AWidget, ParentWidget?) { parentReference: this.parent

will contain a valid/expected reference to the widget parent and all the widget's methods can access the parent.

However since this is not how the parser works, I need to do the following.

Allow the parser to create the container and add all the item children.

Then call postCreate on the container to iterate through the kids again setting special properties on each kid that should be set during addChild, because the container is tracking the sequence in which kids are added, and needs to set properties based on this sequence. But I have to remember that since postCreate is called after postCreate on all the kids, I have to revisit each kid later on from the container's postCreate method, in order render the kids because the kids won't have all the information they need until the sequence dependent stuff is set on each kid. The sequence dependent stuff is passed from the container to the widgets via the items, so the call from the last postCreate call on the container has to to obtain widgets from the items and then call the custom render methods on the widgets (Custom because the widgets don't have all the information they need and the time that dojo wants to render them)

Continuing on.....

Allow the parser to add the item's widget children.

Now allow the parser to call postCreate on the item setting the container reference on each widget. This is because postCreate on the widget did not have access to the item's parent yet (We have to call postCreate on the item, which is called after postCreate on the widget).

Now I can finally render all the widgets from within the container's post create method because they have the information they need.

comment:5 Changed 13 years ago by ole_ersoy@…

The more I look at this the more it seems that the lifecycle used for Java Server Faces components is also very applicable here.

If you are interested just google for Java Server Faces...I'm attempting a rewrite of the parser using this as a reference point...

Note that Java Server Faces separates the widget into components and renderers, .... so a component is given a renderer so that it can dispaly itself...seems like this type of thinking was included in the design of dojo widgets as well....

In addition to having validators and converters like JSF has (See one of the other enhancements I posted - with full example) - it may make sense to have components and renderers explicitly instead of widgets ... that way rendering methods are kept separate from widget, and widget reuse will most likely be more straight forward / cleaner....

comment:6 Changed 13 years ago by ole_ersoy@…

OK - I have a basic outline of the activities I think the parser/view-handler should perform, and I'll just post it here in case anyone wants to follow along or add comments:

Step 0: Create the rootWidget

Step 1: Get the first element under the body root

Step2: See if the element name has dojo: in it

Step 3: See whether the element has a dojoType attribute

Step4: if (2or3) Get the widget name from either the element name or the dojoType attribute

Step5: if (2or3) Check whether the widget has a tag name in the dojo.widgets.tags map

Step6: if (2or3) If there is a corresponding tag, get it's full namespace and store it in a variable

If there is no tag raise a NoTagDefinition? exception

Step7 if 6 is exception free

Get all the attributes from the widget element and create a map

Step 8: Add to the attributes map the root widget/component if the widget is topLevel, or the parent widget otherwise...there is an isTopLevel attribute on widgets...is this really necessary... it's a descriptive derived attribute, but what is the use case for it?

Create a widget instance passing in the attributes map to the widgets constructor and allow the widget to initialize its attributes, including setting its parent attribute.

Side Note: consider a new createWidget factory method for this, since I think the current one has a bug

Step 9 Get the widgets template and parse creating a reference to the root node

Step 10: Look for dojoAttachEvents, variable substitution placeholders, and attributes and the dojoContainerNode attribute

Step 11: Hook up event functions to the corresponding event handler on the template node

Step 12: Add tags text node to the text node of the containerNode

Step 13: Parse ${} placeholders and substitute the corresponding attribute value on the widget

If a corresponding attribute value cannot be found raise and exception

Step 14: Call initialize on the widget so it can finish it's initialization

Step 15: Ask the widget whether it is a container

If it is not then continue on the the next widget

If it is then repeat the whole process above for each widget kid found. Once the widget kid has been initialized through step 15, call addChild on the parent widget and add it. Inside the addChild method of widget, have methods that automatically set the widgets parent.

comment:7 Changed 13 years ago by ole_ersoy@…

JSF API:

http://java.sun.com/javaee/javaserverfaces/1.2/docs/api/index.html

I'll use as much of the specification as makes sense in the recode.

This way anyone who understands the JSF specification will have an easy time understanding the approach. This should also inspire groups like Apache myfaces and others to get more involved with Dojo widgets, since they will now have a more compatible way of interacting with them.

Once this work is done I'll do a cross post.

I'm going to provide som additional components with this new ViewHandler? / Parser as well. Such as UIInput as a parent of components that are for input. These component will have a renderer reference that can be updated, substituted, and is client specific.

The package structure used will be as follows:

dojo.presentation.viewhandlers.AbstractViewHandler?

dojo.presentation.viewhandlers.HTMLViewHandler

dojo.presentation.components

dojo.presentation.renderers

dojo.presentation.validators

dojo.presentation.converters

A widget will now be the result of combining a component with a renderer.

The components will support validators and converters as well.

comment:8 Changed 13 years ago by dylan

Component: GeneralParser
Milestone: 0.4
Owner: changed from anonymous to dylan

I totally agree on the interal variable names being sucky when they are short and uncommented. Though in reality the crypticness of the parser is due to some of the longer recusion stuff that I wrote.

I don't know if I can digest all of this and get it into 0.4 in time, but I'll add it for that release.

comment:9 Changed 13 years ago by ole_ersoy@…

Cool

I'm attaching a preview of the dojo.presentation.application.Config Class where I've commented out a reasonable introduction on the direction.

I hope to have a working version of the dojo.presentation framework in a few days, with all the classes unit tested and reasonably robust.

I'll do my best to post documented classes asap, so that the framework becomes easier to digest hopefully in time for 0.4

Incidentally I've allready written a lot on the ViewHandler? that can be used to parse the dom and create a "Widgeted" View

Althought now it can have the following lifecycle steps (Written pseudo java like):

public UIViewRoot createView(context, viewId)

public initView(viewRoot) In case the view needs to be initialized further post create

public validateView() Perform view validation for use during design time and potentially during runtime

public renderView() This could be done during createView by calling component.render() on each component also speeding up rendering by only traversing the dom once

Changed 13 years ago by guest

Attachment: Config.js added

comment:10 Changed 13 years ago by guest

Hmmm...Looks like someone from Exadel has thought along similar lines...

http://www.theserverside.com/tt/articles/article.tss?l=GWTandJSF&asrc=EM_NLN_509409

It's CDDL licensed

comment:11 Changed 13 years ago by Another Related Implementation

Just thought I'd post this as well. It's related material. JMaki....

https://ajax.dev.java.net/getstarted.html

comment:12 Changed 13 years ago by ole_ersoy@…

OK - I don't think that much is going to change in the ViewHandler? of the dojo.presentation framework, so I'll post the ViewHandler? code and the test cases for early review purposes. There's an introduction written at the top of the ViewHandler?.

I now need to finish up some solid examples as well as do the final test cases having the ViewHandler? render a real page.

Changed 13 years ago by guest

Attachment: testViewHandler.html added

Changed 13 years ago by guest

Attachment: ViewHandler.js added

comment:13 Changed 12 years ago by dylan

Milestone: 0.40.5

ok, this is a lot to digest, and I'm going to have to push to 0.5 unfortunately.

comment:14 Changed 12 years ago by bill

Priority: highestnormal
Resolution: invalid
Status: newclosed

Hi. This is a very very long bug chain, so I'll address the original bug summary and then close this bug; if there is still an issue (by which i mean, bug or enhancement), then please open a new bug report summarizing the issue.

First, let's look at this:

dojo.widget.defineWidget(
    "ChildWidget", Widget, {
        parentWidget: this.parent,

This won't work because the code above becomes part of the prototype of ChildWidget? (analogous to becoming part of the class definition in java). Of course, there is no parent for the class itself. Instances of ChildWidget? have a parents, but ChildWidget? itself (the definition of the ChildWidget? widget) does not have a parent.

Now, considering this:

postCreate() {
        alert(this.parent); }

You really shouldn't try to access the parent inside postCreate() because it doesn't make sense when widgets are created programatically:

   var parent  = dojo.widget.createWidget("LayoutContainer", ...);
   var child = dojo.widget.createWidget("ContentPane", ...);
   parent.addChild(child);

Note that the parent is unknown when postCreate() is called.

comment:15 Changed 12 years ago by ole_ersoy

Hi,

I created a new framework to solve this "Life Cycle Issue" + add some enhancements that I called dojo.presentation.

It works more like Java Swing or SWT, with support for programmatic or tag based addition of listeners, validators, converters, and renderers. It also separates the Renderer from the Component, like Java Server Faces does.

Karl Tiedt wanted to learn more so I sent it all to him about a week ago.

Cheers,

  • Ole
Note: See TracTickets for help on using tickets.