Reputation: 207
I would like to add a function in which users can go to the next searched result. Thanks, @ggorlen for helping with the recursive search.
I have a recursive search function that gives the first value and makes them selected = true and if it is in nested array make showTree=true.
How I can add a function in which if the user clicks the next search record then the selected: true will set to the next result and remove the previous one?
and based on the new results showTree will change.
How to add a variable which gets updated based on the number of time search is called...
previous record option so user can go back to the previous result
const expandPath = (nodes, targetLabel) => {
for (const node of nodes) {
if (node.label.includes(targetLabel)) {
return (node.selected = true);
} else if (expandPath(node.item, targetLabel)) {
return (node.showTree = true);
}
}
};
// Output
expandPath(testData, 'ch');
//// add variable for count example: 1 of 25
console.log(testData);
//if user click on nextrecord after search
//nextrecord(){
//logic to remove the selected true from current and add for next
//update showtree
//update recordNumber of totalValue example: 2 of 25
//}
//child3 should get selected true and remove child1 selected true and showtree
//same add showTree= true based on selected value
//if user click on previous record after search
//previousrecord(){
//logic to remove the selected true from current and add for previous
//update showtree
//update recordNumber of totalValue example: 1 of 25
//}
console.log(testData);
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script>
// Test Data
const testData = [
{
id: 1,
label: 'parent1',
item: [
{
id: 21,
label: 'child1',
item: [
{
id: 211,
label: 'child31',
item: [
{
id: 2111,
label: 'child2211',
item: [{ id: 21111, label: 'child22111' }]
}
]
},
{ id: 222, label: 'child32' }
]
},
{
id: 22,
label: 'child2',
item: [
{
id: 221,
label: 'child421',
item: [{ id: 2211, label: 'child2211' }]
},
{ id: 222, label: 'child222' }
]
}
]
},
{
id: 2,
label: 'parent2',
item: [
{
id: 21,
label: 'child2',
item: [
{
id: 511,
label: 'child51',
item: [
{
id: 5111,
label: 'child5211',
item: [{ id: 51111, label: 'child52111' }]
}
]
},
{ id: 522, label: 'child352' }
]
}
]
}
];
</script>
Upvotes: 3
Views: 642
Reputation: 424
You can use refer following code
const testData = [
{
id: 1,
label: 'parent1',
item: [
{
id: 21,
label: 'child1',
item: [
{
id: 211,
label: 'child31',
item: [
{
id: 2111,
label: 'child2211',
item: [{ id: 21111, label: 'child22111' }]
}
]
},
{ id: 222, label: 'child32' }
]
},
{
id: 22,
label: 'child2',
item: [
{
id: 221,
label: 'child421',
item: [{ id: 2211, label: 'child2211' }]
},
{ id: 222, label: 'child222' }
]
}
]
},
{
id: 2,
label: 'parent2',
item: [
{
id: 21,
label: 'child2',
item: [
{
id: 511,
label: 'child51',
item: [
{
id: 5111,
label: 'child5211',
item: [{ id: 51111, label: 'child52111' }]
}
]
},
{ id: 522, label: 'child352' }
]
}
]
}
];
// flatten down tree to array and add parent pointer
const flatten = (data) => {
let flattenData = [data]
if (data.item) {
for (const item of data.item) {
item.parent = data;
flattenData = flattenData.concat(flatten(item));
}
}
return flattenData;
}
let flattenData = [];
// flatten down the test data
for (const data of testData) {
flattenData = flattenData.concat(flatten(data));
}
// to update showTree flag
const toggle = (item, expand = true) => {
const parent = item.parent;
if (parent) {
parent.showTree = expand;
if (parent.parent) {
return toggle(parent, expand);
}
return parent;
}
return item;
}
/**
*
* @param {targetLabel} query
* @returns function navigate with param forward flag
*/
const seach = (query) => {
let index = -1;
const items = flattenData.filter(x => x.label.includes(query));
return (forward = true) => {
if (index > -1) {
items[index].selected = false;
toggle(items[index], false);
}
index = index + (forward ? 1 : -1);
let item = null;
if (index > -1 && index < items.length) {
items[index].selected = true;
item = toggle(items[index], true);
}
return {
item,
index,
length: items.length
}
}
}
const navigate = seach('child5211');
// next result
let result = navigate();
// previous result
result = navigate(false);
// result will look like this
/**
* {
* item: root of current item with showTree and selected falgs or null if out of bound,
* index: current match,
* length: total match
* }
*
*/
Upvotes: 1
Reputation: 139
Tackling one thing at a time here, you can pretty quickly get the desired 'next' functionality you want by converting you're recursive search to a generator function:
function* expandPath(nodes, targetLabel) {
for (const node of nodes) {
if (node.label.includes(targetLabel)) {
yield (node.selected = true);
} else if (expandPath(node.item, targetLabel)) {
yield (node.showTree = true);
}
}
};
const gen = expandPath(mynodes, "thisTargetLabel");
gen.next()
gen.next() //<-- the next one
It's a little hard to know without more of your context how to answer the other questions, but what it really seems like you need here is state, and (es6) class is a good way to make this:
class Searcher {
constructor(mynodes, mylabel){
this.count=0;
this.nodes=mynodes;
this.label=mylabel;
this.generateMatches(this.nodes);
this.selectNode(this.matches[0]); // select the first node
}
generateMatches(nodes){
this.matches=[];
for (const node of nodes) {
if (node.label.includes(this.label)) {
this.matches.push(node);
} else {
this.generateMatches(nodes.node)
}
}
}
updateTreeById(id, node){
this.nodes.forEach(n=>n.showTree = false);
for (const node of this.nodes) {
if (node.id === id) {
//noop but we are here
} else if(this.updateTreeById(id, this.nodes.node)) {
node.showTree = true;
}
}
}
selectNode(i){
const index = i % this.matches.length;
this.currNodeId = this.matches[index].id;
this.matches[index].selected = true // we are wrapping around
this.count = i; // setting your current count
this.updateTreeById(this.matches[index].id)
// update logic, reset trees
}
nextNode(){
this.selectNode(this.count + 1)
}
prevNode(){
this.selectNode(this.count - 1)
}
}
Upvotes: 0