I am building a react application in which user enters a search word and backend gives array of json. On the result page I am trying to implement faceted search, so I have few filters. I am filtering the fetched result based on the user chosen checkboxes. Here is the UI.
This is my js file for the search results page.
import React from 'react';
import NavigationBar from './NavigationBar';
import SearchPageResultsStyle from "../assets/css/SearchResultsPage.css"
import Pagination from './Pagination';
class SearchResultsPage extends React.Component{
constructor(props) {
super(props);
this.state = {
results: this.props.location.state.data.results,
keyword: this.props.location.state.data.keyword,
pageOfItems: [],
cities: {
'New York City (NYC)': false,
'Delhi': false,
'Bangkok': false,
'Paris': false,
'Mexico City': false
},
topics: {
'Environment': false,
'Crime': false,
'Politics': false,
'Social Unrest': false,
'Infrastructure': false
},
languages: {
'Hindi': false,
'English': false,
'Thai': false,
'French': false,
'Spanish': false
}
};
this.onChangePage = this.onChangePage.bind(this);
this.onCityChange = this.onCityChange.bind(this);
}
componentDidUpdate(prevProps, prevState) {
if (prevState !== this.state) {
console.log(this.state.cities);
const filteredCities = [];
for (let key in this.state.cities) {
if (this.state.cities[key] === true) {
filteredCities.push(key)
}
}
console.log(filteredCities);
const filteredResults = [];
this.state.results.forEach((result) => {
for (let i = 0; i < filteredCities.length; i++) {
if (result.city === filteredCities[i]) {
filteredResults.push(result)
}
}
})
console.log("fileterdPageOfItems", filteredResults)
this.updatePageOfItems(filteredResults)
}
}
// Function to filter the search results based on user chosen filters
updatePageOfItems(filteredResults) {
this.setState({
results: filteredResults
})
}
onChangePage(pageOfItems) {
// update local state with new page of items
this.setState({pageOfItems});
}
// setting each city in cities object (city chechboxes which are clicked on UI) to true
onCityChange(e) {
const val = e.target.checked;
const name = e.target.name;
let updatedCities = Object.assign({},this.state.cities,{[name]: val});
this.setState({
cities: updatedCities,
})
}
// rendering checkboxes for cities
renderCity() {
const cities = ['New York City (NYC)','Delhi','Bangkok','Paris','Mexico City']
return cities.map((city,i) => {
return (
<div>
<label key={i}>
{city}
<input
type="checkbox"
name={city}
onChange={this.onCityChange}
value={this.state.cities[city]}/>
</label>
</div>
)
})
}
render() {
const renderItems = this.state.pageOfItems.map((item, index) => {
return (
<div>
<h3 style={{color: '#1a0dab'}} key={index}>{item.text}</h3>
<a href={'https://google.com'} key={index}>{item.tweetUrl}</a>
<br/>
<p><span style={{fontWeight:'bold', textColor:'#6a6a6a'}} key={index}>topic: </span>{item.topic}</p>
<p><span style={{fontWeight:'bold', textColor:'#6a6a6a'}} key={index}>city: </span>{item.city}</p>
<p><span style={{fontWeight:'bold', textColor:'#6a6a6a'}} key={index}>lang: </span>{item.lang}</p>
<p><span style={{fontWeight:'bold', textColor:'#6a6a6a'}} key={index}>Hashtags: </span></p>
<hr/>
</div>
)
});
return (
<div>
<NavigationBar/>
<h4 style={{textAlign:'center', color:'#1a0dab'}}>Showing search results for <span style={{fontWeight:'bold', fontStyle:'Italic'}}>'{this.state.keyword}'</span></h4>
<hr/>
<div className={'wrap'} style={SearchPageResultsStyle}>
<div className={'fleft'}>
<h4>City</h4>
{this.renderCity()}
<hr/>
<h4>Topics</h4>
<hr/>
<h4>Language</h4>
<hr/>
</div>
<div className={'fcenter'}>
{renderItems}
<Pagination items={this.state.results} onChangePage={this.onChangePage}/>
</div>
<div className={'fright'}></div>
</div>
</div>
)
}
}
export default SearchResultsPage;
I am updating the cities in my state to true whenever a user clicks on a particular checkbox, and then I am filtering the fetched result (from backend) based on the cities in my array filteredCities and I am collecting the filtered results in an array filteredResults, and then I am passing this array to a function updatePageOfItems to change the state so that my filtered result could get re-rendered. But When I am calling the function updatePageOfItems, the application is getting into infinite loop.
What is the work around for this problem. I am new to react and facing this issue for the first time.
Here is the stack trace
I was able to solve the issue, instead of filtering the results in the function componentDidUpdate I did the operation in the callback function of setState inside onCityChange function.
onCityChange(e) {
const val = e.target.checked;
const name = e.target.name;
let updatedCities = Object.assign({},this.state.cities,{[name]: val});
this.setState({
cities: updatedCities,
},function () {
const filteredCities = [];
for (let key in this.state.cities) {
if (this.state.cities[key] === true) {
filteredCities.push(key)
}
}
console.log("filteredCities", filteredCities);
const filteredResults = [];
this.state.results.forEach((result) => {
for (let i = 0; i < filteredCities.length; i++) {
if (result.city === filteredCities[i]) {
filteredResults.push(result)
}
}
})
this.setState({
results: filteredResults
},function () {
console.log(this.state.results)
})
})
}
Related
I am using MERN stack and Redux. I have created an array in the state 'comments' which is updated via the clickHandler function with elements from the global state (accessed via props). When i try to show the contents of the array in the render i just get the length of it. How would i show the properties of the elements for example title.
import React, { Component } from "react";
import PropTypes from "prop-types";
import GoogleSearch from "./GoogleSearch";
import { connect } from "react-redux";
import { fetchSubjects } from "../../actions/subject";
import { fetchComments } from "../../actions/comment";
import store from "../../store";
class Subject extends Component {
// on loading the subjects and comments
// are fetched from the database
componentDidMount() {
this.props.fetchSubjects();
this.props.fetchComments();
}
constructor(props) {
super(props);
this.state = {
// set inital state for subjects description
// and summary to invisible
viewDesription: -1,
viewSummary: -1,
comments: [],
};
}
componentWillReceiveProps(nextProps) {
// new subject and comments are added to the top
if (nextProps.newPost) {
this.props.subjects.unshift(nextProps.newPost);
}
if (nextProps.newPost) {
this.props.comments.unshift(nextProps.newPost);
}
}
clickHandler = (id) => {
// when a subject title is clicked pass in its id
// and make the desciption visible
const { viewDescription } = this.state;
this.setState({ viewDescription: viewDescription === id ? -1 : id });
// clear the existing comments in state
this.setState({
comments: [],
});
// loop through the comment items in the global state
// and add any with the same subjects id passed in to the array
var i;
for (i = 0; i < this.props.comments.length; i++) {
if (this.props.comments[i].subject == id) {
console.log(this.props.comments[i]);
this.setState({
comments: this.state.comments.unshift(this.props.comments[i]),
});
}
} // set local storage to the id for the subject that has been clicked
localStorage.setItem("passedSubject", id);
};
// hovering on and off subjects toggles the visibility of the summary
hoverHandler = (id) => {
this.setState({ viewSummary: id });
};
hoverOffHandler = () => {
this.setState({ viewSummary: -1 });
};
render() {
const subjectItems = this.props.subjects.map((subject) => {
// if the state equals the id set to visible if not set to invisible
var view = this.state.viewDescription === subject._id ? "" : "none";
var hover = this.state.viewSummary === subject._id ? "" : "none";
var comments = this.state.comments;
return (
<div key={subject._id}>
<div
className="subjectTitle"
onClick={() => this.clickHandler(subject._id)}
onMouseEnter={() => this.hoverHandler(subject._id)}
onMouseLeave={() => this.hoverOffHandler()}
>
<p className="title">{subject.title}</p>
<p className="rating">Rating: {subject.rating}</p>
<p className="summary" style={{ display: hover }}>
{subject.summary}
</p>
</div>
<div className="subjectBody " style={{ display: view }}>
<div className="subjectAuthor">
<p className="author">
Subject created by: {subject.author} on {subject.date}
</p>
<a href="">
<div className="buttonRateSubject">RATE SUBJECT</div>
</a>
</div>
<div className="subjectDescription">
<p className="description">{subject.description}</p>
</div>
<div className="subjectLinks">Links:</div>
<div className="subjectComments">
<p>Comments:</p>
{/* ************HERE*********** */}
<p>{comments}</p>
{/* ********************************* */}
<a href="/addcomment">
<div className="buttonAddComment">ADD COMMENT</div>
</a>
</div>
</div>
</div>
);
});
return (
<div id="Subject">
<GoogleSearch />
{subjectItems}
</div>
);
}
}
Subject.propTypes = {
fetchSubjects: PropTypes.func.isRequired,
fetchComments: PropTypes.func.isRequired,
subjects: PropTypes.array.isRequired,
comments: PropTypes.array.isRequired,
newPost: PropTypes.object,
};
const mapStateToProps = (state) => ({
subjects: state.subjects.items,
newSubject: state.subjects.item,
comments: state.comments.items,
newComment: state.comments.item,
});
// export default Subject;
export default connect(mapStateToProps, { fetchSubjects, fetchComments })(
Subject,
Comment
);
I think I know your problem. You want to render items of an array.
Let me just give you a short overview.
Javascript:
this.setState({
comments: data
});
render (){
return (
<div>
{ this.state.comments.map(c=> <div>{c.body}</div> ) }
</div>
)
}
Thanks guys, i changed the for loop in the clickHandler to this which now has data rendering, it didn't like objects in the array for some reason.
var temp = [];
for (i = 0; i < this.props.comments.length; i++) {
if (this.props.comments[i].subject == id) {
console.log(this.props.comments[i]);
temp.unshift(this.props.comments[i].comment);
temp.unshift(this.props.comments[i].title);
}
}
this.setState({
comments: temp,
});
I successfully created multiple filtered buttons. However, I noticed that when I first clicked on one filtered button to display, for example, students living in England, the list displayed filtered results and then I click on another filtered button to display students living in USA, the list just went blank and my console showed that the array was empty. I don't know what happened.
import React, { Component } from 'react';
import profiles from '../data/berlin.json';
export class FaceBook extends Component {
constructor(props){
super(props);
this.state = {
profilelist: profiles,
filtered: profiles
}
}
showProfile = () =>{
return this.state.profilelist.map((eachProfile,i)=>{
let studentBoolean;
if(eachProfile.isStudent) {
studentBoolean = "Student";
} else {studentBoolean = "Teacher"}
return(
<div className="profilecard" key={i}>
<div className="profileimage"><img src={eachProfile.img} alt="Actor"/></div>
<div className="profilecontent">
<ul>
<li><strong>First Name:</strong> {eachProfile.firstName}</li>
<li><strong>Last Name:</strong> {eachProfile.lastName}</li>
<li><strong>Country:</strong> {eachProfile.country}</li>
<li><strong>Type:</strong> {studentBoolean}</li>
</ul>
</div>
</div>
)
})
}
showAll = () =>{
this.setState({
profilelist: profiles
})
}
showEngland = () =>{
this.setState({
profilelist: profiles,
filtered: profiles
})
let filterEngland = [...this.state.profilelist];
let newList = filterEngland.filter(item => {
const lc = item.country.toLowerCase();
const filter = "england";
return (lc === filter);
})
console.log(newList);
this.setState({
profilelist: newList,
filtered: newList
})
}
showUSA = () =>{
this.setState({
profilelist: profiles,
filtered: profiles
})
let filterUSA = [...this.state.profilelist];
let newusaList = filterUSA.filter(item => {
const lc = item.country.toLowerCase();
const filter = "usa";
return (lc === filter);
})
this.setState({
profilelist: newusaList,
filtered: newusaList
})
}
render() {
console.log(this.state.profilelist);
return (
<div>
<div className="menubar">
<button onClick={this.showAll}>All</button>
<button onClick={this.showEngland}>England</button>
<button onClick={this.showUSA}>USA</button>
</div>
<div className="profileTable">
{this.showProfile()}
</div>
</div>
)
}
}
export default FaceBook
As you can see, I created 3 buttons "All", "England", "USA". I also created 3 functions for each button. The all button reset the state.profilelist while England and USA display the filtered results. I tried to add
this.setState({
profilelist: profiles,
filtered: profiles
})
at the beginning of the functions for England and USA so that it'll reset the list before it get filtered, but it's not working....
You don't need a function for each filter, just create a function that handles all the filtering. Do not modify profilelist all your filtering should modify filtered array.
// filter profiles by country
filterByCountry = country => {
if (!country || typeof country !== "string") {
return;
}
this.setState(prevState => {
return {
filtered:
country.toLowerCase() === "all"
? this.state.profilelist
: prevState.profilelist.filter(
item =>
item &&
item.country &&
item.country.toLowerCase() === country.toLowerCase()
)
};
});
};
show profiles function
showProfile = () => {
return this.state.filtered.map((eachProfile, i) => (
<div className="profilecard" key={i}>
<div className="profileimage">
<img src={eachProfile.img} alt="Actor" />
</div>
<div className="profilecontent">
<ul>
<li>
<strong>First Name:</strong> {eachProfile.firstName}
</li>
<li>
<strong>Last Name:</strong> {eachProfile.lastName}
</li>
<li>
<strong>Country:</strong> {eachProfile.country}
</li>
<li>
<strong>Type:</strong>{" "}
{eachProfile.isStudent ? "Student" : "Teacher"}
</li>
</ul>
</div>
</div>
));
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.0/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.21.1/babel.min.js"></script>
<div id="root"></div>
<script>
const profiles = [
{
firstName: "James",
lastName: "Peter",
country: "England",
isStudent: true,
img: "https://img.icons8.com/officel/16/000000/edit-user-female.png"
},
{
firstName: "Jane",
lastName: "Jones",
country: "usa",
isStudent: false,
img: "https://img.icons8.com/officel/16/000000/edit-user-female.png"
},
{
firstName: "Michael",
lastName: "Ballack",
country: "Germany",
isStudent: false,
img: "https://img.icons8.com/officel/16/000000/edit-user-female.png"
},
{
firstName: "Mary",
lastName: "Jane",
country: "England",
isStudent: false,
img: "https://img.icons8.com/officel/16/000000/edit-user-female.png"
},
{
firstName: "Charlie",
lastName: "Barack",
country: "usa",
isStudent: true,
img: "https://img.icons8.com/officel/16/000000/edit-user-female.png"
},
{
firstName: "Will",
lastName: "Ozil",
country: "Germany",
isStudent: true,
img: "https://img.icons8.com/officel/16/000000/edit-user-female.png"
}]
</script>
<script type="text/babel">
class App extends React.Component {
constructor() {
super();
this.state = {
profilelist: profiles,
filtered: profiles
};
}
filterByCountry = country => {
if (!country || typeof country !== "string") {
return;
}
this.setState(prevState => {
return {
filtered:
country.toLowerCase() === "all"
? this.state.profilelist
: prevState.profilelist.filter(
item =>
item &&
item.country &&
item.country.toLowerCase() === country.toLowerCase()
)
};
});
};
showProfile = () => {
return this.state.filtered.map((eachProfile, i) => (
<div className="profilecard" key={i}>
<div className="profileimage">
<img src={eachProfile.img} alt="Actor" />
</div>
<div className="profilecontent">
<ul>
<li>
<strong>First Name:</strong> {eachProfile.firstName}
</li>
<li>
<strong>Last Name:</strong> {eachProfile.lastName}
</li>
<li>
<strong>Country:</strong> {eachProfile.country}
</li>
<li>
<strong>Type:</strong>{" "}
{eachProfile.isStudent ? "Student" : "Teacher"}
</li>
</ul>
</div>
</div>
));
};
render() {
return (
<div>
<div className="menubar">
<button onClick={() => this.filterByCountry("All")}>All</button>
<button onClick={() => this.filterByCountry("England")}>
England
</button>
<button onClick={() => this.filterByCountry("usa")}>USA</button>
</div>
<div className="profileTable">{this.showProfile()}</div>
</div>
);
}
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
</script>
The problem boils down to the fact that setState is asynchronous,
When you do
this.setState({
profilelist: profiles,
filtered: profiles
})
let filterEngland = [...this.state.profilelist];
You expect profilelist in the state to be reset before
let filterEngland = [...this.state.profilelist];
line is called. But setState is asynchronous. Your filterEngland will be assigned with previously filtered elements only, and when you run filter on it, list becomes empty.
There are many ways to solve this. setState has a callback function which will be only executed after state is properly updated.
this.setState({}, cb)
In that way you can rewrite functions like this.
showUSA = () => {
this.setState({
profilelist: profiles,
filtered: profiles
},() => {
let filterUSA = [...this.state.profilelist];
let newusaList = filterUSA.filter(item => {
const lc = item.country.toLowerCase();
const filter = "usa";
return (lc === filter);
})
this.setState({
profilelist: newusaList,
filtered: newusaList
})
})
}
But I will ask you to reconsider the way overall code is written. You are iterating
and printing profilelist, instead you should be displaying filtered
Each button click should just update filtered and profileList will remain as your master list.
I'm trying to make a react component that can filter a list based on value chosen from a drop-down box. Since the setState removes all data from the array I can only filter once. How can I filter data and still keep the original state? I want to be able to do more then one search.
Array list:
state = {
tree: [
{
id: '1',
fileType: 'Document',
files: [
{
name: 'test1',
size: '64kb'
},
{
name: 'test2',
size: '94kb'
}
]
}, ..... and so on
I have 2 ways that I'm able to filter the component once with:
filterDoc = (selectedType) => {
//way #1
this.setState({ tree: this.state.tree.filter(item => item.fileType === selectedType) })
//way#2
const myItems = this.state.tree;
const newArray = myItems.filter(item => item.fileType === selectedType)
this.setState({
tree: newArray
})
}
Search component:
class SearchBar extends Component {
change = (e) => {
this.props.filterTree(e.target.value);
}
render() {
return (
<div className="col-sm-12" style={style}>
<input
className="col-sm-8"
type="text"
placeholder="Search..."
style={inputs}
/>
<select
className="col-sm-4"
style={inputs}
onChange={this.change}
>
<option value="All">All</option>
{this.props.docTypes.map((type) =>
<option
value={type.fileType}
key={type.fileType}>{type.fileType}
</option>)}
</select>
</div>
)
}
}
And some images just to get a visual on the problem.
Before filter:
After filter, everything that didn't match was removed from the state:
Do not replace original data
Instead, change what filter is used and do the filtering in the render() function.
In the example below, the original data (called data) is never changed. Only the filter used is changed.
const data = [
{
id: 1,
text: 'one',
},
{
id: 2,
text: 'two',
},
{
id: 3,
text: 'three',
},
]
class Example extends React.Component {
constructor() {
super()
this.state = {
filter: null,
}
}
render() {
const filter = this.state.filter
const dataToShow = filter
? data.filter(d => d.id === filter)
: data
return (
<div>
{dataToShow.map(d => <span key={d.id}> {d.text}, </span>)}
<button
onClick={() =>
this.setState({
filter: 2,
})
}
>
{' '}
Filter{' '}
</button>
</div>
)
}
}
ReactDOM.render(<Example />, document.getElementById('root'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<body>
<div id='root' />
</body>
Don't mutate local state to reflect the current state of the filter. That state should reflect the complete available list, which should only change when the list of options changes. Use your filtered array strictly for the view. Something like this should be all you need to change what's presented to the user.
change = (e) => {
return this.state.tree.filter(item => item.fileType === e.target.value)
}
I have a search and select filters on my page. The issue that I am having is that I can't seem to make the search work with multiple json values.
Example value is { "id": "1", "role": "teacher", "subject": "mathematics", "name": "Jonathan Kovinski" } and I want to be able to use key and values.
I've tried using some other question about combining json key and value into a single array and passing it to the search filter but it didn't work.
text = data.filter(info => {
return Object.keys(info).map(function(key) {
var singleOne = JSON.stringify(info[key]);
console.log(info, "This is the json one")
}).toLowerCase().match(searchString);
});
Here is a link to a JS Fiddle that I've created with all of my code.
I am trying to set my search bar to use all keys and values for searching and sorting data.
i would suggest you put the filtered data in a seperate key in the state in case you want to revert to the original result,
use the Obeject.values instead of Object.keys and filter the data in the handleChange function,
here's a working code :
class Hello extends React.Component {
constructor(props) {
super(props);
this.state = {
isLoading: false,
data: [],
searchString: "",
filtered: []
};
this.handleChange = this.handleChange.bind(this);
}
componentDidMount() {
this.fetchData();
}
handleChange(e) {
var value = e.target.value;
this.setState({
searchString: value,
filtered: this.state.data.filter(e =>
Object.values(e)
.join(" ")
.toLowerCase()
.match(value)
)
});
}
fetchData() {
fetch("https://api.myjson.com/bins/lo3ls")
.then(response => response.json())
.then(json => {
this.setState({
isLoaded: true,
data: json,
filtered: json
});
})
.catch(error => console.log("parsing failed", error));
}
render() {
var { isLoaded, data } = this.state;
const searchString = this.state.searchString.trim().toLowerCase();
let text = this.state.data;
console.log(text);
if (searchString.length > 0) {
text = text.filter(info => {
return info.role.toLowerCase().match(searchString);
});
}
return (
<div>
<input
type="text"
id="searchbar"
value={this.state.searchString}
onChange={this.handleChange}
placeholder="Search"
name="device"
/>
<select className="category-select" name="categories" onChange={this.handleChange}>
{data.map(info => (
<option value={info.role}>{info.role}</option>
))}
</select>
{/* map through the filtered ones*/}
{this.state.filtered.map(info => (
<div className="display">
<span className="role">Role: {info.role}</span>
<span> Name: {info.name}</span>
<span>, Subject: {info.subject}</span>
</div>
))}
</div>
);
}
}
ReactDOM.render(<Hello name="World" />, document.getElementById("container"));
Actually, I read all of your code in Fiddle, But I proffer Fuse to you. Use it inside your code in componentDidMount and implement your search. it is very easy and handy.
const options = {
shouldSort: true,
threshold: 0.6,
location: 0,
distance: 100,
maxPatternLength: 32,
minMatchCharLength: 1,
keys: [
"title",
"author.firstName"
]
};
const fuse = new Fuse(list, options); // "list" is the item array
const result = fuse.search(""); // put your string inside double quotation
The result is your answer.
import React, { PropTypes } from 'react';
import { Link, browserHistory } from 'react-router';
import * as DataConnectionAction from '../../actions/dataconnectionAction.jsx';
import DataConnectionStore from '../../store/dataconnectionstore.jsx';
class DataSource extends React.Component {
constructor(props) {
super(props);
this.state = {
datasourcelist: [],
};
this._dataconnectionStoreChange = this._dataconnectionStoreChange.bind(this);
}
componentWillMount() {
DataConnectionStore.on('change', this._dataconnectionStoreChange);
}
componentWillUnmount() {
DataConnectionStore.removeListener('change', this._dataconnectionStoreChange);
}
componentDidMount() {
DataConnectionAction._getDataSourcesList();
}
_dataconnectionStoreChange(type) {
if (type == 'DataSourcesList') {
let datasourcelist = DataConnectionStore._getDataSourceList() || {};
this.setState({ datasourcelist: datasourcelist.dataconnections });
}
}
DataSourceView(el) {
let data = {
id: el.dataConnectionName
}
}
_handleSearchChange(e) {
let value = e.target.value;
let lowercasedValue = value.toLowerCase();
let datasourcedata = this.state.datasourcelist;
let datasourcelist = datasourcedata && datasourcedata.filter(el => el.dataConnectionName.toLowerCase().includes(lowercasedValue));
this.setState({ datasourcelist });
}
DataSourcesCardUI() {
let datasourcedata = this.state.datasourcelist;
return (
datasourcedata && datasourcedata.map((el) =>
<div key={el.key}>
<div className="col-md-3 topadjust">
<div className="panel panel-default datasource_panel ">
<div className="panel-heading">
<h5 className="panel_title"><i className="fa fa-database"></i> {el.dataConnectionName}</h5>
</div>
<Link className="panel-body" onClick={this.DataSourceView.bind(this, el)}>
<div className="datasource_txt text-center">
<h6>{el.databaseHost}</h6>
<h6>{el.dataConnectionType} </h6>
<p>{el.createdDate}</p>
</div>
</Link>
</div>
</div>
</div>
)
);
}
render() {
return (
<div>
<section className="content_block">
<div className="container-fluid">
<div className="row dashboard_list">
{this.DataSourcesCardUI()}
</div>
</div>
</section>
</div>
);
}
}
export default DataSource;
Here I am getting one issue, that is I can able to filter based on the dataConnectionName, but when I am trying to filter with change of name it is filtering from the first filter array data.
But, I need to filter based on data array if i remove and type again.
Example:
when I tried search with Cu I am getting properly. but again when i remove Cu and search for User It is not searching from data array It is searching from filter array data. Instead of that when i remove and search with other key it should get filtered from data array.
Please Guide me what i am doing wrong.
Instead of overwriting the data in your state, you could keep a separate array in which you put all the elements that match the search.
Example
let data = [
{
dataConnectionName: "Customer_Details",
dataConnectionType: "NO_SQL",
databaseHost: "17.8.10.26",
pluginName: "AGT1_Customer_Details",
createdDate: "2018-09-23",
createBy: "Admin"
},
{
dataConnectionName: "User_Details",
dataConnectionType: "NO_SQL",
databaseHost: "17.8.10.26",
pluginName: "AGT1_Customer_Details",
createdDate: "2018-09-24",
createBy: "Admin"
},
{
dataConnectionName: "Manager_Details",
dataConnectionType: "NO_SQL",
databaseHost: "17.8.10.26",
pluginName: "AGT1_Customer_Details",
createdDate: "2018-09-25",
createBy: "Admin"
},
{
dataConnectionName: "Director_Details",
dataConnectionType: "NO_SQL",
databaseHost: "17.8.10.26",
pluginName: "AGT1_Customer_Details",
createdDate: "2018-09-26",
createBy: "Admin"
}
];
// Give each element a unique id that is used as key
data.forEach(el => el.id = Math.random());
class App extends React.Component {
state = {
data,
filteredData: data
};
_handleSearchChange = e => {
const { value } = e.target;
const lowercasedValue = value.toLowerCase();
this.setState(prevState => {
const filteredData = prevState.data.filter(el =>
el.dataConnectionName.toLowerCase().includes(lowercasedValue)
);
return { filteredData };
});
};
render() {
const { filteredData } = this.state;
return (
<div>
<input onChange={this._handleSearchChange} placeholder="Search"/>
{filteredData.map(el => (
<div key={el.key}>
<div>
{el.dataConnectionName} - {el.pluginName} - {el.createdDate} - {el.createBy}
</div>
</div>
))}
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>