How to implement `Search box` through `props items` using ReactJs - javascript

I want to implement search box from my set of props data .
I tried to follow this article https://dev.to/iam_timsmith/lets-build-a-search-bar-in-react-120j but i guess i m doing some silly mistakes.
any help to correct my mistake would be helpful for me.
//allbook.js
class AllBook extends Component {
constructor(props){
super(props);
this.state = {
search : ""
}
}
updateSearch(e){
this.setState({search: e.target.value.substr(0, 20)});
}
render(){
let filteredBooks = this.props.posts.filter(
(posts) => {
return posts.title.toLowerCase().indexOf(this.state.search.toLowerCase()) !== -1;
}
);
return(
<div>
{Object.keys(filteredBooks).length !== 0 ? <h1 className="post-heading">All books</h1> : <h1 className="post-heading">No Books available</h1>} {/*To check if array is empty or not*/}
{Object.keys(filteredBooks).length !== 0 ?
<input className="post-heading" type="text" value={this.state.search} onChange={this.updateSearch.bind(this)}/> : ""}
{/*Arrow function to map each added object*/}
{filteredBooks.map((post) =>(
<div key={post.id}>
{post.editing ? <EditComponent post={post} key={post.id}/> :
<Post key={post.id} post={post}/>}
</div>
))}
</div>
);
}
}
const mapStateToProps = (state) => {
return{
posts: state
}
}
export default connect(mapStateToProps)(AllBook);

Your updated code seems to be pretty close. I think you might experience a problem with using indexOf() though, since that will only find the index of a single-character within a string (title). This would not be good for multi-character searches (like full-words).
Try using .includes() instead so that you can at least search against complete words and titles. It's essentially a better version of .indexOf()
See sandbox for example: https://codesandbox.io/s/silly-currying-3zpvk
Working code:
class AllBook extends Component {
constructor(props){
super(props);
this.state = {
search : ""
}
}
updateSearch(e){
this.setState({search: e.target.value.substr(0, 20)});
}
render(){
let filteredBooks = this.props.posts.filter(
(posts) => {
return posts.title.toLowerCase().includes(this.state.search.toLowerCase());
}
);
return(
<div>
{Object.keys(filteredBooks).length !== 0 ? <h1 className="post-heading">All books</h1> : <h1 className="post-heading">No Books available</h1>} {/*To check if array is empty or not*/}
{Object.keys(filteredBooks).length !== 0 ?
<input className="post-heading" type="text" value={this.state.search} onChange={this.updateSearch.bind(this)}/> : ""}
{/*Arrow function to map each added object*/}
{filteredBooks.map((post) =>(
<div key={post.id}>
{post.editing ? <EditComponent post={post} key={post.id}/> :
<Post key={post.id} post={post}/>}
</div>
))}
</div>
);
}
}
const mapStateToProps = (state) => {
return{
posts: state
}
}
export default connect(mapStateToProps)(AllBook);

Updated code which is workable react search.

Related

how fix selected permanently ReactJS

I would like to explain my problem of the day.
the code works correctly ,
the only problem is
when i click on my navbar to select a tab ,
my activeclassname works fine except that when i click elsewhere on the same page i lose my activeclassname
I would like him to be active permanently
Do you have an idea of how to fix this?
class MainHome extends Component {
constructor(props) {
super(props);
this.state = {
};
// preserve the initial state in a new object
this.toggle = this.toggle.bind(this);
this.cgtChange1= this.cgtChange1.bind(this);
this.cgtChange2= this.cgtChange2.bind(this);
}
cgtChange1() {
console.log('bière clicked')
this.setState({
cgt : 1
})
}
cgtChange2() {
console.log('cocktails clicked')
this.setState({
cgt :2
})
}
render() {
let addedItems = this.props.items.length ?
(
this.props.items.filter(item => item.ctg === this.state.cgt).map(item => {
return (
<div key={item.id}>
{item.title}
</div>
)
})) :
(
<div></div>
)
return (
<div>
<Header text='Carte'/>
<NavBar
onClick1={this.cgtChange1}
onClick2={this.cgtChange2}
/>
{addedItems}
</div>
)
}
}
NavBar
export default class FocusOnSelect extends Component {
render() {
return (
<div>
<button onClick={this.props.onClick1}
activeClasseName="selected" className='inactive' > Bières
</button>
</div>
<div >
<button onClick={this.props.onClick2} activeClasseName="selected" className='inactive' > Cocktails </button>
</div>
</div>
);
}
}

React | Reusable dropdown component | how to get selected option?

Fairly new with react. I'm creating a dropdown button for a Gatsby project. The button toggle works, but I'm having trouble getting the selected value to the parent where I need it.
-Tried lifting the state up, but this resulted in the button not appearing at all. I was a bit confused here so maybe I was doing something wrong.
-Also tried using refs although I wasn't sure if this was the right use case, it worked, however it seems the value is grabbed before it's updated in the child component and I'm not sure how to change or work around this. (the code is currently set up for this)
Are either of these options right? or could anybody steer me in the right direction, thanks.
Dropdown in parent:
this.dropdownRef1 = React.createRef();
componentDidUpdate(){
console.log("Color Option:" + this.dropdownRef1.current.state.ColorOption)
}
<DropdownBtn ref={this.dropdownRef1} mainText="Color" options={this.props.pageContext.colors || ['']} />
DropdownBtn:
export default class refineBtn extends React.Component {
constructor(props) {
super(props);
}
state = {
open: false,
[this.props.mainText + "Option"]: "all",
};
dropdownBtnToggle = () => {
this.setState((prevState)=> {
return{open: !prevState.open};
});
};
optionClickHandler = (option) => {
this.setState(() => {
console.log(this.props.mainText + " updated to " + option)
return {[this.props.mainText + "Option"] : option}
});
};
render(){
const options = this.props.options
console.log("open: " + this.state.open)
return(
<div>
<button onClick={this.dropdownBtnToggle} >
{this.props.mainText}:
</button>
<div className={this.state.open ? 'option open' : "option"} >
<p key={"all"} onClick={() => this.optionClickHandler("all")}> all</p>
{options.map(option => (
<p key={option} onClick={() => this.optionClickHandler(option)}>{option}</p>
))}
</div>
</div>
);
}
}
You can respond to selection by allowing your component to accept a callback.
class MyComponent extends React.Component {
constructor(props) {
super(props)
this.state = {open: false, value: ''}
}
render() {
return (
<div>
<div onClick={() => this.setState({open: true})}>{this.state.value}</div>
<div style={{display: this.state.open ? 'block' : 'none'}}>
{this.props.options.map((option) => {
const handleClick = () => {
this.setState({open: false, value: option})
this.props.onChange(option)
}
return (
<div key={option} onClick={handleClick} className={this.state.value === option ? 'active' : undefined}>{option}</div>
)
})}
</div>
</div>
)
}
}
<MyComponent onChange={console.log} options={...}/>

How to remove a button if there is no more info in the api

The following code is running smoothly, but I want to implement it in a way that when I do a getNextPers() and there is no info, it hides/removes the Ver Mais button. I've been looking for solutions but have found none, so any help is good. Thank you.
import React from 'react';
import ReactDOM from 'react-dom';
import axios from 'axios';
class List extends React.Component {
constructor(props){
super(props);
this.state = {
personagens: [],
page: 1,
showBtn: true,
};
this.getNextPers = this.getNextPers.bind(this);
}
getNextPers(){
const peopleApiEndpoint = `https://swapi.co/api/people/${this.state.page}`;
axios.get(peopleApiEndpoint).then((p) =>
if(p=={}){
this.setState({ showBtn: false });
}
else {
this.setState({ personagens: this.state.personagens.concat(p), page: this.state.page+1 })
}
);
}
render(){
return (
<div>
<p><b>Personagens:</b></p>
{this.state.personagens.map((pers, i) => (
<div key={i}>
<br />
<p><i>Name:</i> {pers.data.name}</p>
<p><i>Height:</i> {pers.data.height} cm</p>
<p><i>Mass:</i> {pers.data.mass} kg</p>
</div>
))}
<button onClick={this.getNextPers}>Ver Mais</button>
</div>
);
}
}
ReactDOM.render(<List />, document.getElementById('root'));
The real problem is here:
axios.get(peopleApiEndpoint).then((p) => {
if (p == {}) { // THIS WILL NEWER WORK AS EXPECTED
this.setState({showBtn: false});
} else {
this.setState({
personagens: this.state.personagens.concat(p),
page: this.state.page + 1
});
}
});
Also swapi return 404 when there is no more results instead of empty object so you need to add catch block to your axios.get as described in docs: https://github.com/axios/axios#handling-errors
axios.get(peopleApiEndpoint).then((p) => {
this.setState({
personagens: this.state.personagens.concat(p),
page: this.state.page + 1
});
}).catch((err) => {
this.setState({showBtn: false});
});
Now you can use conditional rendering like:
{(this.state.showBtn && <button onClick={this.getNextPers}>Ver Mais</button>)}
First thing getNextPers does not return anything and you can achieve the show/hide by using condintion in your code
{ this.your_condition ?
<button onClick={this.getNextPers}>Ver Mais</button> : ''
}
As addition to Ramya answer you can also use
render(){
return (
<div>
<p><b>Personagens:</b></p>
{this.state.personagens.map((pers, i) => (
<div key={i}>
<br />
<p><i>Name:</i> {pers.data.name}</p>
<p><i>Height:</i> {pers.data.height} cm</p>
<p><i>Mass:</i> {pers.data.mass} kg</p>
</div>
))}
{ this.state.showBtn && <button onClick={this.getNextPers}>Ver Mais</button> }
</div>
);
}
Since you're storing the showBtn state in your component, you can use it to conditionally render the button as follows:
render(){
return (
<div>
<p><b>Personagens:</b></p>
{this.state.personagens.map((pers, i) => (
<div key={i}>
<br />
<p><i>Name:</i> {pers.data.name}</p>
<p><i>Height:</i> {pers.data.height} cm</p>
<p><i>Mass:</i> {pers.data.mass} kg</p>
</div>
))}
{ (this.state.showBtn) ?
<button onClick={this.getNextPers}>Ver Mais</button>
:
null
}
</div>
);
}

React Js custom accordion, open one item at the time

I have an accordion in React formed of a row component which is looped inside a body parent component. In the row I'm toggling the state showDetails to show/hide the details for each row, effectively opening the accordion item. But, since the state is for each row, how do I close one accordion item when I open another one?
Body:
export default class Body extends React.Component {
render() {
const {modelProps, showInfo, linkedRow} = this.props;
return (
<div className="c-table__body">
{this.props.model.map(
(subModel, i) =>
linkedRow ?
<LinkedRow
key={`${i}`}
model={subModel}
modelProps={modelProps}
/>
:
<Row
key={`${i}_${subModel.username}`}
model={subModel}
modelProps={modelProps}
showInfo={showInfo}
handleStatusChanged={this.props.handleStatusChanged}
/>
)}
</div>
);
}
}
Row:
class Row extends React.Component {
constructor(props) {
super(props);
this.state = {
userId: '',
showDetails: false,
showModal: false,
status: '',
value: '',
showInfo: false
};
render() {
const { model, modelProps, showInfo } = this.props;
return (
<div className="c-table__row">
<div className="c-table__row-wrapper">
{modelProps.map((p, i) => (
<div className={`c-table__item ${this.isStatusCell(model[p]) ? model[p] : p}`} key={i}>{this.isStatusCell(model[p]) ? this.toTitleCase(model[p]) : model[p]}</div>
))}
{showInfo ? (
<div className="c-table__item c-table__item-sm">
<a
name="view-user"
onClick={this.showDetailsPanel}
className={this.state.showDetails ? 'info showing' : 'info'}
>
<Icon yicon="Expand_Cross_30_by_30" />
</a>
</div>
) : (
''
)}
</div>
{this.state.showDetails ? (<ConnectedDetails user={model} statusToggle={this.handleStatusChange}/>) : null}
</div>
);
}
}
export default Row;
Not really sure how to approach this, maybe something in the body that check is there's any row open according to the showDetails state in the rows?
Thanks in advance
The approach is to lift the state of which <Row /> is open to the <Body /> component.
Also the method that switch between opened <Row /> is on the <Body /> component.
toggleOpen = (idx) => {
this.setState({ openRowIndex: idx });
}
then when you rendered your <Row />s you can pass a prop isOpen:
<Row
key={`${i}_${subModel.username}`}
model={subModel}
modelProps={modelProps}
showInfo={showInfo}
handleStatusChanged={this.props.handleStatusChanged}
isOpen={this.state.openRowIndex === i}
onToggle={_ => this.toggleOpen(i)}
/>

React - How to show relative div when mouse hover on a html tag?

Below is my code...
<ul className="no-style board__list">
{Object.keys(today.books).map(function(id) {
var refBook = today.books[id][0];
return (
<li key={refBook._id} className="board__list-item">
<div className="container flexrow">
<div className="flexrow__fit-2">{refBook.book_no}</div>
<div className="flexrow__org">
<span className="board__icon-wrap">
{refBook.memo
? (<i className="fa fa-flag" style={{color:"#F9AB9F"}}></i>)
: null
}
</span>
{refBooking.memo
? (<div className="memo_dialog">{refBook.memo}</div>)
: null
}
</div>
</div>
</li>
);
})}
</ul>
I have a object books array and I create a fa-flag icon for each book.
What I want is to show different memo dialog when mouse hover on each flag icon.
I know how to do it with query but how can I do this in react way not using jquery?
I'm not sure what are you trying to achieve but this example might be useful for you
class Book extends React.Component {
constructor(props){
super(props);
this.handleOver = this.handleOver.bind(this);
}
handleOver(name){
this.props.over(this.props.name)
}
render(){
return <div onMouseOver={this.handleOver}>{this.props.name}</div>
}
}
class BookList extends React.Component {
constructor(props){
super(props);
this.mouseOver = this.mouseOver.bind(this);
this.state = {
books: ['hello', 'amazing', 'world'],
memo: ''
}
}
mouseOver(name){
this.setState({memo: name})
}
render(){
const bookList = this.state.books.map((book, index)=>{
return <Book key={index} name={book} over={this.mouseOver}/>
});
return <div>
{bookList}
<hr/>
<div>{this.state.memo}</div>
</div>
}
}
React.render(<BookList />, document.getElementById('container'));
Also fiddle example.
I hope it will help you. Thanks
I suggest you to use isHovered state variable, to store hover state.
We are displaying some component(in your case it would be dialog box), if isHovered is true and hide it when this variable is false.
When we will hover on link element, we will trigger handleEnter function to set isHovered variable to true.
Similarly, when we are moving cursor out of link element, we are triggering handleLeave function to set isHovered variable to false.
Example:
class Test extends React.Component {
constructor(props) {
super(props);
this.state = {
isHovered: false,
};
}
handleEnter() {
this.setState({
isHovered: true
});
}
handleLeave() {
this.setState({
isHovered: false
});
}
render() {
return (
<div>
<a
onMouseEnter={this.handleEnter.bind(this)}
onMouseLeave={this.handleLeave.bind(this)}
>Link</a>
{this.state.isHovered ? (
<div className="box">A component</div>
) : (
<div />
)}
</div>
);
}
}
Also, you can see demo at CodePen.

Categories

Resources