Comments (6)
@elbywan thanks - I've been able to track it down, now that you've proven that it does work. By default Baobab uses immutable: true
, which uses Object.freeze
. This was causing issues for me, with the tree not updating at all when modifying the model data. What I did before, was 'unfreeze' the data using Lodash's cloneDeep
, which worked - at the expense of added overhead, and indeed, complete re-rendering of the tree.
At the time, I did not think there was any difference between immutable edits and completely cloned trees to be honest. Now I switched to immutable: false
(which apparently is recommended during production anyway) and all is well!
from bosket.
Using Angular, I modified the input variable for the model, but change detection is not happening.
That's because the TreeView component uses the changeDetection: ChangeDetectionStrategy.OnPush
which prevents updates unless an event is triggered or if an input variable reference change (mutating objects do not trigger the change detection since the object reference stays the same).
Did you try using a ChangeDetectorRef to update the tree view after mutating the model ?
// Inject the ChangeDetectorRef
constructor(private _cdRef ChangeDetectorRef, /* ... */){}
update(){
// should update the tree view
this._cdRef.markForCheck()
this._cdRef.detectChanges()
}
Or you could try replacing this.model = JSON.parse(JSON.stringify(this.model))
with this.model = [ ...this.model ]
which is in my opinion a little bit more elegant ! (but it will only change the top reference, I'm not 100% sure it will solve the issue since your mutation is nested)
from bosket.
Thanks for the info! Your recommendation for a copy of the model is much better. I'm fine with that.
For the best performance it would be better to get the tree node (as a reference by it's ID) and set there only the model. Then the whole tree would not have to be updated but only the sub tree. Don't know if this will be relevant, since I assume that updating the whole tree in most cases already is efficient enough.
I would love to see some useful functions in the TreeView, like "getNodeById(id)" and "expandPath(id1, id2, ...)", where the latter one returns a promise, so that I know when expand is finished (when using asynchronous children). It's probably a topic for another ticket, but I'd like to know your opinion about it. I find it quite difficult to implement something like this in a bulletproof way ... for example expand a deep node path and afterwards select some node there.
Thanks so far!
from bosket.
Hey @awallat, thanks for the feedback
For the best performance it would be better to get the tree node (as a reference by it's ID) and set there only the model. Then the whole tree would not have to be updated but only the sub tree.
The problem with this approach is that nodes are not rendered when folded. If you want to add a node dynamically, you could retrieve the related framework component node and refresh it manually, but nothing guarantees you that the node actually exists !
I think a good compromise if you want to optimize performance is updating the subtree and its direct ancestors in an immutable style. This way you don't have to meddle with the framework components, you just take advantage of the change detection algorithm.
I added the add and path functions which can do just that :
import {Β tree } from "@bosket/tools"
let model = [
{ label: "a", children: [
{ label: "b" },
{ label: "c" }]
},
{ label: "d" },
{ label: "e", children: [
{ label: "f" },
{ label: "g", children: [
{ label: "h", children: [
{ label: "i" }
]}
]}
]}
]
// element "h"
const h = model[2].children[1].children[0]
// Returns the ancestors of the element "h" and itself
console.log(tree(model, "children").path(h).map(_ => _.label))
// also works with a matching function
console.log(tree(model, "children").path(_ => _.label === "h").map(_ => _.label))
// -> ["e", "g", "h"]
// Add "z" to the tree at position "h", with each ancestor reference updated
// Triggers angular change detection for only the relevant subtree
model = tree(model, "children").add(h, { label: "z" })
// also works with a matching function
model = tree(model, "children").add(_ => _.label === "h", { label: "z" })
I would love to see some useful functions in the TreeView, like "getNodeById(id)" and "expandPath(id1, id2, ...)", where the latter one returns a promise
I'm not too keen on exposing functions in angular components.
I'd rather empower the (framework agnostic) model tree which in turn should trigger the component(s) update.
About getNodeById(id)
if it's about retrieving the TreeViewNode instances, devs can already access them by using @ViewChildren / @ContentChildren. If it's about retrieving a node from the model tree, the new path
method should cover the use case.
About expandPath(...ids)
, I will add another function (soon @bosket/tools
tree.js
file which returns a promise after unwrapping X nested asynchronous children (promises).
Thanks again for your input, I hope that these answers are helpful !
from bosket.
I'm using Riot instead of Angular, and even though I can update the tree dynamically (my tree model uses an immutable data structure through https://github.com/Yomguithereal/baobab), the issue I'm having with updating the whole tree like that, is any unfolded/open nodes are closed again when the model changes.
What happens is similar to this setup: https://jsfiddle.net/b5wpavyx/
A workaround would involve being able to capture the open state of the tree, and reapply this after the tree (model) updates. Would this be a valid approach?
from bosket.
I didn't check explicitely with baobab, but with this setup using riot and the provided immutable tree.add
method I cannot reproduce your issue :
fiddle (Unfold 5, then 8, then click the button to add dynamically)
A workaround would involve being able to capture the open state of the tree
It would be tough, because the "expand" state is stored in the riot nodes.
What you could do is add an expand
boolean property to your model, and a corresponding fold strategy which makes this property controls the folding/unfolding of the elements. Should not be too difficult I think.
from bosket.
Related Issues (20)
- Custom Input field for search HOT 3
- Selecting a node programmatically HOT 1
- Drag on same level HOT 2
- event.dataTransfer undefined during drop event HOT 1
- No seperate classes on leaf nodes vs parent nodes HOT 1
- dragging with handle HOT 1
- Drag and Drop inbetween nodes (re-order nodes) HOT 2
- items dragged off the canvas disappear HOT 1
- Model rebind causes opened nodes to collapse
- Drag and Drop not working on IE 11 HOT 2
- build not working on windows HOT 1
- How to add custom html?
- Edit tree node contents
- Multiselect with selected nodes always open (vue) HOT 2
- Unfold on select but don't fold back when deselecting HOT 1
- Help with the demo HOT 5
- Display method rendered as string not as html HOT 4
- Typescript support?
- bosket + redux tree not call display() props for nested node
- Issue building Bosket/vue
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. πππ
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google β€οΈ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from bosket.