how to show only the result of the selection? - reactjs

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;
});
}

Related

How can I return the corresponding clinic according to the selected province?

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

How can I add the first to the array in useState in React?

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])

Two React-Select dropdowns resetting each other

I have two dropdown menus using React-Select:
<Select
className="type-select"
options={type_options}
onChange={filterType}
/>
<label id='filter-label'>Filter By Generation:</label>
<Select
className="gen-select"
options={generation_options}
onChange={filterGen}
/>
and the options for the two of these are as follows:
{ value: 'none', label: 'None'},
{ value: 'normal', label: 'Normal' },
{ value: 'fire', label: 'Fire' },
{ value: 'water', label: 'Water' },
{ value: 'grass', label: 'Grass' },
{ value: 'electric', label: 'Electric' },
{ value: 'ice', label: 'Ice' },
{ value: 'fighting', label: 'Fighting' },
{ value: 'poison', label: 'Poison' },
{ value: 'ground', label: 'Ground' },
{ value: 'flying', label: 'Flying' },
{ value: 'psychic', label: 'Psychic' },
{ value: 'bug', label: 'Bug' },
{ value: 'rock', label: 'Rock' },
{ value: 'ghost', label: 'Ghost' },
{ value: 'dark', label: 'Dark' },
{ value: 'dragon', label: 'Dragon' },
{ value: 'steel', label: 'Steel' },
{ value: 'fairy', label: 'Fairy' },
];
const generation_options = [
{ value: 'none', label: 'None'},
{ value: 'i', label: 'I'},
{ value: 'ii', label: 'II'},
{ value: 'iii', label: 'III'},
{ value: 'iv', label: 'IV'},
{ value: 'v', label: 'V'},
{ value: 'vi', label: 'VI'},
{ value: 'vii', label: 'VII'},
{ value: 'viii', label: 'VIII'},
]
Both of these dropdowns are stored in state using React Hooks, and in the onChange methods for both, the value for the given Select is updated and the other is reset to "none". Ex: If my first select is set to "Fire" then when I change my second select to Gen IV, the first select sets back to "none". Functionally, I already have this working and am able to use the React-Selects as I want, but the issue I'm having is that when updating one select, the other select won't change to show that it's been changed. I've tried adding value={type} where type is the state the first select corresponds to, but that just causes the React-Select component to never show the selected value. Does anyone know how to get these React-Selects to operate in the way I'm describing? I can elaborate on parts of this more if more explanation is needed.
Thanks!
Edit: Here are the filterType and filterGen methods:
function filterType(selectedOption) {
setType(selectedOption.value)
setGen("none")
if(selectedOption.value === "none") {
setPage(beginningUrl)
} else {
setPage(`https://pokeapi.co/api/v2/type/${selectedOption.value}`)
}
}
function filterGen(selectedOption) {
setGen(selectedOption.value)
setType("none")
if(selectedOption.value === "none") {
setPage(beginningUrl)
} else {
setPage(`generation-${selectedOption.value}`)
}
}
Figured it out. The issue was I was setting the state to just the value of the selected item, instead of the whole object (ie: {value: 'fire', label: 'Fire}. Fixed pieces of code below, with the changes in bold:
function filterType(selectedOption) {
**setType(selectedOption)**
**setGen({ value: 'none', label: 'None'})**
if(selectedOption.value === "none") {
setPage(beginningUrl)
} else {
setPage(`https://pokeapi.co/api/v2/type/${selectedOption.value}`)
}
}
function filterGen(selectedOption) {
**setGen(selectedOption)**
**setType({ value: 'none', label: 'None'})**
if(selectedOption.value === "none") {
setPage(beginningUrl)
} else {
setPage(`generation-${selectedOption.value}`)
}
}
<div className="select-container">
<label id='filter-label'>Filter By Type:</label>
<Select
className="type-select"
options={type_options}
onChange={filterType}
**value={type}**
/>
<label id='filter-label'>Filter By Generation:</label>
<Select
className="gen-select"
options={generation_options}
onChange={filterGen}
**value={gen}**
/>
</div>

I want to create checkbox checked in nested data in react js

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 })}
/>
);
}
}

TypeScript Error: Adding type to .map Array of Objects

I'm trying to add types to the Item object that is returned from unitedStates.map((item: Item) => {}, but I can't seem to correctly add the types.
I've defined the unitedStates array of objects as unitedStates: Array<UnitedStates> and that seems to be correct, but I'm not sure why Item is not correctly typed.
Error:
src/StatePicker.tsx:198:35 - error TS2345: Argument of type '(item: Item) => JSX.Element' is not assignable to parameter of type '(value: UnitedStates, index: number, array: UnitedStates[]) => Element'.
Types of parameters 'item' and 'value' are incompatible.
Type 'UnitedStates' is not assignable to type 'Item'.
{unitedStates.map((item: Item) => {
Types.tsx:
// TypeScript: Types
interface Props {
title: string,
onPress: Function,
onValueChange: Function,
}
interface Item {
label: string,
value: string,
key: number | string,
color: string,
};
interface UnitedStates {
label: string,
value: string,
};
United States (Array of Objects):
// United States
const unitedStates: Array<UnitedStates> = [
{ label: 'AL', value: 'AL' },
{ label: 'AK', value: 'AK' },
{ label: 'AZ', value: 'AZ' },
{ label: 'AR', value: 'AR' },
{ label: 'CA', value: 'CA' },
{ label: 'CO', value: 'CO' },
{ label: 'CT', value: 'CT' },
{ label: 'DE', value: 'DE' },
{ label: 'FL', value: 'FL' },
{ label: 'GA', value: 'GA' },
{ label: 'HI', value: 'HI' },
{ label: 'ID', value: 'ID' },
{ label: 'IL', value: 'IL' },
{ label: 'IN', value: 'IN' },
{ label: 'IN', value: 'IN' },
{ label: 'KS', value: 'KS' },
{ label: 'KY', value: 'KY' },
{ label: 'LA', value: 'LA' },
{ label: 'ME', value: 'ME' },
{ label: 'MD', value: 'MD' },
{ label: 'MA', value: 'MA' },
{ label: 'MI', value: 'MI' },
{ label: 'MN', value: 'MN' },
{ label: 'MS', value: 'MS' },
{ label: 'MO', value: 'MO' },
{ label: 'MT', value: 'MT' },
{ label: 'NE', value: 'NE' },
{ label: 'NV', value: 'NV' },
{ label: 'NH', value: 'NH' },
{ label: 'NJ', value: 'NJ' },
{ label: 'NM', value: 'NM' },
{ label: 'NY', value: 'NY' },
{ label: 'NC', value: 'NC' },
{ label: 'ND', value: 'ND' },
{ label: 'OH', value: 'OH' },
{ label: 'OK', value: 'OK' },
{ label: 'OR', value: 'OR' },
{ label: 'PA', value: 'PA' },
{ label: 'RI', value: 'RI' },
{ label: 'SC', value: 'SC' },
{ label: 'SD', value: 'SD' },
{ label: 'TN', value: 'TN' },
{ label: 'TX', value: 'TX' },
{ label: 'UT', value: 'UT' },
{ label: 'VT', value: 'VT' },
{ label: 'VA', value: 'VA' },
{ label: 'WA', value: 'WA' },
{ label: 'WV', value: 'WV' },
{ label: 'WI', value: 'WI' },
{ label: 'WY', value: 'WY' },
];
Render Method:
// Render iOS Picker
const renderIOSPicker = () => {
try {
return (
<Picker
selectedValue={state}
onValueChange={selectState}>
{unitedStates.map((item: Item) => {
return (
<Picker.Item
label={item.label}
value={item.value}
key={item.key || item.label}
color={item.color}
/>
);
})}
</Picker>
)
}
catch (error) {
console.log(error);
}
};
You're mapping UnitedStates[] but you are type-hinting the item(a UnitedStates object) in the callback as Item.
Maybe you want this
{unitedStates.map((item: UnitedStates) => {
return (
<Picker.Item
label={item.label}
value={item.value}
key={item.key || item.label}
color={item.color}
/>
);
})}
Or this
{myItems.map((item: Item) => {
return (
<Picker.Item
label={item.label}
value={item.value}
key={item.key || item.label}
color={item.color}
/>
);
})}
The issue was that I was incorrectly typing the unitedStates object with Array<UnitedStates>, so the code should look like the following:
Types:
interface UnitedStates {
[index: number]: { label: string; value: string };
map: Function,
}
unitedStates Typing:
const unitedStates: UnitedStates = [];

Resources