why react-select default value doesn't show - reactjs

I using react select like following code1. But In react-select doesnt show default value.
Two console.log are show me same value correctly all time .
(defaultArray is just a variable)
And when I use code2. Default value does not show too. When I use code3 . Default value showed.
That is too curious to me.
Please give me advice.
edit1 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
I found new one. useEffect may be caused it's part of problem.
when I remove [useEffect] and set Array. work well.
But Fundamental problem is invisible yet.
const [defaultArray, setDefaultArray] = useState([
{ value: "30", label: "A" },
{ value: "31", label: "B" },
{ value: "32", label: "C" },
{ value: "33", label: "D" },
{ value: "34", label: "E" },
]);
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
code1
import React from "react";
import { useState, useEffect } from "react";
const SelectPersonality: React.FC<RouteComponentProps> = props => {
const [defaultArray, setDefaultArray] = useState(Array());
useEffect (() => {
setDefaultArray([
{ value: "30", label: "A" },
{ value: "31", label: "B" },
{ value: "32", label: "C" },
{ value: "33", label: "D" },
{ value: "34", label: "E" },
]);
}, []);
return (
<div>
{console.log(defaultArray)}
{console.log([
{ value: "30", label: "A" },
{ value: "31", label: "B" },
{ value: "32", label: "C" },
{ value: "33", label: "D" },
{ value: "34", label: "E" },
])}
<Select
isMulti
defaultValue={defaultArray}
options={character_options}
onChange={value => Change(value)}
className="select_personality_character"
/>
</div>
);
};
export default SelectPersonality;
code2
{console.log(defaultArray)}
{console.log([
{ value: "30", label: "A" },
{ value: "31", label: "B" },
{ value: "32", label: "C" },
{ value: "33", label: "D" },
{ value: "34", label: "E" },
])}
<Select
isMulti
defaultValue={
defaultArray
? defaultArray
: [
{ value: "30", label: "A" },
{ value: "31", label: "B" },
{ value: "32", label: "C" },
{ value: "33", label: "D" },
{ value: "34", label: "E" },
]
}
options={character_options}
onChange={value => Change(value)}
className="select_personality_character"
/>
code3
<Select
isMulti
defaultValue={
defaultArray
? [
{ value: "30", label: "A" },
{ value: "31", label: "B" },
{ value: "32", label: "C" },
{ value: "33", label: "D" },
{ value: "34", label: "E" },
]
: defaultArray
}
options={character_options}
onChange={value => Change(value)}
className="select_personality_character"
/>

it seems that defaultArray is not equal to the array ( read the code bellow, is much easier to understand than to explain )
defaultArray != [
{ value: "30", label: "A" },
{ value: "31", label: "B" },
{ value: "32", label: "C" },
{ value: "33", label: "D" },
{ value: "34", label: "E" },
]
defaultArray it may be an anidated array
[
[
{ value: "30", label: "A" },
{ value: "31", label: "B" },
{ value: "32", label: "C" },
{ value: "33", label: "D" },
{ value: "34", label: "E" },
]
]
please check and let me know
edit:
the code2 and code3 gives us the hint that defaultArray:
is not null
is not undefined
it may be empty
like you said into the edit, it may be useEffect fault
basically you initialize the array, render the component, populate the array with the values
try this :
const [defaultArray, setDefaultArray] = useState([
{ value: "30", label: "A" },
{ value: "31", label: "B" },
{ value: "32", label: "C" },
{ value: "33", label: "D" },
{ value: "34", label: "E" },
]);
you should populate the array before rendering
also, keep this in mind
const dependenciesArray = []
useEffect(()=>{}, dependenciesArray) // this will block the rerender of the component at state update
useEffect(()=>{}) // not passing an array will force a rerender of the component at each state update
so if you want dinamic select values, don't pass the second argument into the useEffect()
see docs: useEffect docs

Try this,
import React from "react";
import "./styles.css";
import Select from "react-select";
export default function App() {
return (
<div className="App">
<h1>React-select example</h1>
<SelectComponent />
</div>
);
}
const SelectComponent = () => {
const options = [
{ value: "30", label: "A" },
{ value: "31", label: "B" },
{ value: "32", label: "C" },
{ value: "33", label: "D" },
{ value: "34", label: "E" },
{ value: "35", label: "F" },
{ value: "36", label: "G" },
{ value: "37", label: "H" },
{ value: "38", label: "I" }
];
const defaults = [options[0], options[1], options[2], options[3]];
return (
<div>
<Select
isMulti
defaultValue={defaults}
options={options}
/>
</div>
);
};
I think the problem is that your default values dont match the options values, you are feeding the select component 2 different data arrays and it gets confused

Hi I resolved this problem but I still don't understand what caused it.
I had to add {defaultArray !== undefined && (~)} . This code doesn't work without it.
I can't understand.
why....
import React from "react";
import { useState, useEffect } from "react";
const SelectPersonality: React.FC<RouteComponentProps> = props => {
const [defaultArray, setDefaultArray] = useState<Array<{ [key: string]: string }>>();
useEffect (() => {
setDefaultArray([
{ value: "30", label: "A" },
{ value: "31", label: "B" },
{ value: "32", label: "C" },
{ value: "33", label: "D" },
{ value: "34", label: "E" },
]);
}, []);
return (
<div>
     {defaultArray !== undefined && (
<Select
isMulti
defaultValue={defaultArray}
options={character_options}
onChange={value => change(value)}
className="select_personality_character"
/>
)}
</div>
);
};
export default SelectPersonality;

Related

Error when changing the value of an object within an array causing another object to be called

I'm working on a project where I need the values in an array to change depending on if a button is clicked for that specific item. Right now, I'm able to get the first name (pescatarian) in my first subCategories object to work, but when I press the second one (vegan), it is displaying my second subCategories object and changing data[0] to
"category": "Diet", "subCategories": [{"name": "one", "value": false}, {"name":"two", "value": false}, {"name": "three", "value": false}, {"name": "four", "value": false}]}
from:
{"category": "Diet", "subCategories": [{"name": "pescatarian", "value": false}, {"name": "vegan", "value": false}, {"name": "vegetarian", "value": false}]}
From there, I am able to press the first two subCategories (one and two), but if I press the third one I get an error stating: TypeError: undefined is not an object (evaluating 'data[index].subCategories'). Does anyone know why this is happening? I would really appreciate any help or advice. Thank you!
const [data, setData] = useState([
{
category: 'Diet',
subCategories: [
{name:'pescatarian', value: false },
{name:'vegan', value: false },
{name:'vegetarian', value: false }
],
}, {
category: 'Daily Exercise in Hours',
subCategories: [
{name:'one', value: false },
{name:'two', value: false },
{name:'three', value: false },
{name:'four', value: false }
],
},
])
const onChangeValue = (item, index, newValue) => {
console.log('data[index]:', data[index].subCategories)
const newSub = data[index].subCategories.map(subCat => {
if (subCat.name.includes(item.name)) {
return {
...subCat,
value: newValue,
}
}
return subCat
})
const newData = data.map(newItem => {
if (newItem.subCategories.some(x => x.name === item.name)){
return {
...newItem,
subCategories:newSub,
}
}
return newItem
})
setData(newData)
}
onValueChange={newValue => onChangeValue(item, index, newValue)}

Sort and group objects alphabetically by the first letter from an array in Angular?

How can I sort and group objects alphabetically by the first letter from an array in angular? I have seen the example to do this Sort and group objects alphabetically in Javascript and the exact answer and output json i am looking in Angular.
As of now My api json is like this stackblitz
Expexted api json would like this stackblitz
I have tried this but i am unable to found the solution in angular.
real Json:
employees = [
{ name: "Abigail", age: "25" },
{ name: "Axle", age: "29" },
{ name: "Brianna", age: "25" },
{ name: "Brooklyn", age: "23" },
{ name: "Camila", age: "24" },
{ name: "Charlotte", age: "28" },
{ name: "David", age: "22" }
];
expecting json after sort and group objects alphabetically by the first letter from an array would like:
[
{
"alphabet": "A",
"record": [
{ "name": "Abigail", "age": "25" },
{ "name": "Axle", "age": "29" }
]
},
{
"alphabet": "B",
"record": [
{ "name": "Brianna", "age": "25" },
{ "name": "Brooklyn", "age": "23" }
]
},
{
"alphabet": "C",
"record": [
{ "name": "Camila", "age": "24" },
{ "name": "Charlotte", "age": "28" }
]
},
{
"alphabet": "D", "record": [
{ "name": "David", "age": "22" }
]
}
]
expected output like:
A
Abigail
Axle
B
Brianna
Brooklyn
C
Camila
Charlotte
D
David
As mentioned in the comment, there is no Typescript specific way to sort and group the data. You could the JS Array#reduce to group the objects to your requirement.
Try the following
const employees = [ { name: "Abigail", age: "25" }, { name: "Axle", age: "29" }, { name: "Brianna", age: "25" }, { name: "Brooklyn", age: "23" }, { name: "Camila", age: "24" }, { name: "Charlotte", age: "28" }, { name: "David", age: "22" } ];
const output = employees
.reduce((acc, curr) => {
const idx = acc.findIndex(e => e.alphabet === curr.name[0]);
if (idx === -1) {
acc.push({ alphabet: curr.name[0], record: [curr] });
}
else {
acc[idx].record.push(curr);
acc[idx].record.sort((r1, r2) => r1.name > r2.name ? 1 : -1);
}
return acc;
}, [])
.sort((e1, e2) => e1.alphabet > e2.alphabet ? 1 : -1);
console.log(output);
It would look like following in the Stackblitz.
export class ExpansionOverviewExample {
#ViewChild(MatAccordion, { static: false }) accordion: MatAccordion;
employees = [
{ name: "Brianna", age: "25" },
{ name: "Axle", age: "29" },
{ name: "David", age: "22" },
{ name: "Brooklyn", age: "23" },
{ name: "Camila", age: "24" },
{ name: "Abigail", age: "25" },
{ name: "Charlotte", age: "28" }
];
constructor() {
this.employees = this.employees
.reduce((acc, curr) => {
const idx = acc.findIndex(e => e.alphabet === curr.name[0]);
if (idx === -1) {
acc.push({ alphabet: curr.name[0], record: [curr] });
} else {
acc[idx].record.push(curr);
acc[idx].record.sort((r1, r2) => (r1.name > r2.name ? 1 : -1));
}
return acc;
}, [])
.sort((e1, e2) => (e1.alphabet > e2.alphabet ? 1 : -1));
}
}
You could also use safe navigation operator ?. in the template so you don't get any undefined errors before the reduce is complete.
<div *ngFor="let mani of employees">
<div>
<p>{{mani?.alphabet}}</p>
<p *ngFor="let group of mani?.record"> {{ group?.name }}</p>
<hr>
</div>
</div>
I've updated your Stackblitz

React js Tree View using ul and li

I want to create a tree view with search nodes using ul/li from JSON data in react js without using any external library.
Here is the sample of my JSON data.
-
[ { value: "General", label: "General", count: "12 / 30", }, { value: "Accounting", label: "Accounting", count: "17 / 30", }, { value: "Labour Management", label: "Labour Management", count: "05 / 30", children: [ { value: "Labour ManagementChild", label: "Labour ManagementChild", children: [ { value: "Labour ManagementSub Child", label: "Labour ManagementSub Child", }, ], }, { value: "Labour ManagementChild2", label: "Labour ManagementChild2", }, ], }, ]
Suppose your JSON data is stored in a variable called tree
and you have some random format of your data in the li tags
then you can go with
const traverseNode = (node) => {
return (
<li key={node.label}>
{node.label}:{node.value} {node.count}
{node.children
? node.children.map((childNode) => (
<ul>{traverseNode(childNode)}</ul>
))
: null}
</li>
);
};
return <ul>{tree.map((node) => traverseNode(node))}</ul>;
Recursive solutions are helpful with such problems. I suggest taking a look again at data structures and algorithms for them (for example on programiz). Your structure is not exactly a tree, but a polytree.

How to search and filter in array of objects on setState

I'm trying to create a search based on an array of objects with react which data is in this format:
const data = [
{"category 1" : [
{
"name": "Orange",
"desc": "juice, orange, Water"
},
{
"name": "Ananas",
"desc": "juice, ananas, water"
}
]
},
{"category 2" : [
{
"name": "Banana Split",
"desc": "Banana, ice cream, chocolat, topping",
"allergens": "nuts"
},
{
"name": "Mango Sticky Rice",
"desc": "Mango, rice, milk",
"allergens": ""
}
]
}
]
I stored this data inside useState declaration to be able to render accordingly on data chnage:
const [filteredBySearch, setFilteredBySearch] = useState(data)
I have an input where we can type anything and set inside useState declaration.
Goal:
If I type in my input:
"Jui"
Output should be:
console.log(filteredBySearch)
/* output:
[
{"category 1" : [
{
"name": "Orange",
"desc": "juice, orange, Water"
},
{
"name": "Ananas",
"desc": "juice, ananas, water"
}
]
},
{"category 2" : []
}
]*/
Exemple 2:
If I type in my input:
"Orange banana"
Output should be:
console.log(filteredBySearch)
/* output: [
{"category 1" : [
{
"name": "Orange",
"desc": "juice, orange, Water"
}
]
},
{"category 2" : [
{
"name": "Banana Split",
"desc": "Banana, ice cream, chocolat, topping",
"allergens": "nuts"
}
]
}
]*/
I've try creating a new object with map and filter and set it with setFilteredBySearch, but I can't get anything, even creating this new object.
This the full component:
import Card from '../components/Card'
import React, { useState } from 'react';
export default function IndexPage({ data, search }) {
//search is the result of input value set on a useState
//Filter categoriesFoods by search
const [FilteredBySearch, setFilteredBySearch] = useState(data)
return (
<div className="main-content">
<div className="card-container">
{
FilteredBySearch.map(function(el, i) {
return (
<div key={i}>
<h2 className="category" id={Object.keys(el)}>{Object.keys(el)}</h2>
{
el[Object.keys(el)].map (function(itm,index){
return <Card key={index} infoItem={itm}/>
})
}
</div>
)
})
}
</div>
<style jsx>{`...`}</style>
</div>
)}
Any idea for me ?
Thanks a lot for your guidance!
I think this is what you are looking for. I have created below utilities for filtering as per your requirement.
const dataObj = [
{
'category 1': [
{
name: 'Orange',
desc: 'juice, orange, Water',
},
{
name: 'Ananas',
desc: 'juice, ananas, water',
},
],
},
{
'category 2': [
{
name: 'Banana Split',
desc: 'Banana, ice cream, chocolat, topping',
allergens: 'nuts',
},
{
name: 'Mango Sticky Rice',
desc: 'Mango, rice, milk',
allergens: '',
},
],
},
]
const checkIfInputMatches = (input, desc) => input.toLowerCase().split(" ").some(o => desc.toLowerCase().includes(o))
const filterByInput = (data, input) => {
let finalResult = [];
data.forEach(d => {
let keys = Object.keys(d);
let values = Object.values(d);
finalResult = [...finalResult, ...values.map((obj, index) => {
let result = obj.filter(o => checkIfInputMatches(input, o.desc))
return {[keys[index]]: result}
})]
})
return finalResult
}
console.log(filterByInput(dataObj, 'JUI'))
console.log(filterByInput(dataObj, "orange"))
console.log(filterByInput(dataObj, "rice"))
console.log(filterByInput(dataObj, "Orange banana"))
Hope this helps.

Rendering a list of nested objects in Reacts

I have a list of objects:
const products2 = [
{category: "Category 1", products:
{
product1: "1",
product2: "2"
}
},
{category: "Category 2", products:
{
product1: "3",
product2: "4"
}
},
]
How can I render it in a div?
Tried to map it but it didn't work :(
Thanks,
Kuba
products is an array so map over it should be fine. products on the other hand is not and therefore map won't work. You can use, for example, Object.values(products2[0].products) so you get 1 and 2 in an array and do what you need with it.
const products2 = [
{
category: "Category 1",
products: {
product1: "1",
product2: "2"
},
},
{
category: "Category 2",
products: {
product1: "3",
product2: "4"
},
},
]
const result = products2
.map(product => `${product.category} ${Object.values(product.products).join(' ')}`)
console.log(result)
Same applies in a react component:
render() {
return (
<div>
{products2
.map(product =>
<div>
{product.category}
{Object.values(product.products).map(name => <p>{name}</p>)}
</div>
)
}
</div>
)
}
PS: You don't need to map twice as I did. Mapping only once and returning the div right away is also fine.

Resources