0

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));
Jack BeNimble
  • 35,733
  • 41
  • 130
  • 213
  • This code snippet doesn't help us helping you. Try adding your whole component's function and where it is using the Semantic's UI component as well. It seems to be very simple to do what you are asking for, but without your code I can't be sure about what you really need. – gustavoilhamorais Feb 02 '21 at 01:33
  • Can you please add more code. I can't understand –  Feb 02 '21 at 01:35

1 Answers1

0

Use native <form> element and you are good to go! the browsers will do the hard liftings. wrap your inputs in a <form> instead of a <div> and pass your actual form submit handler to onSubmit listener on <form onSubmit={this.handleSearchChangeNew}>. then you need a event.preventDefault() to prevent page refresh; give your inputs a name is also a good practice though. <form> element will do a basic validation, and also handle enter key;

meanwhile if you don't feel comfortable using <form>, you can also handle key change event yourself ( as you did handled most of native <form> functionalities ); add a keyDown event listener on parent html element where your form logically is; then handle enter key code.

function (event) {
    if (event.which == 13 || event.keyCode == 13) {
        // enter key had been pressed
        // submit
    }
};

Edit: how handle keydown manually:

<div onKeyDown={(e)=>console.log(e.keyCode)}>
  <input .... />
  <input .... />
  <Search onSearchChange={(e) => this.handleSearchChangeNew(e.target.value)} />
</div>
Mechanic
  • 5,015
  • 4
  • 15
  • 38
  • Is the code snippet above the keydown event listener, or the code that's called by the listener? If it's the code that's called by the listener, what does the listener itself look like? Also, what to put in place of the "// submit" comment that actually does the submit? – Jack BeNimble Feb 02 '21 at 03:39
  • Using the
    tag sounds interesting, but I'm not exactly sure how to put it in the code. Can you give a bit more detail?
    – Jack BeNimble Feb 02 '21 at 03:41
  • @JackBeNimble There is a [handy article](https://reactjs.org/docs/forms.html) in reactjs.org, explains most stuff related to forms and how to use them with react – Mechanic Feb 02 '21 at 05:40