View Full Version : initstage issues
Ok, what's wrong with the below code?
As far as I thought, the oninit handler wouldn't be called as the class is declared initstage="defer"... but according to the debugger it is.
Inspecting the object in the debugger reveals that isinited==true. :(
Ideas? am running 3.2cr2
<canvas width="100%" height="100%">
<class name="test" extends="view" initstage="defer">
<method event="oninit">
Debug.write("oninit");
</method>
</class>
<test id="testV"/>
</canvas>
jstretch
06-13-2006, 07:15 AM
From appendix a:
intstage="defer"
Children are not created until completeInstantiation() is called
This doesn't mean that completeInstantiation isn't called by your application without you explicitly calling it. To test this, I put a Debug.write("ci called") in the completeInstantiation method and it output 'ci called' twice in my application, which does not call completeInstantiation anywhere. 'defer' really means 'last'. Everything is eventually instantiated during compile.
jsundman
06-13-2006, 07:23 AM
It's not a good idea to name a class "test", because there already is a <test> class built into LZX. If I remember correctly, that class doesn't get loaded by default, so I don't think there is a conflict here.
As to why the deferred class is getting initted, I don't know. I would be happy to learn the answer.
jsundman
06-13-2006, 07:25 AM
I thought that that was the answer, but when I read the documentation, it wasn't clear on that point. Bad documentation!
I think I'll go file a JIRA task to make sure I clear this up.
jstretch
06-13-2006, 08:19 AM
paou try this also...as a workaround,
<view initstage="defer">
<test />
</view>
My debug statements are showing that the class is getting assigned a 'late' initstage somewhere...I'm fishing around the NodeModel class atm, I could be off target.
I don't think it's anything to do with the class name, since that small example was knocked up to illustrate the issue.... but I'll have a go tommorow morning at renaming it and see what happens.
Unfortunately the workaround isn't gonna help so much either, but thanks anyhow...
perhaps I'll explain a bit better what I need to do:
I have a base class that I derive lot's of stuff from. This base class (and the derived ones) are created dynamically from a dataset (recursively), along with any child nodes (expressed as child nodes in the data)
I just extended this to allow replication of these instances from a second dataset, but of course, the code for creating the children then broke as the replicated views are instanciated by the replicator,
So, I moved the child creation into the oninit handler. And it worked again, but the problem is I also need to delay this child creation (and therefore oninit) until I've done some other stuff with the new instance. therefore I wanted control over exactly where completeInstantiation is called.
According to the docs initstage="defer" is exactly what I'm looking for.
I'll have a browse through the laszlo source tommorow and see if I can debug it, but if anyone else comes up with a solution first then I'd be very grateful :)
in docs here (http://www.laszlosystems.com/lps-3.2/docs/guide/initialization-and-instantiation.html) .. is intstage a typo error?
Synchronous creation
No other code can run until all the children for this instance are created
intstage="immediate"
new classname(parent, args, children, false) or any trailing args are omitted, e.g. new classname(parent, args)
Asynchronous creation
Children for this instance will be put on the LzInstantiator queue and created later.
initstage="early"
initstage="normal"
Children will be created at high priority
initstage="late"
Children will be created at low priority
intstage="defer"
Children are not created until completeInstantiation() is called
Think I found the bug...
The issue seems to be that createChildren in LzNode.as is never called on the offending view (as it has no children, obviously)
It's in create children that the code is set up to skip initialising this view if initstage="defer" or "late" (variable __LZlateinit)
More info.
In the simple test above the backtrace showed that the oninit event is fired from __LZcallinit (which is called recursively, skipping any views with __LZlateinit)
The offending call to the views __LZcallinit comes from LaslocCanvas.as (callinit is duplicated in the node def too, but this view is on the canvas)
LaszloCanvas.as:305..
for ( var i = 0; i<sl; i++ ){
var s = this.subnodes[ i ];
if ( s.isinited || s.__LZlateinit ) continue;
s.__LZcallInit( );
}
However, as the view has no children, __LZlateinit is never defined on the object.
Next I need to figure out what the actual desired behaviour is, as I think initstage should really act the same on the view whether or not it has children.
ok, one more thing....
in LzNode.as:98
if the view has no children then __LZinstantiationDone is called, which should call __LZcallinit on this view (looking at the code)
this code (for whatever reason) is NOT the one that initialises the view (look at the trace below), it definately comes from the canvas.
So, any laszlo guys comment on this? for now I can just add an empty subview in my class to get it to work correctly, but not the most effecient solution, considering this will exactly double my view count ;)
0: «__LzStackFrame#28| LzEvent.sendEvent.apply(#LzIdle.onidle, [317])»
1: «__LzStackFrame#32| LzInstantiator.checkQ.apply(#LzInstantiator, [317])»
2: «__LzStackFrame#35| LzInstantiator.makeSomeViews.apply(#LzInstantiator , [, 500])»
3: «__LzStackFrame#39| LzCanvas.__LZinstantiationDone.apply(«LzCanvas#37| This is the canvas», [])»
4: «__LzStackFrame#42| LzCanvas.okToInit.apply(«LzCanvas#37| This is the canvas», [])»
5: «__LzStackFrame#45| LzCanvas.__LZcallInit.apply(«LzCanvas#37| This is the canvas», [])»
6: «__LzStackFrame#48| LzNode.__LZcallInit.apply(#testView, [])»
7: «__LzStackFrame#51| LzEvent.sendEvent.apply(#testView.oninit, [testClass id: testView ])»
8: «__LzStackFrame#54| «Function#52| $playpen$2Elzx_4_26_$m18».apply(#testView, [testClass id: testView ])»
9: «__LzStackFrame#57| Debug.backtrace.apply(#Debug, [])»
AAAAARGH!
Ok, so adding the <view/> into the class worked... the oninit method is called only if I add a completeInstantiation()!!
I think YAY!
I try it with replication, and it fails.
I think ARRGGH (again)
I get two oninits from the "NORMAL" class, and none from the "DEFER" class.
If I take out the datapath it works OK, and I get oninit from both.
any ideas, anyone?
<canvas width="100%" height="100%">
<dataset name="testDS">
<object name="1"/>
<object name="2"/>
</dataset>
<class name="testClassDEFER" extends="view" initstage="defer">
<method event="oninit">
Debug.write("oninit defer");
Debug.write(Debug.backtrace())
</method>
<view/>
</class>
<class name="testClassNORMAL" extends="view">
<method event="oninit">
Debug.write("oninit normal");
Debug.write(Debug.backtrace())
</method>
<view/>
</class>
<testClassNORMAL datapath="testDS:/object"/>
<testClassDEFER id="testView" datapath="testDS:/object"/>
<script>
testView.completeInstantiation();
</script>
</canvas>
As the documentation says, initstage controls the priority with which children of a node are made, not the priority of the node itself.
You can argue whether this is a good API or not, but the API is operating the way it is documented (and was designed).
vBulletin® v3.8.4, Copyright ©2000-2012, Jelsoft Enterprises Ltd.