i am working on react-flow, and my task is to transform the following data => `
`const configObj = {
name: "Dataset",
nodeChild: {
type: "schema",
nodeConfiguration: {
sid1: {
name: "Schema 1",
nodeChild: {
type: "dashboard",
nodeConfiguration: {
did1: {
name: "Dashboard 1"
}
}
}
},
sid2: {
name: "Schema 2",
nodeChild: {
type: "dashboard",
nodeConfiguration: {
did2: {
name: "Dashboard s1",
},
did3: {
name: "Dashboard 3"
}
}
}
}
}
}
}` to this ->
const elements = [
{
id: '1',
type: 'input', // input node
data: { label: 'Input Node' },
position: { x: 250, y: 25 },
},
// default node
{
id: '2',
// you can also pass a React component as a label
data: { label: <div>Default Node</div> },
position: { x: 100, y: 125 },
},
{
id: '3',
type: 'output', // output node
data: { label: 'Output Node' },
position: { x: 250, y: 250 },
},
// animated edge
{ id: 'e1-2', source: '1', target: '2', animated: true },
{ id: 'e2-3', source: '2', target: '3' },
];
`
not exactly but according to data1 so i prepare a code for it and it is working well in node environment but the moment i try it on react it shows some errorenter image description here here is my code
const configObj = {
name: "Dataset",
onClick: true,
nodeChild: {
type: "schema",
nodeConfiguration: {
sid1: {
name: "Schema 1",
nodeChild: {
type: "dashboard",
nodeConfiguration: {
did1: {
name: "Dashboard 1"
}
}
}
},
sid2: {
name: "Schema 2",
nodeChild: {
type: "dashboard",
nodeConfiguration: {
did2: {
name: "Dashboard s1",
nodeChild: {
type: "ritik",
nodeConfiguration: {
ri1: {
name: "Ritik",
}
}
}
},
did3: {
name: "Dashboard 3"
}
}
}
}
}
},
}
let count =1;
let dataConfig = []
const recursion = (obj, level,type) => {
let objData = {}
for(let j in obj){
if(j !== 'nodeChild' && j !== 'nodeParent'){
if(j === 'name'){
objData= {
...objData,
label: obj[j]
}
}else {
objData= {
...objData,
[j]: obj[j]
}
}
}
}
let idd = count
dataConfig = [...dataConfig, {id: count, data: objData, type, level, parentID}]
count++;
if('nodeChild' in obj){
const {nodeConfiguration, type} = obj.nodeChild
for(let val in nodeConfiguration){
recursion(nodeConfiguration[val], level+1, type, parentID = idd)
}
}
if('nodeParent' in obj){
const {nodeConfiguration, type} = obj.nodeParent
for(let val in nodeConfiguration){
recursion(nodeConfiguration[val], level-1, type)
}
}
}
recursion(configObj, level=0, type='root', parentID=1)
let edges = []
for(let i=1; i<dataConfig.length; i++){
let e = {
id: `e${dataConfig[i].id}-${dataConfig[i].parentID}`,
source: `${dataConfig[i].parentID}`, target: `${dataConfig[i].id}`, animated: true
}
edges = [
...edges,
e
]
}
let finalDataSet = []
let x=650, y=25;
let flag = false;
for(let i in dataConfig){
let element = {}
for(let key in dataConfig[i]){
if(key !== 'parentID'){
if(key === 'type'){
let k = dataConfig[i][key]
if(k === 'schema' || k === 'root'){
element = {
...element,
[key]: 'input'
}
}else {
element = {
...element,
[key]: 'output'
}
}
}else {
element = {
...element,
[key]: dataConfig[i][key]
}
}
}
}
element = {
...element,
position: { x, y }
}
// console.log(i)
finalDataSet = [
...finalDataSet,
element
]
y += 75;
if(!flag){
x = 25;
}
x = flag ? x+155 : x
flag = true
}
for(let i =0; i<edges.length; i++){
finalDataSet = [
...finalDataSet,
edges[i]
]
}
const DataSET = finalDataSet
export default DataSET
this code is perfectly working on local nodejs but the same code pops errors on react.js can any one help me on this
It's the recursion(configObj, level=0, type='root', parentID=1) calls that are causing trouble. You think that level=0 is saying to pass 0 to the level parameter but javascript doesn't recognize that syntax. It thinks that level is some variable you forgot to define. Hence the is not defined error.
To fix the issue, just do something like recursion(configObj, 0, 'root', 1) instead.
Related
I am trying to achieve the same result as i wrote in below syntax by implementing filter function to my script.
The current script i have
let sheet = [
{ $0: { 'Name': 'Report1' } },
{ $0: { 'Name': 'Row Count' } },
{ $0: { 'Name': 'Report2' } },
{ $0: { 'Name': 'User' } }
]
let nope = ['User','Row Count','Container']
let result = []
for(let i = 0; i < sheet.length ;i++){
if(sheet[i].$0.Name != nope[0] && sheet[i].$0.Name != nope[1] && sheet[i].$0.Name != nope[2]){
result.push(sheet[i])
}
}
console.log(result)
On my browser inspect element, it will result of (2) [{…}, {…}] on console.log
I tried using filter function
let result_2 = sheet.filter(w => !w.$0.Name.includes(nope[0]))
console.log(result_2)
1 : One problem and logic i face is that im unsure on how can i includes all the element of 'nope' in 'includes()'
2 : I will have to hard code the index such as nope[0] which i dont think is advisable if its going to be a big array
You actually almost finish but you reverse the w.$0.Name and nope.
let sheet = [
{ $0: { Name: "Report1" } },
{ $0: { Name: "Row Count" } },
{ $0: { Name: "Report2" } },
{ $0: { Name: "User" } },
];
let nope = ["User", "Row Count", "Container"];
let result_2 = sheet.filter(w => !nope.includes(w.$0.Name));
console.log(result_2);
PS: I think you should take a break and drink some tea. :)
let result_2 = sheet.filter(w => !nope.includes(w.$0.Name))
A simple and alternativr solution would be to use every() method within the filter. Like this:
It will check one element for every case of the second array and return true if nothing similar would be found.
let result_2 = sheet.filter(w => nope.every(x=> x !== w.$0.Name))
console.log(result_2)
let sheet = [{
$0: {
'Name': 'Report1'
}
},
{
$0: {
'Name': 'Row Count'
}
},
{
$0: {
'Name': 'Report2'
}
},
{
$0: {
'Name': 'User'
}
}
]
let nope = ['User', 'Row Count', 'Container']
let result = []
let result_2 = sheet.filter(w => nope.every(x => x !== w.$0.Name))
console.log(result_2)
Or if you want to use includes() you can do this:
let result_3 = sheet.filter(w => !nope.includes(w.$0.Name))
console.log(result_2)
let sheet = [{
$0: {
'Name': 'Report1'
}
},
{
$0: {
'Name': 'Row Count'
}
},
{
$0: {
'Name': 'Report2'
}
},
{
$0: {
'Name': 'User'
}
}
]
let nope = ['User', 'Row Count', 'Container']
let result = []
let result_3 = sheet.filter(w => !nope.includes(w.$0.Name))
console.log(result_2)
Fiddle example
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>
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
* }
*
*/
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)
}
}
Context: I want to be able to look through my nested arrays of objects and depending on the array key that property belonged to then prepend the string.
Issue: I was able to do it before I changed my data structure to include more objects within the parent array. Probably not the most efficient way to do it but it worked (appreciate any pointers on tidying this up).
method to append:
for (let key in temps) {
let test = temps[key].display;
if (key === "room1") {
temps[key].display = "Our friend: " + test;
}
if (key === "room2") {
temps[key].display = "Our friend: " + test;
}
if (key === "room3") {
temps[key].display = "Unknown:" + test;
}
}
So I am appending the value of display depending on the parent key they came from "room1, room2 or room3".
Original data structure:
let temps = {
room1: { id: 1, display: "shahid" },
room2: { id: 2, display: "akram" },
room3: { id: 3, display: "zia" }
};
New data structure:
let temps = {
room1: [{ id: 1, display: "shahid" }, { id: 11, display: "Zen" }],
room2: [{ id: 2, display: "akram" }, { id: 12, display: "Julia" }],
room3: [{ id: 3, display: "zia" }, { id: 13, display: "Octane" }]
};
So how do I get the method to work with my new data structure... better still, whats a better way of doing this if any please?
As your new structure has an extra (array) layer, you need an extra level of looping:
let temps = {
room1: [{ id: 1, display: "shahid" }, { id: 11, display: "Zen" }],
room2: [{ id: 2, display: "akram" }, { id: 12, display: "Julia" }],
room3: [{ id: 3, display: "zia" }, { id: 13, display: "Octane" }]
};
for (let key in temps) {
for (let item of temps[key]) {
let test = item.display;
if (key === "room1") {
item.display = "Our friend: " + test;
}
if (key === "room2") {
item.display = "Our friend: " + test;
}
if (key === "room3") {
item.display = "Unknown:" + test;
}
}
}
console.log(temps);
Remarks
There are a few things you could improve. For instance, it is a pity that you overwrite the original display name, which really is a user name. The way it gets displayed should better be a separate property. Imagine that such a user-object would move to another room, and then updating that property...
If your rooms are really called room1, room2, ...etc, then using those as object keys is not really called for. Then you are better off with an array, where the index determines the room.
I would also suggest using more descriptive variable names. temps or test are not very descriptive of what they really represent. rooms and name would probably better describe what they are.
For instance:
let rooms = [
[{ id: 1, name: "shahid" }, { id: 11, name: "Zen" }],
[{ id: 2, name: "akram" }, { id: 12, name: "Julia" }],
[{ id: 3, name: "zia" }, { id: 13, name: "Octane" }]
];
for (let [roomId, room] of rooms.entries()) {
for (let item of room) {
item.display = (roomId === 2 ? "Unknown: " : "Our friend: ") + item.name;
}
}
console.log(rooms);
Or in an object oriented way, where you can define methods to move users in and out of a room, and where the display feature can determine the string dynamically on-the-fly (as a getter):
class User {
constructor(id, name) {
this.id = id;
this.name = name;
this.room = null;
}
exitRoom() {
if (this.room) this.room.removeUser(this);
}
enterRoom(room) {
room.addUser(room);
}
get display() {
return (this.room?.hasFriends ? "Our friend: " : "Unknown: ") + this.name;
}
}
class Room {
constructor(name, hasFriends=false) {
this.name = name;
this.users = [];
this.hasFriends = hasFriends;
}
addUser(user) {
if (user.room) user.room.removeUser(user);
user.room = this;
this.users.push(user);
return this;
}
removeUser(user) {
if (user.room != this) return;
this.users.splice(this.users.indexOf(user), 1);
user.room = null;
}
}
let rooms = [
new Room("room1", true)
.addUser(new User(1, "shahid"))
.addUser(new User(11, "Zen")),
new Room("room2", true)
.addUser(new User(2, "akram"))
.addUser(new User(12, "Julia")),
new Room("room3", false)
.addUser(new User(3, "zia"))
.addUser(new User(13, "Octane")),
];
for (let room of rooms) {
console.log(`Room: ${room.name}`);
for (let user of room.users) {
console.log(` ${user.display}`);
}
}
let temps = {
room1: [{ id: 1, display: "shahid" }, { id: 11, display: "Zen" }],
room2: [{ id: 2, display: "akram" }, { id: 12, display: "Julia" }],
room3: [{ id: 3, display: "zia" }, { id: 13, display: "Octane" }]
};
temps = Object.keys(temps).map(function (key) {
return { [key]: temps[key] };
});
for (let i of temps) {
for (let key in i) {
if (key === "room1") {
i[key].forEach(e=>e.display = "Our friend: "+e.display);
}
if (key === "room2") {
i[key].forEach(e=>e.display = "Our friend: "+e.display );
}
if (key === "room3") {
i[key].forEach(e=>e.display = "Unknown: "+e.display );
}
}
}
console.log(temps)
The issue detail:
1. I implement the feature with the vue-slider-component module, but that has a lot of warnings when I move the dots on the slider.
2. I know that the reason is that I used v-for to point to an object that will change, but I do not know how to fix this issue.
the following link is my test site:
https://jsfiddle.net/ncwv84x9/
enter image description here
My codes:
code1 (Html)
<div id="app">
<div class="box" v-for="(item,index) in columnvalue">
<label>{{item.text}}</label>
<input v-model="value[index]" />
</div>
<hr />
<br />
<vue-slider v-model="value" :order="false" :tooltip="'always'" :process="false" :marks="marks" :width="600">
<template slot="tooltip" slot-scope="{index}">
<div>{{getText(index)}}</div>
</template>
</vue-slider>
</div>
JavaScript + Vue:
new Vue({
el: '#app',
components: {
VueSlider: window['vue-slider-component']
},
data: function() {
return {
// collect the all values
columnvalue: [],
// stored disease value
pet_name: [{
text: 'dog',
index: 0
},
{
text: 'cat',
index: 1
}
],
// stored drug value
feeder_name: [{
text: 'Sam',
index: 0
}],
// from age filter
age: [
65, 100
],
test: "",
value: [],
process: dotsPos => [
[dotsPos[0], dotsPos[1], {
backgroundColor: 'pink'
}],
[dotsPos[1], dotsPos[2], {
backgroundColor: 'blue'
}],
[dotsPos[2], dotsPos[3], {
backgroundColor: 'black'
}],
],
after: {},
relations: [],
marks: {
'0': {
label: 'start',
margin: '0 0 0 10px'
},
'100': {
label: 'end',
labelStyle: {
left: '100%',
margin: '0 0 0 10px',
top: '50%',
transform: 'translateY(-50%)'
}
}
}
}
},
created: function() {
//vue instance 被 constructor 建立後,在這裡完成 data binding
let tmpArray = this.pet_name.concat(this.feeder_name);
let tmpValueArray = [];
for (i = 0; i < tmpArray.length; i++) {
tmpArray[i].index = i;
tmpValueArray.push(0);
}
this.columnvalue = tmpArray;
this.value = tmpValueArray;
},
methods: {
getText(index) {
const ani = this.columnvalue.find((v) => v.index == index).text;
this.after = {
...this.after,
[ani]: this.value[index]
}
return ani;
},
getNodeRelation() {
const indexs = this.after;
let result = [];
let result2 = [];
let placement = [];
for (obj in indexs) {
placement.push([obj, indexs[obj]]);
}
placement.sort(function(a, b) {
/* console.log(a[1]) */
return a[1] - b[1];
})
for (i = 0; i < placement.length; i++) {
if (i + 1 >= placement.length) {
break;
}
let distance = placement[i + 1][1] - placement[i][1];
let predicate = "";
if (distance > 0) {
predicate = "after";
} else if (distance == 0 && placement[i + 1][1] == 0) {
predicate = "hasUse";
} else {
predicate = "same";
}
let source = {
label: placement[i][0],
index: i
};
let target = {
label: placement[i + 1][0],
index: i
};
// store the 4-tuple reprsentations about slider
result2.push({
source: source,
target: target,
type: predicate,
days: distance
});
}
/* this.relations = "{\"relation\":" + JSON.stringify(result2)+"}" */
;
this.relations = JSON.stringify(result2);
},
getAllFilters() {
let vm = this;
let beginHas = true;
if (vm.relations.length == 0) {
vm.getNodeRelation();
beginHas = false;
}
let result = {
age: vm.age,
disease_name: vm.disease_name,
drug_name: vm.drug_name,
relation: vm.relations
};
if (!beginHas) {
vm.relations = [];
}
this.test = JSON.stringify(result);
}
},
})
I get a infinite loop error which disappears when I remove this section in getText()
this.after = {
...this.after,
[ani]: this.value[index]
}
This is because there is some reactivity triggered and re-renders the dom, which calls that function, which renders the dom and so on...
I need to search for an element in a json object like this:
var new_a = 'new';
var json = { cells:
[ { type: 'model',
id: '5aef826a1809',
attrs: {
text: 'first',
a: 'changethis'
}
},
{ type: 'model',
id: '2c11b8bd8112',
attrs: {
text: 'second'
}
}
]
}
Now I want to find the object with the id = 5aef826a1809, because I want to change the value of a to new_a or insert an a-element if it doesn't exist.
If id = 2c11b8bd8112 a new a-element with the content new_a should be added.
I tried to use
var res = _.find(json.cells, { id: '5aef826a1809' }); // doesn't work
res.attrs.a = new_a; // this would update or add new field, right?
But this doesn't work
Try like this
var new_a = 'new';
var json = {
cells: [{
type: 'model',
id: '5aef826a1809',
attrs: {
text: 'first',
a: 'changethis'
}
}, {
type: 'model',
id: '2c11b8bd8112',
attrs: {
text: 'second'
}
}]
};
var obj = json.cells.find(function (x) {
return x.id == '5aef826a1809'
});
if (obj) { // return value if found else return undefined if not found
obj.attrs.a = new_a;
console.log(json);
}
JSFIDDLE
Using this simple for loop should work, if that's what you're looking for:
for(var i = 0; i<json.cells.length; i++){
if(json.cells[i].id == "5aef826a1809" || json.cells[i].id == "2c11b8bd8112"){
json.cells[i].attrs.a = "new_a";
}
}
Hope it helped.
You can use Array.prototype.some for searching, changing and for making a short circuit to prevent more iteration than necessary.
var new_a = 'new',
json = {
cells: [{
type: 'model',
id: '5aef826a1809',
attrs: {
text: 'first',
a: 'changethis'
}
}, {
type: 'model',
id: '2c11b8bd8112',
attrs: {
text: 'second'
}
}]
};
function change(id) {
json.cells.some(function (a) {
var i = id.indexOf(a.id);
if (~i) {
a.attrs = a.attrs || {};
a.attrs.a = new_a;
id.splice(i, 1);
if (!id.length) {
return true;
}
}
});
}
change(['5aef826a1809', '2c11b8bd8112']);
document.write('<pre>' + JSON.stringify(json, 0, 4) + '</pre>');