Tree: How to keep opened states when tree updated
I need to keep tree nodes open/closed stated when i set new data to this.dataSource.data
. New data is very same with old - it just have one or several lowest-level nodes added/removed.
My idea is to record node expansion to ReplaySubject
and replay expansion queue. It should work but it's very ugly way.
I hope that here are have much more elegant way to solve my problem.
angular angular-material2
add a comment |
I need to keep tree nodes open/closed stated when i set new data to this.dataSource.data
. New data is very same with old - it just have one or several lowest-level nodes added/removed.
My idea is to record node expansion to ReplaySubject
and replay expansion queue. It should work but it's very ugly way.
I hope that here are have much more elegant way to solve my problem.
angular angular-material2
add a comment |
I need to keep tree nodes open/closed stated when i set new data to this.dataSource.data
. New data is very same with old - it just have one or several lowest-level nodes added/removed.
My idea is to record node expansion to ReplaySubject
and replay expansion queue. It should work but it's very ugly way.
I hope that here are have much more elegant way to solve my problem.
angular angular-material2
I need to keep tree nodes open/closed stated when i set new data to this.dataSource.data
. New data is very same with old - it just have one or several lowest-level nodes added/removed.
My idea is to record node expansion to ReplaySubject
and replay expansion queue. It should work but it's very ugly way.
I hope that here are have much more elegant way to solve my problem.
angular angular-material2
angular angular-material2
asked Nov 13 '18 at 11:30
VadimVadim
3710
3710
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
I added a boolean 'expanded' to my datamodel. I then use a function on (click) which inverts this, and a recursive loop to save that change to the actual data that is used for dataSource.data. So in reality I am not using the treecontrol anymore, even though I have still need it (the tree does not work without).
<button mat-icon-button
[attr.aria-label]="'toggle ' + node.name"
(click)="changeState(node, myJson)"
>
<mat-icon class="mat-icon-rtl-mirror">
{{node.expanded ? 'expand_more' : 'chevron_right'}}
</mat-icon>
</button>
--
/** Changes expanded state for clicked tree-item, saves change to json data used by tree datasource */
changeState(node, myJson) {
node.expanded = !node.expanded;
if (node.children && node.children.length > 0) {
this.found = false;
myJson.forEach(child => {
if (!this.found) {
this.saveStates(child, node);
}
});
}
}
/** recursive loop-function used by this.changeState() to save tree-items expanded-state to the master array */
saveStates(child, clickedChild) {
if (child.id === clickedChild.id) {
child.expanded = clickedChild.expanded;
this.found = true;
return;
} else if (child.children && child.children.length > 0) {
child.children.forEach(c => {
this.saveStates(c, clickedGroup);
});
}
}
--
And the standard functions from the tree-example I changed like this to work with my data:
// checks if datasource for material tree has any children
hasNestedChild = (_: number, nodeData: MyModel) => nodeData.children.length > 0;
// returns children
private _getChildren = (node: MyModel) => node.children;
Good idea but comparing between old and newdataNodes
is very expensive operation. Especially if you have ~10k nodes. So, it can't be used in my project.
– Vadim
Nov 13 '18 at 13:08
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53280079%2ftree-how-to-keep-opened-states-when-tree-updated%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
I added a boolean 'expanded' to my datamodel. I then use a function on (click) which inverts this, and a recursive loop to save that change to the actual data that is used for dataSource.data. So in reality I am not using the treecontrol anymore, even though I have still need it (the tree does not work without).
<button mat-icon-button
[attr.aria-label]="'toggle ' + node.name"
(click)="changeState(node, myJson)"
>
<mat-icon class="mat-icon-rtl-mirror">
{{node.expanded ? 'expand_more' : 'chevron_right'}}
</mat-icon>
</button>
--
/** Changes expanded state for clicked tree-item, saves change to json data used by tree datasource */
changeState(node, myJson) {
node.expanded = !node.expanded;
if (node.children && node.children.length > 0) {
this.found = false;
myJson.forEach(child => {
if (!this.found) {
this.saveStates(child, node);
}
});
}
}
/** recursive loop-function used by this.changeState() to save tree-items expanded-state to the master array */
saveStates(child, clickedChild) {
if (child.id === clickedChild.id) {
child.expanded = clickedChild.expanded;
this.found = true;
return;
} else if (child.children && child.children.length > 0) {
child.children.forEach(c => {
this.saveStates(c, clickedGroup);
});
}
}
--
And the standard functions from the tree-example I changed like this to work with my data:
// checks if datasource for material tree has any children
hasNestedChild = (_: number, nodeData: MyModel) => nodeData.children.length > 0;
// returns children
private _getChildren = (node: MyModel) => node.children;
Good idea but comparing between old and newdataNodes
is very expensive operation. Especially if you have ~10k nodes. So, it can't be used in my project.
– Vadim
Nov 13 '18 at 13:08
add a comment |
I added a boolean 'expanded' to my datamodel. I then use a function on (click) which inverts this, and a recursive loop to save that change to the actual data that is used for dataSource.data. So in reality I am not using the treecontrol anymore, even though I have still need it (the tree does not work without).
<button mat-icon-button
[attr.aria-label]="'toggle ' + node.name"
(click)="changeState(node, myJson)"
>
<mat-icon class="mat-icon-rtl-mirror">
{{node.expanded ? 'expand_more' : 'chevron_right'}}
</mat-icon>
</button>
--
/** Changes expanded state for clicked tree-item, saves change to json data used by tree datasource */
changeState(node, myJson) {
node.expanded = !node.expanded;
if (node.children && node.children.length > 0) {
this.found = false;
myJson.forEach(child => {
if (!this.found) {
this.saveStates(child, node);
}
});
}
}
/** recursive loop-function used by this.changeState() to save tree-items expanded-state to the master array */
saveStates(child, clickedChild) {
if (child.id === clickedChild.id) {
child.expanded = clickedChild.expanded;
this.found = true;
return;
} else if (child.children && child.children.length > 0) {
child.children.forEach(c => {
this.saveStates(c, clickedGroup);
});
}
}
--
And the standard functions from the tree-example I changed like this to work with my data:
// checks if datasource for material tree has any children
hasNestedChild = (_: number, nodeData: MyModel) => nodeData.children.length > 0;
// returns children
private _getChildren = (node: MyModel) => node.children;
Good idea but comparing between old and newdataNodes
is very expensive operation. Especially if you have ~10k nodes. So, it can't be used in my project.
– Vadim
Nov 13 '18 at 13:08
add a comment |
I added a boolean 'expanded' to my datamodel. I then use a function on (click) which inverts this, and a recursive loop to save that change to the actual data that is used for dataSource.data. So in reality I am not using the treecontrol anymore, even though I have still need it (the tree does not work without).
<button mat-icon-button
[attr.aria-label]="'toggle ' + node.name"
(click)="changeState(node, myJson)"
>
<mat-icon class="mat-icon-rtl-mirror">
{{node.expanded ? 'expand_more' : 'chevron_right'}}
</mat-icon>
</button>
--
/** Changes expanded state for clicked tree-item, saves change to json data used by tree datasource */
changeState(node, myJson) {
node.expanded = !node.expanded;
if (node.children && node.children.length > 0) {
this.found = false;
myJson.forEach(child => {
if (!this.found) {
this.saveStates(child, node);
}
});
}
}
/** recursive loop-function used by this.changeState() to save tree-items expanded-state to the master array */
saveStates(child, clickedChild) {
if (child.id === clickedChild.id) {
child.expanded = clickedChild.expanded;
this.found = true;
return;
} else if (child.children && child.children.length > 0) {
child.children.forEach(c => {
this.saveStates(c, clickedGroup);
});
}
}
--
And the standard functions from the tree-example I changed like this to work with my data:
// checks if datasource for material tree has any children
hasNestedChild = (_: number, nodeData: MyModel) => nodeData.children.length > 0;
// returns children
private _getChildren = (node: MyModel) => node.children;
I added a boolean 'expanded' to my datamodel. I then use a function on (click) which inverts this, and a recursive loop to save that change to the actual data that is used for dataSource.data. So in reality I am not using the treecontrol anymore, even though I have still need it (the tree does not work without).
<button mat-icon-button
[attr.aria-label]="'toggle ' + node.name"
(click)="changeState(node, myJson)"
>
<mat-icon class="mat-icon-rtl-mirror">
{{node.expanded ? 'expand_more' : 'chevron_right'}}
</mat-icon>
</button>
--
/** Changes expanded state for clicked tree-item, saves change to json data used by tree datasource */
changeState(node, myJson) {
node.expanded = !node.expanded;
if (node.children && node.children.length > 0) {
this.found = false;
myJson.forEach(child => {
if (!this.found) {
this.saveStates(child, node);
}
});
}
}
/** recursive loop-function used by this.changeState() to save tree-items expanded-state to the master array */
saveStates(child, clickedChild) {
if (child.id === clickedChild.id) {
child.expanded = clickedChild.expanded;
this.found = true;
return;
} else if (child.children && child.children.length > 0) {
child.children.forEach(c => {
this.saveStates(c, clickedGroup);
});
}
}
--
And the standard functions from the tree-example I changed like this to work with my data:
// checks if datasource for material tree has any children
hasNestedChild = (_: number, nodeData: MyModel) => nodeData.children.length > 0;
// returns children
private _getChildren = (node: MyModel) => node.children;
answered Nov 13 '18 at 12:33
Lars RødalLars Rødal
9619
9619
Good idea but comparing between old and newdataNodes
is very expensive operation. Especially if you have ~10k nodes. So, it can't be used in my project.
– Vadim
Nov 13 '18 at 13:08
add a comment |
Good idea but comparing between old and newdataNodes
is very expensive operation. Especially if you have ~10k nodes. So, it can't be used in my project.
– Vadim
Nov 13 '18 at 13:08
Good idea but comparing between old and new
dataNodes
is very expensive operation. Especially if you have ~10k nodes. So, it can't be used in my project.– Vadim
Nov 13 '18 at 13:08
Good idea but comparing between old and new
dataNodes
is very expensive operation. Especially if you have ~10k nodes. So, it can't be used in my project.– Vadim
Nov 13 '18 at 13:08
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53280079%2ftree-how-to-keep-opened-states-when-tree-updated%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown