Open phillipskevin opened 5 years ago
Options for handling teardowns:
We could owerwrite the removeChild
/appendChild
/etc methods in order to know when to check an elements depth and remove its event handlers and the event handlers of its children in the correct order.
This isn't great because it breaks the goal of keeping this Isolated
.
can-dom-mutate
for DOM manipulationThis isn't great because it breaks the Invisible to users
goal.
One option is to use MutationObserver.takeRecords() at the end of the notify queue.
This would allow us to synchronously find all of the elements that have been removed, and tear down their bindings (and the bindings of their children) in the correct order based on their depth.
The downside of this is that it changes when mutation events are dispatched, which is likely a breaking change. We also aren't sure of the performance of this.
We could use Zones to figure out when to call takeRecords
.
I'm not sure exactly how this would work, but it's another option we could consider.
It would most likely lead to a poor debugging experience, similar to the issues with debugging Angular apps.
Potential issues with this solution:
People using node.firstChild, node.children, etc would have to change their code since the DOM being rendered would contain these extra Comment Nodes.
Something like this would cause problems since the "depth" would be changing:
{{#if(something)}}
<div>
{{/if}}
<p>{{otherThing}}</p>
{{#if(something)}}
</div>
{{/if}}
This will likely cause a performance degredation in stache. We'll need to test to see exactly what scenarios have worse performance and how bad it actually is.
Added benfits of this solution:
We would be able to use these Comment Nodes to show the {{#if(foo)}}
helpers in CanJS devtools. This would be awesome.
There's a related problem to all of this ... it's that observation updates (in the derive queue) should be scheduled in relation to the element they are associated with. In stache, these observations are created with priority of their nodeList+1
.
There's a test that sets this relationship up manually:
This tests this: https://github.com/canjs/can-view-live/blob/70d7de60628b1810b4d803beac5efb4421a6cd05/test/html-test.js#L107
If we are going recreate this, we need some way of making these computes evaluate late. We already have the ability to call [@can.setPriority]()
. Priorities could be an element?
Once an observable's priority is set, should this propagate to its children? For example, say I have a component like:
view: `{{this.fullName}}`,
ViewModel: {
get fullName(){
return this.user.first + this.user.last
}
}
The observable created for {{this.fullName}}
will get its priority set. Then should it similarly make fullName
update "later", same with this.user.first
and this.user.last
if they are derived? This would be some form of "priority pressure". Once an Observation is associated with an element, all other "derivable" observables it reads from should be told to update late.
What if there are conflicts? Say this.user.first
is derivable, but a parent component is reading it? Presumably, whichever is earlier wins. Also, Observation.updateChildrenAndSelf
might solve this.
A related problem is that elements are not always in the page and then they get inserted later. This might be a problem if element-associated tasks are queued and then their element is inserted. We might have to re-arrange the queue.
Could we keep these separate and do a in-page
check and re-insert?
meta.priority
take either an HTML element or a number. Elements will be sorted in document order but run after number priorities. live.html()
and such will set the priority to their "element"live.html()
will use the observation name and a placeholder element
In order to replace can-view-nodelist, we could insert comment nodes in place of live-bound sections. Some details of this will be explained below (and some are not yet figured out), but the high-level details are:
n
) and set the depth of the new element ton + 1
.Put comment nodes in place of live-bound sections
This means that some stache like:
...might return some DOM like:
Use a WeakMap to store the "depth" of elements
Store the depth in the WeakMap when an element is inserted
When an element is inserted, recursively check its parents for an element with a depth, and set the depth of this element to its parent's depth plus 1.
The depth would only need to be stored for elements with bindings that will need to be torn down.
Use this depth to do the teardowns in the correct order
This depth can then be used to replace what
can-view-nodelist
does now.From the can-view-nodelist docs:
How this would work exactly hasn't been totally figured out.
A few options will be discussed in a comment below.