Ticket #2529863 (closed defect)

Reporter


Lee
Opened: 01/24/11
Last modified: 09/27/11
Status: closed
Type: defect
Resolution: fixed

Owner


Satyen Desai
Target Release: 3.4.1
Priority: P3 (normal)
Summary: widget-parent _uiAddChild assumes siblings are rendered
Description:

the _uiAddChild method in widget-parent assumes that nextSibling/prevSibling are rendered if they exist. This may not always be the case. When augmenting widget-parent to use async-queue, the
prev/next siblings do exist on the parent but may not yet be rendered in which case the call to get(BOUNDING_BOX) will throw an error.

Type: defect Observed in Version: 3.3.0
Component: Widget Severity: S3 (normal)
Assigned To: Satyen Desai Target Release: 3.4.1
Location: Priority: P3 (normal)
Tags: widget, widget-parent Relates To:
Browsers: N/A
URL:
Test Information:

using the widget-parent-render-queue plugin here https://gist.github.com/793426 you can see it fail. by uncommenting the call to this.beforeHostMethod('_uiAddChild', this._uiAddChild, host); in the
plugin initializer you can see that it works when checking if the sibling is rendered.

Change History

Satyen Desai

YUI Developer

Posted: 01/24/11
  • milestone changed to 3.4.0
  • priority changed to P3 (normal)
  • status changed from new to accepted

Satyen Desai

YUI Developer

Posted: 07/27/11
  • milestone changed from 3.4.0 to 3.5.0

These are backlog bugs which didn't make it into any of the 3.4.0 sprints. Marking as 3.5.0 backlog for evaluation going into 3.5.0 sprint 1

Satyen Desai

YUI Developer

Posted: 08/23/11
  • milestone changed from 3.5.0 to 3.4.1

Moving back to 3.4.1 (just for reporting/backlog management for now - still need to filter against time available)

Satyen Desai

YUI Developer

Posted: 08/23/11
  • estimated changed from 0 to 1
  • sprint changed to sprint 1

Satyen Desai

YUI Developer

Posted: 09/10/11

Yeah. This make sense in general. I'm assuming in the absence of rendered siblings to render next to, the child renders as the last child (appends itself to parent) and then is moved into the correct location implicitly when the siblings are rendered (siblings will insert themselves before/after the "out of place" child pushing it into the correct place when all children are rendered.).

Am I correct in assuming the only piece of code which you need changed is this:


_uiAddChild: function (child, parentNode) {

...

/* OLD IMPL, WHICH ASSUMES SIBLINGS ARE RENDERED */
/*
if (nextSibling) {
siblingBB = nextSibling.get("boundingBox");
siblingBB.insert(childBB, "before");
} else {
prevSibling = child.previous(false);
if (prevSibling) {
siblingBB = prevSibling.get("boundingBox");
siblingBB.insert(childBB, "after");
}
}
*/

/* NEW IMPL */
if (nextSibling && nextSibling.get(RENDERED)) {
siblingBB = nextSibling.get(BOUNDING_BOX);
siblingBB.insert(childBB, "before");
} else {
prevSibling = child.previous(false);
if (prevSibling && prevSibling.get(RENDERED)) {
siblingBB = prevSibling.get(BOUNDING_BOX);
siblingBB.insert(childBB, "after");
}
}
},

Satyen Desai

YUI Developer

Posted: 09/10/11

Also, can you post your test case which uses your Async Queue plugin, so I can make sure it resolves that test case.

Satyen Desai

YUI Developer

Posted: 09/10/11
  • completed changed from 0 to 0.2
  • remaining changed from 1 to 0.8

Satyen Desai

YUI Developer

Posted: 09/12/11
  • status changed from accepted to infoneeded

Yeah, so just using the Async Queue implementation (with the _uiAddChild override commented out) doesn't bring out the issue (https://gist.github.com/1211940).

I'd imagine you'd need to add children non-sequentially, or in separate operations. As mentioned, if you can post the actual usage of the Async Queue implementation which brings out the bug, I can make sure what we change for 3.4.1 fixes your actual usage. I'll try and come up with an independent repro case in the mean time. thx.

Lee

YUI Contributor

Posted: 09/12/11
  • status changed from infoneeded to assigned

yeah, i'll need some time on this. Its been a while since I filed this bug, i'll have to go back and build a repro case for you. Thanks for looking, i'll get back to you.

Satyen Desai

YUI Developer

Posted: 09/12/11

Nevermind, scanned through the plugin and ParentChild code. So it only impacts children added after render. For children added before render, when the parent is rendered, it just iterates and renders all children without going through the _uiAddChild logic (so, even if they're rendered asynchronously the queue still maintains the order in which they are rendered).

I'd like to see if I can repro the issue without the plugin (since the plugin makes some pretty low-level changes to the child rendering logic, in which case it's arguably fine to overide the _uiAddChild method also). It does seem like something fundamental which needs to be fixed in _uiAddChild, regardless of the plugin. Just need to find the basic code path to break it. I'm thinking adding children out of order (sparsely populating the array) is the way to bring it out.

Satyen Desai

YUI Developer

Posted: 09/12/11
  • status changed from assigned to accepted

Satyen Desai

YUI Developer

Posted: 09/12/11

I can't reproduce the problem with the current API (even when populating items in random order). e.g:

https://gist.github.com/1212192

Looking through the code, it does need someone to modify child rendering behavior to make the child.render() implementation asynchronous, so that when _uiAddChild is invoked, you're not guaranteed that the child has been rendered to DOM:

https://gist.github.com/1212204

So, in this case I think it's fine for your plugin to be overriding _uiAddChild to match the other changes it's making - since it's the one changing the out of the box behavior of child.render().

That said:

a) I don't think it hurts to add the RENDERED check (aside from a bit of a performance hit at large - 1000s of children - scale, which we need to evaluate anyway) to support customizations where children maybe rendered asynchronously I'll add that for 3.4.1

b) Even the fixed _uiAddChild implementation won't handle random async rendering completely. In your case, the order of operations is still maintained for child rendering. We're still rendering Child 1 before Child 2 - it's just that we're rendering them asynchronously. For complete async support, we need to allow children to be rendered asynchronously in random order (Child 2 is rendered before Child 1). This needs deeper changes (as the comment indicates, we need to move the "where to insert" logic into the Child implementation, so that no matter when it's rendered, the logic kicks in) which we can queue up for a future release.

Satyen Desai

YUI Developer

Posted: 09/12/11
  • completed changed from 0.2 to 1
  • remaining changed from 0.8 to 0
  • status changed from accepted to checkedin

Satyen Desai

YUI Developer

Posted: 09/12/11
  • resolution changed to fixed

Added additional check in _uiAddChild, to make sure prev/next sibling
is rendered before trying to insert content relative to it.

NOTE: This fix is not really required for the out-of-the-box parent/child
implementation, but came up because a user had a custom impl. which made
child.render() async [probably a valid usecase for parent/child]. See

Fixes #2529863
View Commit: df315088426ba61b1911bca0c888843588e552e9

Satyen Desai

YUI Developer

Posted: 09/16/11

Added additional check in _uiAddChild, to make sure prev/next sibling
is rendered before trying to insert content relative to it.

NOTE: This fix is not really required for the out-of-the-box parent/child
implementation, but came up because a user had a custom impl. which made
child.render() async [probably a valid usecase for parent/child]. See

Fixes #2529863
View Commit: df315088426ba61b1911bca0c888843588e552e9

Jenny Donnelly

YUI Developer

Posted: 09/27/11
  • status changed from checkedin to closed