My data is in nested array objects. I want to make checked/unchecked the nodes like a tree view. ie. when any child node is selected then the parent node is checked itself.
This is my nested JSON. From this object, I create a tree view from this data:
const nodes = [
{
value: "/app",
label: "app",
children: [
{
value: "/app/Http",
label: "Http",
children: [
{
value: "/app/Http/Controllers",
label: "Controllers",
children: [
{
value: "/app/Http/Controllers/WelcomeController.js",
label: "WelcomeController.js",
},
],
},
{
value: "/app/Http/routes.js",
label: "routes.js",
},
],
},
{
value: "/app/Providers",
label: "Providers",
children: [
{
value: "/app/Http/Providers/EventServiceProvider.js",
label: "EventServiceProvider.js",
},
],
},
],
},
{
value: "/config",
label: "config",
children: [
{
value: "/config/app.js",
label: "app.js",
},
{
value: "/config/database.js",
label: "database.js",
},
],
},
{
value: "/public",
label: "public",
children: [
{
value: "/public/assets/",
label: "assets",
children: [
{
value: "/public/assets/style.css",
label: "style.css",
},
],
},
{
value: "/public/index.html",
label: "index.html",
},
],
},
{
value: "/.env",
label: ".env",
},
{
value: "/.gitignore",
label: ".gitignore",
},
{
value: "/README.md",
label: "README.md",
},
];
I am using this function to make parent checked when child is checked.
checkChange(targetNode: any, event) {
/// debugger;
const targetNodeId = targetNode.id;
this.findIndexNestedforCheckbox(targetNode, targetNodeId);
let newTableData = [...this.state.tableData];
this.setState({ tableData: newTableData, isActionFooter: true });
}
findIndexNestedforCheckbox(data, index) {
if (data.id === index) data.isChecked = "Yes";
let result;
const i = (data.children || []).findIndex((child) => {
child.isChecked = "Yes";
return (result = this.findIndexNestedforCheckbox(child, index));
});
if (result) return [i, ...result];
}
npm install react-checkbox-tree
import React from 'react';
import CheckboxTree from 'react-checkbox-tree';
const nodes = [{
value: 'mars',
label: 'Mars',
children: [
{ value: 'phobos', label: 'Phobos' },
{ value: 'deimos', label: 'Deimos' },
],
}];
class Widget extends React.Component {
state = {
checked: [],
expanded: [],
};
render() {
return (
<CheckboxTree
nodes={nodes}
checked={this.state.checked}
expanded={this.state.expanded}
onCheck={checked => this.setState({ checked })}
onExpand={expanded => this.setState({ expanded })}
/>
);
}
}
Related
I need to select a province in the select to return the clinics that are located in that province, but when I select a province I get this error TypeError: termSearch.toLowerCase is not a function. I am a little lost in this part of the code, any help is appreciated.//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
import React, { useState, useEffect } from 'react'
import Select, { SingleValue } from 'react-select'
import { getClinic } from '../../api/drupalAPI'
import {Clinic} from '#icofcv/common';
export const SearchFilterClinics = () => {
////filter
type OptionType = {
value: string;
label: string;
};
const provincesList: OptionType[] = [
{ value: 'Todos', label: 'Todos' },
{ value: 'Alava/Araba', label: 'Alava/Araba' },
{ value: 'Albacete', label: 'Albacete' },
{ value: 'Alicante', label: 'Alicante' },
{ value: 'Almería', label: 'Almería' },
{ value: 'Avila', label: 'Avila' },
{ value: ' Badajoz', label: ' Badajoz' },
{ value: 'Islas Baleares', label: 'Islas Baleares' },
{ value: 'Barcelona', label: 'Barcelona' },
{ value: 'Burgos', label: 'Burgos' },
{ value: 'Cáceres', label: 'Cáceres' },
{ value: 'Cádiz', label: 'Cádiz' },
{ value: 'Castellón', label: 'Castellón' },
{ value: 'Ciudad Real', label: 'Ciudad Real' },
{ value: 'Córdoba', label: 'Córdoba' },
{ value: 'A Coruña/La Coruña', label: 'A Coruña/La Coruña' },
{ value: 'Cuenca', label: 'Cuenca' },
{ value: 'Gerona/Girona', label: 'Gerona/Girona' },
{ value: 'Granada', label: 'Granada' },
{ value: 'Guadalajara', label: 'Guadalajara' },
{ value: 'Gipuzkoa/Guipuzcoa', label: 'Gipuzkoa/Guipuzcoa' },
{ value: 'Huelva', label: 'Huelva' },
{ value: 'Huesca', label: 'Huesca' },
{ value: 'Jaen', label: 'Jaen' },
{ value: 'León', label: 'León' },
{ value: 'Lérida/Lleida', label: 'Lérida/Lleida' },
{ value: 'La Rioja', label: 'La Rioja' },
{ value: 'Lugo', label: 'Lugo' },
{ value: 'Madrid', label: 'Madrid' },
{ value: ' Málaga', label: ' Málaga' },
{ value: 'Murcia', label: 'Murcia' },
{ value: 'Navarra', label: 'Navarra' },
{ value: 'Orense/Ourense', label: 'Orense/Ourense' },
{ value: 'Asturias', label: 'Asturias' },
{ value: 'Palencia', label: 'Palencia' },
{ value: 'Las Palmas', label: 'Las Palmas' },
{ value: 'Pontevedra', label: 'Pontevedra' },
{ value: 'Salamanca', label: 'Salamanca' },
{ value: 'S.C.Tenerife', label: 'S.C.Tenerife' },
{ value: 'Cantabria', label: 'Cantabria' },
{ value: 'Segovia', label: 'Segovia' },
{ value: ' Sevilla', label: ' Sevilla' },
{ value: 'Soria', label: 'Soria' },
{ value: 'Tarragona', label: 'Tarragona' },
{ value: 'Teruel', label: 'Teruel' },
{ value: 'Toledo', label: 'Toledo' },
{ value: 'Valencia', label: 'Valencia' },
{ value: 'Valladolid', label: 'Valladolid' },
{ value: 'Bizkaia/Vizcaya', label: 'Bizkaia/Vizcaya' },
{ value: 'Zamora', label: 'Zamora' },
{ value: 'Zaragoza', label: 'Zaragoza' },
{ value: 'Ceuta', label: 'Ceuta' },
{ value: 'Melilla', label: 'Melilla' },
]
const [clinicList, setClinicList] = useState<Clinic[]>([]);
const [clinicListFilteredSelect, setClinicListFilteredSelect] = useState<Clinic[]>([]);
const [filterSelectClinic, setFilterSelectClinic] = useState<SingleValue<OptionType>>(provincesList[0]);
const fetchClinicList = async () => {
getClinic().then((response)=>{
console.log(response)
setClinicList(response);
setClinicListFilteredSelect(response)
}).catch ( (error) => {
console.error(error);
throw error;
});
}
const handleChangeSelect = (provinceList: SingleValue<OptionType>) =>{
console.log(provinceList)
setFilterSelectClinic(provinceList);
filterSelect(provinceList );
}
const filterSelect=(termSearch)=>{
const resultFilterSelect = clinicList.filter((element) => {
if(element.province?.toString().toLowerCase().includes(termSearch.toLowerCase() )
){
return element;
}
});
setClinicListFilteredSelect(resultFilterSelect);
}
useEffect (() => {
fetchClinicList();
}, []);
return (
<>
<div>
<h1>Encuentra tu clínica</h1>
</div>
<div>
<Select
defaultValue={filterSelectClinic}
options={provincesList}
onChange={handleChangeSelect}
/>
{
clinicListFilteredSelect.map((clinic) => (
<div>
<div>{clinic.title}</div>
<div>{clinic.propsPhone}</div>
<div>{clinic.mobile}</div>
<div>{clinic.email}</div>
<div>{clinic.province} </div>
<div>{clinic.registry}</div>
</div>
))
}
</div>
</>
)
}
In your filterSelect function, you are implicitly expecting termSearch to be a string termSearch: string. Looking at where filterSelect is used in handleChangeSelect it is passed this parameter provinceList: SingleValue<OptionType>.
Therefore the fix is:
termSearch.value.toLowerCase()
And putting it into context with your code, this line:
if(element.province?.toString().toLowerCase().includes(termSearch.value.toLowerCase() )
That's because SingleValue<OptionType> has the property getter .value
my current code shows a complete list of clinics, when in the selector I choose a province, it shows me the clinics located in that province, what I would like is not to show the complete list of clinics at the beginning but only show the result when filtering by province. That is to say, when starting the application that only the selection is seen and once the province is selected, the results will be shown.
import React, { useState, useEffect } from 'react'
import Select, { SingleValue } from 'react-select'
import { getClinic } from '../../api/drupalAPI'
import {Clinic} from '#icofcv/common';
export const SearchFilterClinics = () => {
////filter
type OptionType = {
value: string;
label: string;
};
const provincesList: OptionType[] = [
{ value: 'Todos', label: 'Todos' },
{ value: 'Alava/Araba', label: 'Alava/Araba' },
{ value: 'Albacete', label: 'Albacete' },
{ value: 'Alicante', label: 'Alicante' },
{ value: 'Almería', label: 'Almería' },
{ value: 'Avila', label: 'Avila' },
{ value: ' Badajoz', label: ' Badajoz' },
{ value: 'Islas Baleares', label: 'Islas Baleares' },
{ value: 'Barcelona', label: 'Barcelona' },
{ value: 'Burgos', label: 'Burgos' },
{ value: 'Cáceres', label: 'Cáceres' },
{ value: 'Cádiz', label: 'Cádiz' },
{ value: 'Castellón', label: 'Castellón' },
{ value: 'Ciudad Real', label: 'Ciudad Real' },
{ value: 'Córdoba', label: 'Córdoba' },
{ value: 'A Coruña/La Coruña', label: 'A Coruña/La Coruña' },
{ value: 'Cuenca', label: 'Cuenca' },
{ value: 'Gerona/Girona', label: 'Gerona/Girona' },
{ value: 'Granada', label: 'Granada' },
{ value: 'Guadalajara', label: 'Guadalajara' },
{ value: 'Gipuzkoa/Guipuzcoa', label: 'Gipuzkoa/Guipuzcoa' },
{ value: 'Huelva', label: 'Huelva' },
{ value: 'Huesca', label: 'Huesca' },
{ value: 'Jaen', label: 'Jaen' },
{ value: 'León', label: 'León' },
{ value: 'Lérida/Lleida', label: 'Lérida/Lleida' },
{ value: 'La Rioja', label: 'La Rioja' },
{ value: 'Lugo', label: 'Lugo' },
{ value: 'Madrid', label: 'Madrid' },
{ value: ' Málaga', label: ' Málaga' },
{ value: 'Murcia', label: 'Murcia' },
{ value: 'Navarra', label: 'Navarra' },
{ value: 'Orense/Ourense', label: 'Orense/Ourense' },
{ value: 'Asturias', label: 'Asturias' },
{ value: 'Palencia', label: 'Palencia' },
{ value: 'Las Palmas', label: 'Las Palmas' },
{ value: 'Pontevedra', label: 'Pontevedra' },
{ value: 'Salamanca', label: 'Salamanca' },
{ value: 'S.C.Tenerife', label: 'S.C.Tenerife' },
{ value: 'Cantabria', label: 'Cantabria' },
{ value: 'Segovia', label: 'Segovia' },
{ value: ' Sevilla', label: ' Sevilla' },
{ value: 'Soria', label: 'Soria' },
{ value: 'Tarragona', label: 'Tarragona' },
{ value: 'Teruel', label: 'Teruel' },
{ value: 'Toledo', label: 'Toledo' },
{ value: 'Valencia', label: 'Valencia' },
{ value: 'Valladolid', label: 'Valladolid' },
{ value: 'Bizkaia/Vizcaya', label: 'Bizkaia/Vizcaya' },
{ value: 'Zamora', label: 'Zamora' },
{ value: 'Zaragoza', label: 'Zaragoza' },
{ value: 'Ceuta', label: 'Ceuta' },
{ value: 'Melilla', label: 'Melilla' },
]
const [clinicList, setClinicList] = useState<Clinic[]>([]);
const [clinicListFilteredSelect, setClinicListFilteredSelect] = useState<Clinic[]>([]);
const [filterSelectClinic, setFilterSelectClinic] = useState<SingleValue<OptionType>>(provincesList[0]);
const fetchClinicList = async () => {
getClinic().then((response)=>{
console.log(response)
setClinicList(response);
setClinicListFilteredSelect(response)
}).catch ( (error) => {
console.error(error);
throw error;
});
}
const handleChangeSelect = (provinceList: SingleValue<OptionType>) =>{
console.log(provinceList)
setFilterSelectClinic(provinceList);
filterSelect(provinceList );
}
const filterSelect=(termSearch)=>{
const resultFilterSelect = clinicList.filter((element) => {
if(element.province?.toString().toLowerCase().includes(termSearch.value.toLowerCase() )
){
return element;
}
});
setClinicListFilteredSelect(resultFilterSelect);
}
useEffect (() => {
fetchClinicList();
}, []);
return (
<>
<div>
<h1>Encuentra tu clínica</h1>
</div>
<div>
<Select
defaultValue={filterSelectClinic}
options={provincesList}
onChange={handleChangeSelect}
/>
{
clinicListFilteredSelect.map((clinic) => (
<div>
<div>{clinic.title}</div>
<div>{clinic.propsPhone}</div>
<div>{clinic.mobile}</div>
<div>{clinic.email}</div>
<div>{clinic.province} </div>
<div>{clinic.registry}</div>
</div>
))
}
</div>
</>
)
}
You're setting clinicListFilteredSelect in your useEffect with an empty dependancy array. This means when your component mounts it will set clinicListFilteredSelect to the response of your API call.
If you instead want to only show the response when filterting by clinics, you need to move this call to the event handler and remove the useEffect.
Something like:
const handleChangeSelect = async (provinceList: SingleValue<OptionType>) => {
getClinic().then((response) => {
setClinicList(response);
setClinicListFilteredSelect(response)
setFilterSelectClinic(provinceList);
filterSelect(provinceList );
}).catch ((error) => {
console.error(error);
throw error;
});
}
I have an array object called tempArr.
When I run a function called fetchLifeCycle, i want to act setPickerItems(tempArr); is mandatory first, and then setPickerItems([...tempArr, { label: 'Not selected', value: "NONE" }]) .
As a result, { label: 'not selected', value: "NONE" } was added at the end.
But I want to add that object to the first object of pickerItems. How do I do that?
this is my code
tempArr = [
{ label: "hi", value: 'egg' },
{ label: "bye", value: 'insect' },
{ label: "woo", value: 'pest' },
{ label: "pick", value: 'hambuger' },
]
const [pickerItems, setPickerItems] = useState([])
const fetchLifeCycle = () => {
setPickerItems(tempArr);
setPickerItems([...tempArr, { label: '선택안함', value: "NONE" }])
}
expected answer
pickerItems = [
{ label: '선택안함', value: "NONE" }
{ label: "hi", value: 'egg' },
{ label: "bye", value: 'insect' },
{ label: "woo", value: 'pest' },
{ label: "pick", value: 'hambuger' },
]
tempArr = [
{ label: "hi", value: 'egg' },
{ label: "bye", value: 'insect' },
{ label: "woo", value: 'pest' },
{ label: "pick", value: 'hambuger' },
]
const updated = [{ label: '선택안함', value: "NONE" }, ...tempArr]
console.log('updated', updated)
You just have to reverse the order:
setPickerItems([{ label: '선택안함', value: "NONE" }, ...tempArr])
You can put the new item first, then spread the existing array:
setPickerItems([{ label: '선택안함', value: "NONE" }, ...tempArr])
Just simple:
setPickerItems([{ label: '선택안함', value: "NONE" }, ...tempArr])
I have one list look like allsettings. I want to convert that list to a new list. Since I am new to react I don't have much idea, I tried by doing the below way but 1st item in the new list is always empty.
const [mySetting, setMySet] = useState([]);
useEffect(() => {
const allSettings = [
{ name: "Setting1", value: true, label: 1 },
{ name: "Setting2", value: true, label: 2 },
{ name: "Setting3", value: true, label: 3 },
{ name: "Setting4", value: false, label: 4 },
{ name: "Setting5", value: true, label: 5 },
{ name: "Setting6", value: true, label: 6 },
{ name: "Setting7", value: true, label: 7 }
];
const settings = [];
const allSettingsMap = allSettings.reduce((resMap, current) => {
settings.push(resMap);
return {
...resMap,
SettingID: current.label,
Name: current.name,
value: current.value
};
}, {});
setMySet(settings);
}, []);
//I want new list like this:
const newSettings = [
{ name: "Setting1", value: true, SettingID: 1 },
{ name: "Setting2", value: true, SettingID: 2 },
{ name: "Setting3", value: true, SettingID: 3 },
{ name: "Setting4", value: false, SettingID: 4 },
{ name: "Setting5", value: true, SettingID: 5 },
{ name: "Setting6", value: true, SettingID: 6 },
{ name: "Setting7", value: true, SettingID: 7 }
];
You can use array#map to rename a key in your object and keeping other keys intact. For each object, you can pick label and rename it to SettingID and keep other key-values same.
const allSettings = [ { name: "Setting1", value: true, label: 1 }, { name: "Setting2", value: true, label: 2 }, { name: "Setting3", value: true, label: 3 }, { name: "Setting4", value: false, label: 4 }, { name: "Setting5", value: true, label: 5 }, { name: "Setting6", value: true, label: 6 }, { name: "Setting7", value: true, label: 7 } ],
result = allSettings.map(({label, ...other}) => ({...other, SettingID: label}));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can easily do it by map on array
const allSettings = [
{ name: "Setting1", value: true, label: 1 },
{ name: "Setting2", value: true, label: 2 },
{ name: "Setting3", value: true, label: 3 },
{ name: "Setting4", value: false, label: 4 },
{ name: "Setting5", value: true, label: 5 },
{ name: "Setting6", value: true, label: 6 },
{ name: "Setting7", value: true, label: 7 }
];
const newAllSettings = allSettings.map(item => {
return {
name: item.name,
value: item.value,
SettingID:item.label
};
});
console.log(newAllSettings)
Replace your allSettings.reduce method with this map method
const settings = [];
allSettings.map((setting) => {
const item = { ...setting };
const tempValue = item?.label;
// delete item label
delete item["label"];
item["SettingID"] = tempValue;
settings.push(item);
});
I am getting array in props which is props.logsInfo.logs and I want to use it according to the number of elements in array instead of hard coding it like props.logsInfo.logs[0]['id']. I want to use map.Logs array size can be more than one.I don't want to write one more cells: [
{ key: 'cell-0', children: props.logsInfo.logs[1]['id'] },How can i achieve it??
import React from 'react';
import Table from 'terra-table';
const StripedTable = props => (
<Table
summaryId="striped-table"
summary="This table displays striped rows."
numberOfColumns={4}
dividerStyle="horizontal"
headerData={{
cells: [
{ id: 'header-Id', key: 'id', children: 'Id' },
{ id: 'header-vendorId', key: 'vendorId', children: 'VendorId' },
{ id: 'header-userId', key: 'userId', children: 'UserId' },
{ id: 'header-payLoad', key: 'payLoad', children: 'PayLoad' },
],
}}
bodyData={[
{
rows: [
{
key: 'row-0',
cells: [
{ key: 'cell-0', children: props.logsInfo.logs[0]['id'] },
{ key: 'cell-1', children: props.logsInfo.logs[0]['vendorId'] },
{ key: 'cell-2', children: props.logsInfo.logs[0]['userId'] },
{ key: 'cell-3', children: props.logsInfo.logs[0]['payLoad']},
],
},
],
},
]}
/>
);
export default StripedTable;
Yes, you can use .map:
bodyData={[
{
rows: props.logsInfo.logs.map(log => ({
key: log.id,
cells: [
{ key: 'cell-0', children: log.id },
{ key: 'cell-1', children: log.vendorId },
{ key: 'cell-2', children: log.userId },
{ key: 'cell-3', children: log.payLoad},
],
}),
},
]}
You can also do the same for cells if you keep an array with the field names around:
const fields = ['id', 'vendorId', 'userId', 'payLoad'];
// ...
bodyData={[
{
rows: props.logsInfo.logs.map(log => ({
key: log.id,
cells: fields.map(field => ({key: field, children: log[field]})),
}),
},
]}