Search code examples
reactjstypescriptionic-frameworkionic-react

Ionic React trying to implement a filtering search bar to filter pre made lists by their title


I have been struggling on how to create a search bar in my Ionic application. As when I try to find out how to create a search bar I only find examples of Angular with Ionic and the React example on the Ionic docs does not help unfortunately. Also when I search simply for how to do it with React and Typescript I keep hitting a dead end. I can't seem to comprehend how to implement the search bar to allow the user to type in the title which then will only display that card on its own. Any help would be greatly appreciated to figure out the solution to this problem.

import React, { useState } from "react";
import {
  IonHeader,
  IonContent,
  IonToolbar,
  IonTitle,
  IonPage,
  IonButton,
  IonCard,
  IonCardHeader,
  IonCardSubtitle,
  IonCardTitle,
  IonCardContent,
  IonGrid,
  IonRow,
  IonCol,
  IonItem,
  IonLabel,
  IonFooter,
  IonModal,
  IonIcon,
  IonSearchbar,
} from "@ionic/react";

export const SEARCH = [
  {
    id: "s1",
    title: "Business",
    detail:
      "It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English.",
    page: "/search-business",
  },
  {
    id: "s2",
    title: "Computing",
    detail:
      "It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English.",
    page: "/search-computing",
  },
  {
    id: "s3",
    title: "Connections",
    detail:
      "It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English.",
    page: "/search-connections",
  },
  {
    id: "s4",
    title: "Construction",
    detail:
      "It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English.",
    page: "/search-construction",
  },
  {
    id: "s5",
    title: "Engineering",
    detail:
      "It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English.",
    page: "/search-engineering",
  },
  {
    id: "s6",
    title: "Graduate",
    detail:
      "It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English.",
    page: "/search-graduate",
  },
  {
    id: "s7",
    title: "Marketing",
    detail:
      "It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English.",
    page: "/search-marketing",
  },
  {
    id: "s8",
    title: "Medicine",
    detail:
      "It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English.",
    page: "/search-medicine",
  },
  {
    id: "s9",
    title: "Science",
    detail:
      "It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English.",
    page: "/search-science",
  },
];

export const Search: React.FC = () => {
  const [showModal, setShowModal] = useState(false);

  return (
    <IonPage>
      <IonHeader>
        <IonToolbar>
          <IonTitle>Search</IonTitle>
        </IonToolbar>
        <IonToolbar>
          <IonSearchbar>
            
          </IonSearchbar>
        </IonToolbar>
      </IonHeader>
      <IonContent className="ion-padding">
        <IonGrid>
          <IonRow>
            {SEARCH.map((search) => (
              <IonCol
                size="12"
                size-xs="12"
                size-sm="6"
                size-md="4"
                size-lg="4"
                key={search.id}
              >
                <IonCard>
                  <IonCardHeader>
                    <IonCardTitle>{search.title}</IonCardTitle>
                    <IonCardSubtitle>Sector</IonCardSubtitle>
                  </IonCardHeader>
                  <IonCardContent>{search.detail}</IonCardContent>
                  <IonFooter className="ion-text-right">
                    <IonButton
                      color="secondary"
                      fill="clear"
                      routerLink={search.page}
                    >
                      View
                    </IonButton>
                  </IonFooter>
                </IonCard>
              </IonCol>
            ))}
            <IonCol className="ion-text-center">
              <IonModal isOpen={showModal} cssClass="my-custom-class">
                <p>This is modal content</p>
                <IonButton
                  color="secondary"
                  onClick={() => setShowModal(false)}
                >
                  Close Modal
                </IonButton>
              </IonModal>
              <IonButton color="secondary" onClick={() => setShowModal(true)}>
                Information
              </IonButton>
            </IonCol>
          </IonRow>
        </IonGrid>
      </IonContent>
    </IonPage>
  );
};

export default Search;


Solution

  • As pointed out by Cuong Manh Nguyen you need to add onIonChange on the searchBar and filter the search array whenever the search query is changed

    import React, { useState, useEffect } from "react";
    import {
      IonHeader,
      IonContent,
      IonToolbar,
      IonTitle,
      IonPage,
      IonButton,
      IonCard,
      IonCardHeader,
      IonCardSubtitle,
      IonCardTitle,
      IonCardContent,
      IonGrid,
      IonRow,
      IonCol,
      IonItem,
      IonLabel,
      IonFooter,
      IonModal,
      IonIcon,
      IonSearchbar,
    } from "@ionic/react";
    
    export const SEARCH = [
      {
        id: "s1",
        title: "Business",
        detail:
          "It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English.",
        page: "/search-business",
      },
      {
        id: "s2",
        title: "Computing",
        detail:
          "It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English.",
        page: "/search-computing",
      },
      {
        id: "s3",
        title: "Connections",
        detail:
          "It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English.",
        page: "/search-connections",
      },
      {
        id: "s4",
        title: "Construction",
        detail:
          "It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English.",
        page: "/search-construction",
      },
      {
        id: "s5",
        title: "Engineering",
        detail:
          "It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English.",
        page: "/search-engineering",
      },
      {
        id: "s6",
        title: "Graduate",
        detail:
          "It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English.",
        page: "/search-graduate",
      },
      {
        id: "s7",
        title: "Marketing",
        detail:
          "It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English.",
        page: "/search-marketing",
      },
      {
        id: "s8",
        title: "Medicine",
        detail:
          "It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English.",
        page: "/search-medicine",
      },
      {
        id: "s9",
        title: "Science",
        detail:
          "It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English.",
        page: "/search-science",
      },
    ];
    
    export const Search: React.FC = () => {
      const [showModal, setShowModal] = useState(false);
      const [searchQuery, setSearchQuery] = useState('');
      const [filteredSearch, setFilteredSearch] = useState([
      {
        id: "",
        title: "",
        detail: "",
        page: "",
      }])
    
    useEffect(() => {
        let tempSearchResult = SEARCH.filter(ele => ele.title.includes(searchQuery))
        setFilteredSearch([...tempSearchResult])
    },[searchQuery])
    
      return (
        <IonPage>
          <IonHeader>
            <IonToolbar>
              <IonTitle>Search</IonTitle>
            </IonToolbar>
            <IonToolbar>
              <IonSearchbar value={searchQuery} onIonChange={e => setSearchQuery(e.detail.value!) >
                
              </IonSearchbar>
            </IonToolbar>
          </IonHeader>
          <IonContent className="ion-padding">
            <IonGrid>
              <IonRow>
                {filteredSearch.map((search) => (
                  <IonCol
                    size="12"
                    size-xs="12"
                    size-sm="6"
                    size-md="4"
                    size-lg="4"
                    key={search.id}
                  >
                    <IonCard>
                      <IonCardHeader>
                        <IonCardTitle>{search.title}</IonCardTitle>
                        <IonCardSubtitle>Sector</IonCardSubtitle>
                      </IonCardHeader>
                      <IonCardContent>{search.detail}</IonCardContent>
                      <IonFooter className="ion-text-right">
                        <IonButton
                          color="secondary"
                          fill="clear"
                          routerLink={search.page}
                        >
                          View
                        </IonButton>
                      </IonFooter>
                    </IonCard>
                  </IonCol>
                ))}
                <IonCol className="ion-text-center">
                  <IonModal isOpen={showModal} cssClass="my-custom-class">
                    <p>This is modal content</p>
                    <IonButton
                      color="secondary"
                      onClick={() => setShowModal(false)}
                    >
                      Close Modal
                    </IonButton>
                  </IonModal>
                  <IonButton color="secondary" onClick={() => setShowModal(true)}>
                    Information
                  </IonButton>
                </IonCol>
              </IonRow>
            </IonGrid>
          </IonContent>
        </IonPage>
      );
    };
    
    export default Search;