I have a simple React JS application to which I'd like to add a search function. I've created the search function code and added the Search component (from Semantic-UI), which passes the searched value to the function.
How do I get it to call to the function from the search component below to trigger a form submit?
Here's the search component.
<Search
onSearchChange={(e) => this.handleSearchChangeNew(e.target.value)}
/>
Here's the search function:
async handleSearchChangeNew (value) {
console.log("value in new search: " + value)
this.props.updateSearchString(value);
fetch(`api/license/search/${JSON.stringify(this.props.searchString)}`, {
credentials: 'include'})
.then(response => response.json())
.then(data => this.setState({
licenses: data,
isLoading: false,
licensePage: data.slice(this.state.begin, this.state.end)
}))
.catch(() => this.props.history.push('/'));
}
The above function prints the value passed from the search box.
I had previously put together a somewhat inelegant search function where the input was keyed into a text box, and the above search function invoked by pressing a "Search" submit function. That search function would repopulate the page based on what was in the input box. It's still in there, but I've also added the new search function code shown above.
For reference, here is the entire class.
import React, { Component } from 'react';
import { Button, ButtonGroup, Container, Table } from 'reactstrap';
import { Pagination, Search } from 'semantic-ui-react'
import AppNavbar from './AppNavbar';
import { Link, withRouter } from 'react-router-dom';
import { instanceOf } from 'prop-types';
import { withCookies, Cookies } from 'react-cookie';
class LicenseList extends Component {
static propTypes = {
cookies: instanceOf(Cookies).isRequired
};
constructor(props) {
super(props);
const {cookies} = props;
this.state = {
word: '',
newWord: '',
licenses: [],
licensePage: [],
csrfToken: cookies.get('XSRF-TOKEN'),
isLoading: true,
licensesPerPage: 7,
activePage: 1,
begin: 0,
end: 7
};
this.remove = this.remove.bind(this);
this.btnClick = this.btnClick.bind(this);
this.handleSearchChangeNew = this.handleSearchChangeNew.bind(this);
}
componentDidMount() {
this.setState({isLoading: true});
console.log("searchString: " + this.props.searchString);
fetch(`/api/license/search/${this.props.searchString}`, {credentials: 'include'})
.then(response => response.json())
.then(data => this.setState({
licenses: data,
isLoading: false,
licensePage: data.slice(this.state.begin, this.state.end)
}))
.catch(() => this.props.history.push('/'));
}
async handleSearchChange(value) {
this.props.updateSearchString(value)
}
async searchFromString () {
this.setState({isLoading: true});
fetch(`api/license/search/${this.props.searchString}`, {
credentials: 'include'})
.then(response => response.json())
.then(data => this.setState({
licenses: data,
isLoading: false,
licensePage: data.slice(this.state.begin, this.state.end)
}))
.catch(() => this.props.history.push('/'));
}
async clearSearchString(value) {
this.props.updateSearchString('');
}
async btnClick(
event: React.MouseEvent<HTMLAnchorElement>,
data: PaginationProps
) {
await this.setState({activePage: data.activePage});
await this.setState({begin: this.state.activePage * this.state.licensesPerPage - this.state.licensesPerPage});
await this.setState({end: this.state.activePage *this.state.licensesPerPage});
this.setState({
licensePage: this.state.licenses.slice(this.state.begin, this.state.end),
});
}
async remove(id) {
if (window.confirm('Are you sure you wish to delete this license?')) {
await fetch(`/api/license/${id}`, {
method: 'DELETE',
headers: {
'X-XSRF-TOKEN': this.state.csrfToken,
'Accept': 'application/json',
'Content-Type': 'application/json'
},
credentials: 'include'
}).then(() => {
let updatedLicenses = [...this.state.licenses].filter(i => i.id !== id);
this.setState({licenses: updatedLicenses});
});
}
}
download(url) {
// fake server request, getting the file url as response
setTimeout(() => {
const response = {
file: url,
};
// server sent the url to the file!
// now, let's download:
window.open(response.file);
// you could also do:
// window.location.href = response.file;
}, 100);
}
async handleSearchChangeNewx(value) {
this.props.updateSearchString(value);
}
async handleSearchChangeNew (value) {
console.log("value in new search: " + value)
this.props.updateSearchString(value);
fetch(`api/license/search/${JSON.stringify(this.props.searchString)}`, {
credentials: 'include'})
.then(response => response.json())
.then(data => this.setState({
licenses: data,
isLoading: false,
licensePage: data.slice(this.state.begin, this.state.end)
}))
.catch(() => this.props.history.push('/'));
}
render() {
const {licensePage, activePage } = this.state;
const {licenses, isLoading, licensesPerPage} = this.state;
const totalPages = Math.ceil(licenses.length / licensesPerPage);
if (isLoading) {
return <p>Loading...</p>;
}
const licenseList = licensePage.map(license => {
return<tr key={license.id}>
<td style={{whiteSpace: 'nowrap'}}>{license.fullName}</td>
<td style={{whiteSpace: 'nowrap'}}>{license.requester}</td>
<td style={{whiteSpace: 'nowrap'}}>{license.tag}</td>
<td style={{whiteSpace: 'nowrap'}}>{license.dateCreated.substring(0, 10)}</td>
<td style={{whiteSpace: 'nowrap'}}>{license.expiration}</td>
<td style={{whiteSpace: 'nowrap'}}>{license.systems}</td>
<td>
<ButtonGroup>
<Button size="sm" color="primary" tag={Link} to={"/licenses/" + license.id}>Edit</Button>
<Button size="sm" color="dark" onClick={() => this.download(license.url)}>Download</Button>
<Button size="sm" color="danger" onClick={() => this.remove(license.id)}>Delete</Button>
</ButtonGroup>
</td>
</tr>
});
return (
<div>
<AppNavbar/>
<Container fluid>
<h3>License List</h3>
<div className="float-left">
<div>
<input type="text" value={this.props.searchString} onChange={(e) => this.props.updateSearchString(e.target.value)} />
<input type="submit" value="Search" onClick={() => this.searchFromString()} />
<input type="submit" value="Clear Search" onClick={() => this.clearSearchString()} />
<Search
onSearchChange={(e) => this.handleSearchChangeNew(e.target.value)}
/>
</div>
</div>
<div className="float-right">
<Button color="primary" tag={Link} to="/licenses/new">Create License</Button>
</div>
<Table className="mt-4">
<thead>
<tr>
<th width="10%">Full Name</th>
<th width="5%">Requester</th>
<th width="10%">Tag</th>
<th width="5%">Created</th>
<th width="5%">Expiration</th>
<th width="5%">Systems</th>
<th width="10%">Actions</th>
</tr>
</thead>
<tbody>
{licenseList}
</tbody>
</Table>
<div>
</div>
<div className="col text-center">
<Pagination
activePage={activePage}
onPageChange={this.btnClick}
totalPages={totalPages}
ellipsisItem={null}
/>
</div>
</Container>
</div>
);
}
}
export default withCookies(withRouter(LicenseList));