I'm developing a plugin to search streets with elastic search, ok?
I have a datalist to show my options to select.
When I receive info from database I create all html option elemtns and add click event to capture and handle.
But I dont know why not works onClick event that I've added to each option element.
Here is my code EDITED:
render() {
const { value, streets, error, labelError } = this.state;
return (
<div className="w-100 d-flex flex-column">
<div className="plug-search plug-search__content">
<div className="plug-inner-addon">
<input onKeyDown={this.handlePressEnter.bind(this)} onChange={this.handleSearch.bind(this)} type="text" placeholder={PLACEHOLDER} value={value} list="streets" autoComplete="on" />
<datalist id="streets">
{ streets && streets.length > 0 && streets.map((street, index) => {
return (
<Item street={street} position={index} key={index} />
);
})}
</datalist>
</div>
<div className="plug-btn-search plug-btn-search__content">
<i onClick={this.handleGetGeometry} className={`icon-search plug-search-icon`}></i>
</div>
</div>
{error &&
<div className={`plug-error plug-error__content ${(error) ? 'slideDown' : 'slideUp'}`}>
<label className="plug-label">{labelError}</label>
</div>
}
</div>
);
}
Now I've created a Item component, but still doesnt work:
class Item extends Component {
clickedOption = (event, index) => {
console.log('clicked');
console.log('value: ', event.target.value);
console.log('index: ', index);
};
render() {
return (
<div className="option" onClick={(event) => this.clickedOption(event, this.props.position)}>
<option value={this.props.street.nombre} />
</div>
)
}
}
export default Item;
Currently, <datalist /> don't support onClick events in his <options />, you could see this question, in order to apply an option in this kind of cases. Hope this help.
Thanks to Alberto Perez
Solved:
clickedOption = (event) => {
console.log('clicked');
console.log('value: ', event.target.value);
};
render() {
const { value, streets, error, labelError } = this.state;
return (
<div className="w-100 d-flex flex-column">
<div className="plug-search plug-search__content">
<div className="plug-inner-addon">
<input onInput={this.clickedOption} onChange={this.handleSearch.bind(this)} type="text" placeholder={PLACEHOLDER} value={value} list="streets" autoComplete="on" />
<datalist id="streets">
{ streets && streets.length > 0 && streets.map((street, index) => {
return (
<option value={street.nombre} key={index} />
);
})}
</datalist>
</div>
<div className="plug-btn-search plug-btn-search__content">
<i onClick={this.handleGetGeometry} className={`icon-search plug-search-icon`}></i>
</div>
</div>
{error &&
<div className={`plug-error plug-error__content ${(error) ? 'slideDown' : 'slideUp'}`}>
<label className="plug-label">{labelError}</label>
</div>
}
</div>
);
}
handleSearch = (e) => {
this.setState({
value: e.target.value
})
}
render() {
const { value, streets, error, labelError } = this.state;
return (
<div className="w-100 d-flex flex-column">
<div className="plug-search plug-search__content">
<div className="plug-inner-addon">
<input onKeyDown={this.handlePressEnter.bind(this)} onChange={this.handleSearch.bind(this)} type="text" placeholder={"placeholder"} value={value} list="streets" autoComplete="on" />
<datalist id="streets">
{ streets && streets.length > 0 && streets.map((street, index) => {
return (
<div key={index} className="option">
<option value={street.nombre} />
</div>
);
})}
</datalist>
</div>
<div className="plug-btn-search plug-btn-search__content">
<i onClick={this.handleGetGeometry} className={`icon-search plug-search-icon`}></i>
</div>
</div>
{error &&
<div className={`plug-error plug-error__content ${(error) ? 'slideDown' : 'slideUp' }`}>
<label className="plug-label">{labelError}</label>
</div>
}
</div>
);
}
Related
I am having trouble displaying my yogaCard in the return statement. When I call it as {yogaCard} I get a message saying it is undefined.
if (yogas.length > 0) {
let yogaCard = yogas.filter((yoga) => {
if (searchPose === "") {
return yoga
}
else if (
yoga.english_name.toLowerCase().includes(searchPose.toLocaleLowerCase())) {
return yoga
}
}).map((yoga) => (
<div key={yoga.id} style={{width: '20%' }} className="card"
>
<img className='yogaphoto' src={yoga.img_url}/>
<div className="card-body">
<h2>{yoga.english_name}</h2>
</div>
</div>
))
}
return (
<>
<div className="yoga">
<div className='yogasearch'>
<h1>Yoga Poses</h1>
<input type="text" class="input" placeholder="Search by pose" onChange={event => {setSearchPose(event.target.value)}}/>
</div>
<div className="row">
{yogaCard}
</div>
</div>
</>
)
}
export default IndexYogas
You're not showing how you're retrieving your yogas data from axios or any way to debug your current issue, but I'd recommend passing your data retrieved from axios to a child component that contains all those div boxes and formatting, etc.
function MainPage() {
const [yogas, setYogas] = React.useState([]);
useEffect(() => {
// axios call to populate data
requestYogaInfo().then((resp) => {
setYogas(resp.data); // this depends on the shape of your webservice response
});
}, []);
return (
<>
<div className="yoga">
<div className='yogasearch'>
<h1>Yoga Poses</h1>
<input type="text" class="input" placeholder="Search by pose" onChange={event => {setSearchPose(event.target.value)}}/>
</div>
<div className="row">
{yogas && yogas.length > 0
? (
yogas.filter((yoga) => {
if (searchPose === "") {
return yoga
}
else if (
yoga.english_name.toLowerCase().includes(searchPose.toLocaleLowerCase())) {
return yoga
}
}).map((yoga) => (
<div key={yoga.id} style={{width: '20%' }} className="card"
>
<img className='yogaphoto' src={yoga.img_url}/>
<div className="card-body">
<h2>{yoga.english_name}</h2>
</div>
</div>
))
)
: null
}
</div>
</div>
</>
)
}
I have an input and a select starting when placing any value in the case of the input, it begins to generate dynamic statements and in the case of the input, dynamic inputs are generated but in decrement, everything works fine, I only need that the dynamic inputs that begin to appear are show one by one and not all piled up as I show in the picture.
problem image
how do i want it to be
import React, { useState } from "react";
//input dynamic
import Row from "./Row2";
let initialState = {
first: null,
arraySelect: []
};
function Pruebas(props) {
/*input dynamic */
const [rows, setRows] = useState([]);
const [initialeRow, setInitialRow] = useState({ nombre: "" });
const handleOnChange = (index, value) => {
const copy = rows.map((e, i) => {
if (i === index) {
e.nombre = value;
}
return e;
});
setRows([...copy]);
};
const handleOnAdd = () => {
if (initialeRow.nombre >= 1) {
setInitialRow({ nombre: initialeRow.nombre - 1 });
setRows([...rows, initialeRow]);
}
};
/////////////////////////////////////////////////////
const [input_multi, setInput_multi] = useState();
const [arraySelect, setarraySelect] = useState(initialState.arraySelect);
const [numberIni, setnumberIni] = useState(initialState.first);
const getArray = (value) => {
let arr = [];
{
let reco = Math.round(numberIni - parseInt(value));
console.log(reco);
if (parseInt(value) == numberIni) {
return false;
}
Array(reco)
.fill(1)
.map((value2, key) => {
arr.push(parseInt(value) + parseInt(key + 1));
});
}
return arr;
};
const setSelect = (value) => {
let isArray = getArray(value);
if (isArray) {
setarraySelect([...arraySelect, isArray]);
}
//input dynamyc
if (initialeRow.nombre >= 1) {
setInitialRow({ nombre: initialeRow.nombre - 1 });
setRows([...rows, initialeRow]);
}
};
//input dynamic
const handleInput_division = (event) => {
setInitialRow({ nombre: event.target.value });
};
const handleSubmit = (event) => {
event.preventDefault();
setnumberIni(event.target.numberIni.value);
};
const resetForm = () => {
setnumberIni(null);
setarraySelect([]);
};
return (
<div>
<form onSubmit={handleSubmit}>
<div class="row">
<label>PHASES</label>
<div class="col-sm-6">
<h6>enter a number</h6>
<div class="input-group ">
<input
type="number"
name="numberIni"
placeholder="0"
class="form-control"
value={input_multi}
onChange={(event) => setInput_multi(event.target.value)}
/>
<br />
<button type="submit" className="btn btn-success"> <i class="far fa-save"></i></button>
<br />
<div class="col-sm-6">
<h6>2 - # input dynamic</h6>
<div class="input-group ">
<select name='numberIni2' class='form-control' onChange={handleInput_division}>
<option value='no' selected>
Seleccione </option>
<option value='2'> 2</option>
<option value='3'>3
</option>
</select>
<br/>
</div>
</div>
</div>
</div>
</div>
</form>
<br />
<div class="col-sm-12 btn btn-primary">
<b>PHASES</b>
</div>
<br /> <br />
<div class="row">
<div class="col-sm-12">
{numberIni && (
<div class="col-sm-12">
<label>
<font size="2">
1° PHASES <br />
select a number : {" "}
</font>
</label>
<select onChange={(e) => setSelect(e.target.value)} name="" id="">
<option value="seleccione">Seleccione</option>
{Array(parseInt(numberIni))
.fill(1)
.map((value, key) => {
return <option value={key + 1}>{key + 1} equipment</option>;
})}
</select>
<label>
<font size="2"> equipment </font>{" "}
</label>
{Array(parseInt(numberIni))
.fill(1)
.map((value, key2) => {
return (
<div>
{arraySelect[key2] && (
<>
<label>
<font size="2">
2° select another number <br />
classify: {" "}
</font>{" "}
</label>
<select
onChange={(e) => setSelect(e.target.value)}
name=""
id=""
>
<option value="seleccione">Seleccione</option>
{arraySelect[key2].map((value, key3) => {
return (
<option value={arraySelect[key2][key3]}>
{arraySelect[key2][key3]} equipment
</option>
);
})}
</select>
{rows.map((e, index) => (
<Row
nombre={e.nombre}
index={index}
onChange={(index, value) => handleOnChange(index, value)}
key={index}
/>
))}
</>
)}
</div>
);
})}
</div>
)}
</div>
</div>
{numberIni && (
<input
onClick={() => resetForm()}
type="button"
className="btn btn-danger"
value="restart phase"
/>
)}
</div>
);
}
export default Pruebas;
//Row2
const Row = (props) => {
const { onChange, onRemove, nombre, index } = props;
console.log(props);
return (
<div>
<input
disabled
value={nombre}
onChange={(e) => onChange(index, e.target.value)}
placeholder="Decrementar"
/>
</div>
);
};
export default Row;
Why filter by search work but by drop-down list not?
I don't know why this is so, maybe someone sees some error.
I would like to filter tags using checkboxes. It was hard for me to find a tutorial on the internet, I was able to find filtering by searching. It turned out that everything was set up successfully, then I wanted to set filtering by list, but here I have a problem. I don't know why the list search doesn't work - even though it seems to work on the console.
demo here:
https://codesandbox.io/s/adoring-wu-rt4wd?file=/src/styles.css
const [filterParam, setFilterParam] = useState(['All'])
const [q, setQ] = useState('')
const [searchParam] = useState(['tags'])
function search(data) {
return data.filter((item) => {
if (item.tags == filterParam) {
return searchParam.some((newItem) => {
return (
item[newItem].toString().toLowerCase().indexOf(q.toLowerCase()) > -1
)
})
} else if (filterParam == 'All') {
return searchParam.some((newItem) => {
return (
item[newItem].toString().toLowerCase().indexOf(q.toLowerCase()) > -1
)
})
}
})
}
return (
<>
<div>
<label htmlFor='search-form'>
<input
type='search'
name='search-form'
id='search-form'
className='search-input'
placeholder='Search for...'
value={q}
onChange={(e) => setQ(e.target.value)}
/>
<span className='sr-only'>Search countries here</span>
</label>
</div>
<div className='select'>
<select
onChange={(e) => {
setFilterParam(e.target.value)
// console.log(setFilterParam(e.target.value.toString()))
console.log(e.target.value.toString())
}}
aria-label='Filter Countries By Region'
>
<option value='All'>All</option>
<option value='accessibility'>accessibility</option>
<option value='javascript'>javascript</option>
<option value='css'>css</option>
<option value='advanced'>advanced</option>
<option value='svg'>svg</option>
</select>
</div>
<section className={styles.main}>
{search(data).map((item) => (
<div className={styles.card}>
<div>
<div className={styles.card__first}>
<div className={styles.card__name}>
<FaTwitter className={styles.card__icon} />
<span className={styles.card__author}>{item.authorId}</span>
</div>
<div className={styles.card__price}>
<p>{item.price}</p>
</div>
</div>
<div className={styles.card__title}>
<h1>{item.title}</h1>
</div>
<div>
<p className={styles.card__desc}>{item.description}</p>
</div>
</div>
<div className={styles.card__tags}>
{item.tags.map((t) => {
return (
<div className={styles.card__tag}>
<p>{t}</p>
</div>
)
})}
</div>
</div>
))}
</section>
</>
)
}
export default Page
You have to change a lot of things, you can try this example
import "./styles.css";
import { useState, useEffect } from "react";
import styles from "./App.module.css";
export default function App() {
const [data, setData] = useState([]);
const [filterParam, setFilterParam] = useState("All");
const [q, setQ] = useState("");
const [searchParam, setSearchParam] = useState([]);
const getData = () => {
fetch("data.json", {
headers: {
"Content-Type": "application/json",
Accept: "application/json"
}
})
.then(function (response) {
console.log(response);
return response.json();
})
.then(function (myJson) {
console.log(myJson);
setData(myJson);
});
};
useEffect(() => {
getData();
}, []);
function search(data) {
return data.filter(
(item) =>
(filterParam === "All" || item.tags.includes(filterParam)) &&
(searchParam.length === 0 ||
(searchParam.every((tag) => item.tags.includes(tag)) &&
JSON.stringify(item).toLowerCase().indexOf(q.toLowerCase()) > -1))
);
}
const inputChangedHandler = (event) => {
const value = event.target.value;
const index = searchParam.indexOf(value);
if (index > -1) {
const updatedParam = [...searchParam];
updatedParam.splice(index, 1);
setSearchParam(updatedParam);
} else {
setSearchParam([...searchParam, event.target.value]);
}
};
return (
<>
<div>
<label htmlFor="search-form">
<input
type="search"
name="search-form"
id="search-form"
className="search-input"
placeholder="Search for..."
value={q}
onChange={(e) => setQ(e.target.value)}
/>
<span className="sr-only">Search countries here</span>
</label>
</div>
<div className="select">
<select
onChange={(e) => {
setFilterParam(e.target.value);
// console.log(setFilterParam(e.target.value.toString()))
console.log(e.target.value.toString());
}}
aria-label="Filter Countries By Region"
>
<option value="All">All</option>
<option value="accessibility">accessibility</option>
<option value="javascript">javascript</option>
<option value="css">css</option>
<option value="advanced">advanced</option>
<option value="svg">svg</option>
</select>
</div>
<div>
<input
type="checkbox"
id="topping"
name="advanced"
value="advanced"
onChange={inputChangedHandler}
/>
advanced
</div>
<div>
<input
type="checkbox"
id="topping"
name="javascript"
value="javascript"
onChange={inputChangedHandler}
/>
javascript
</div>
<div>
<input
type="checkbox"
id="topping"
name="fundamentals"
value="fundamentals"
onChange={inputChangedHandler}
/>
fundamentals
</div>
<div>
<input
type="checkbox"
id="topping"
name="css"
value="css"
onChange={inputChangedHandler}
/>
css
</div>
<div>
<input
type="checkbox"
id="topping"
name="svg"
value="svg"
onChange={inputChangedHandler}
/>
svg
</div>
<div>
<input
type="checkbox"
id="topping"
name="accessibility"
value="accessibility"
onChange={inputChangedHandler}
/>
accessibility
</div>
<section className={styles.main}>
{search(data).map((item) => (
<div className={styles.card}>
<div>
<div className={styles.card__first}>
<div className={styles.card__name}>
<p className={styles.card__icon}>ICON</p>
<span className={styles.card__author}>{item.authorId}</span>
</div>
<div className={styles.card__price}>
<p>{item.price}</p>
</div>
</div>
<div className={styles.card__title}>
<h1>{item.title}</h1>
</div>
<div>
<p className={styles.card__desc}>{item.description}</p>
</div>
</div>
<div className={styles.card__tags}>
{item.tags.map((t) => {
return (
<div className={styles.card__tag}>
<p>{t}</p>
</div>
);
})}
</div>
</div>
))}
</section>
{/* <Margins>
<Header data={data} />
<Main data={data} />
</Margins> */}
</>
);
}
enter link description here
I have the following React component (using hooks), which lists a number of Tasks as a dropdown list. When an item is selected from the list, I want to display an Update form. This works only when an item is selected for the first time. When I select a new item, nothing happens (although console.log(e.target.value); prints the correct value). I store the selected task's id in st_taskId.
I wonder if you see any issues in the code below:
const ManageReviewTasks = props => {
const reviewRoundId = props.match.params.reviewRoundId;
const [st_taskId, set_taskId] = useState();
useEffect(() => {
if (props.loading == false && st_taskId == null)
props.fetchReviewTasksByReviewRound(reviewRoundId);
}, [reviewRoundId, st_taskId]);
if (props.loading == true) {
return <div>Loading...</div>;
}
return (
<>
{props.reviewTasks && (
<div>
<h3>Configure the Review Tasks</h3>
<br />
{
<div>
<div>
<h4>
Tasks for <span className="font-italic">students receiving</span> feedback:
</h4>
<select
className="form-control"
onChange={e => {
e.preventDefault();
console.log(e.target.value);
set_taskId(e.target.value);
}}>
<option>--SELECT--</option>
{Object.keys(props.reviewTasks).map(id => {
const task = props.reviewTasks[id];
{
if (task.isForStudent) {
return (
<option key={id} id={id} value={id}>
{task.title}
</option>
);
}
}
})}
</select>
</div>
{props.reviewTasks[st_taskId] && (
<UpdateReviewTaskForm task={props.reviewTasks[st_taskId]} />
)}
</div>
}
</div>
)}
</>
);
};
Below is the code for the UpdateReviewTaskForm component:
const UpdateReviewTaskForm = (props) => {
const [st_Title, set_Title] = useState(props.task.title);
const [st_Description, set_Description] = useState(RichTextEditor.createValueFromString(props.task.description, 'html'));
const [st_startDate, set_startDate] = useState(new Date(props.task.startDate.replace('-', '/')));
const [st_DueDate, set_DueDate] = useState(new Date(props.task.dueDate.replace('-', '/')));
const handleCancelClick = (event) => {
event.preventDefault();
history.goBack();
}
const onSubmit_saveTask = (e) => {
e.preventDefault();
props.updateReviewTask({
Id: props.task.id,
Title: st_Title,
Description: st_Description.toString('html'),
StartDate: format(st_startDate, 'DD/MM/YYYY'),
DueDate: format(st_DueDate, 'DD/MM/YYYY'),
})
}
if (props.loading)
return <div>Updating...</div>
return (
<div>
<br/>
<br/>
<div className="p-3 bg-light">
<h3 className="text-info">Update the Task:</h3>
{
props.task &&
<form onSubmit={onSubmit_saveTask}>
<div className="form-group">
<label>Enter the title</label>
<input
//placeholder="Enter a title..."
value={st_Title}
onChange={(event) => { set_Title(event.target.value) }}
className="form-control" />
</div>
<div className="form-group">
<label>Enter a description for the assessment</label>
<RichTextEditor
value={st_Description}
onChange={set_Description}
/>
</div>
<div className="form-group">
<label>Start date to start: </label>
<DatePicker
className="form-control"
selected={st_startDate}
onChange={(date) => set_startDate(date)}
/>
</div>
<div className="form-group">
<label>Due date to complete: </label>
<DatePicker
className="form-control"
selected={st_DueDate}
onChange={(date) => set_DueDate(date)}
/>
</div>
<br />
<button type="submit" className="btn btn-primary">Submit</button>
<button type="reset" className="btn btn-light" onClick={handleCancelClick}>Cancel</button>
</form>
}
</div>
</div>
)
}
Because you are using internal state in UpdateReviewTaskForm, even if this component re-render for the second time, its state will not be reset (to the default value props.task.title for example).
One way to force the state to reset is to use a key prop in UpdateReviewTaskForm like this :
{props.reviewTasks[st_taskId] && (
<UpdateReviewTaskForm key={st_taskId} task={props.reviewTasks[st_taskId]} />
)}
Another way is to use useEffect inside UpdateReviewTaskForm to run when props.task change
useEffect(() => {
// reset the state here
}, [props.task])
I try to implement renderField for radio buttons, i can display it but when i click on radio field does not fill.
When i check the console, value of input is equal to undefined, always !
This is my code :
render(){
const {input, array, meta, label} = this.props;
return(
<div className="input-row">
<div className="radio-box">
{array.map((option,i) =>
<div className="radio-field" key={i}>
<input type='radio' name={option.name} onChange={() => {input.onChange('oui')}} value={option.value} checked={input.value === option.value} />
{/* Try this before <input type='radio' {...input} name={option.name} value={option.value} checked={input.value == option.value}/> */}
<label>{option.name}</label>
</div>
)}
</div>
</div>
)
}
I call this with :
<Field name="courtage" type="radio" label="Courtage ?" component={renderRadioField} array={selectOptions.courtage} {...courtage} />
SelectOptions.courtage is an array of object.
After few hours, I find a solution, I play with the state :
setRadioState(a) {
const obj = {};
obj[a.target.name] = a.target.value;
this.setState(obj);
}
render(){
const {input, array, meta, label, name} = this.props;
return(
<div className="input-row">
<div className="label-box">
<label>{label}</label>
</div>
<div className="radio-box">
{array.map((option,i) =>
<div className="radio-field" key={i}>
<input type='radio' name={name} {...input} onChange={this.setRadioState.bind(this)} value={option.value} checked={this.state.name} />
<label>{option.name}</label>
</div>
)}
{/* <div className="errors">{meta.touched && ((error && <span>{error}</span>))}</div> */}
</div>
</div>
)