Creating a custom autocomplete search using Angular's pipes and input

Trying to implement an autocomplete input feature for any field value, I decided to create a custom pipe for this purpose.

One challenge I'm facing is how to connect the component displaying my JSON data with the component housing the autocomplete input?

Should I utilize the @Input and @Output decorators for this task?

As a beginner, I'm a bit lost on how to proceed with this setup.

Any help or guidance on this matter is greatly appreciated.

json.file

 {
        "boatType": "Semi-rigide",
        "img": "/assets/img/boat-img/semi-rigide.jpg",
        "longeur": 10,
        "largeur": 20,
        "tirantEau": 50,
        "equipage": false,
        "annexe": true
    },

table.component.html

<div class="search">
    <app-input #inputComponent></app-input>
</div>
<table>
   <caption>Statement Summary</caption>
    <thead>
        <tr>
            <th scope="col" class="toto">img</th>
            <th scope="col">Type de bateau</th>
            <th scope="col">longeur</th>
            <th scope="col">largeur</th>
            <th scope="col">tirant d'eau</th>
            <th scope="col">equipage</th>
            <th scope="col">annexe</th>
        </tr>
    </thead>
    <tbody>
        <tr *ngFor="let boat of user | filter : inputComponent?.searchText">
            <td data-label="img"><img [src]="boat.img" alt="boat" class="img"></td>
            <td data-label="boat type">{{ boat.boatType }}</td>
            <td data-label="longeur">{{boat.longeur}} cm</td>
            <td data-label="largeur">{{boat.largeur}} cm</td>
            <td data-label="tirant d'eau">{{boat.tirantEau}} cm</td>
            <td data-label="equipage">{{boat.equipage ? "Oui" : "Non"}}</td>
            <td data-label="annexe">{{boat.annexe ? "Oui" : "Non"}}</td>
        </tr>
    </tbody>
</table>

input.component.html

 <input type="text" placeholder="Chercher un bateau.." [(ngModel)]="searchText">

filter.pipe

     import { Pipe, PipeTransform } from '@angular/core';
        
        @Pipe({
          name: 'filter'
        })
        export class FilterPipe implements PipeTransform {
        
        transform(items: any[], searchText: string): any[] {
    if (!items) return [];
    if (!searchText) return items;

    // TODO: need to improve this filter
    // because at this moment, only filter by boatType
    return items.filter(item => {
      return item.boatType.toLowerCase().includes(searchText.toLowerCase());
    });
  }
        
        }

Answer №1

It appears that there are some adjustments required in the code as the tools have been utilized incorrectly.

However, after refactoring the code slightly, it was successfully functioning.

A brief description is provided along with the solution available on stackblitz: https://stackblitz.com/edit/angular-ivy-ybubhx?file=src/app/filter.pipe.ts

In order to access the search input reference from the app-input component, I had to utilize #inputComponent. (There are alternative methods for achieving this).

app.component.html

<div class="search">
  <!-- A variable named inputComponent is created within the template -->
  <app-input #inputComponent></app-input> 
</div>
<table>
  <caption>Statement Summary</caption>
  <thead>
    <tr>
      <th scope="col">type</th>
      <th scope="col">length</th>
      <th scope="col">width</th>
      <th scope="col">>draft<</th>
      <th scope="col">crew</th>
      <th scope="col">tender</th>
    </tr>
  </thead>
  <body>
    <!-- The searchText string retrieved from inputComponent is passed to the filter pipe -->
    <tr *ngFor="let boat of boats | filter : inputComponent?.searchText">
      <td data-label="boat type">{{ boat.boatType }}</td>
      <td data-label="length">{{boat.length}} cm</td>
      <td data-label="width">{{boat.width}} cm</td>
      <td data-label="draft">{{boat.draft}} cm</td>
      <td data-label="crew">{{boat.crew ? "Yes" : "No"}}</td>
      <td data-label="tender">{{boat.tender ? "Yes" : "No"}}</td>
    </tr>
  </tbody>
</table>

app.component.ts

import { Component, VERSION } from "@angular/core";

@Component({
  selector: "my-app",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.css"]
})
export class AppComponent {
  // The 'boats' array is used as an example payload to showcase the filter pipe functionality
  boats = [
    {
      boatType: "a1a12",
      img: "/assets/img/boat-img/semi-rigide.jpg",
      length: 10,
      width: 20,
      draft: 50,
      crew: false,
      tender: true
    },
    {
      boatType: "EAEA",
      img: "/assets/img/boat-img/eaea.jpg",
      length: 10,
      width: 20,
      draft: 50,
      crew: false,
      tender: true
    },
    {
      boatType: "bcbc",
      img: "/assets/img/boat-img/bcbc.jpg",
      length: 10,
      width: 20,
      draft: 50,
      crew: false,
      tender: true
    },
    {
      boatType: "bcbc 2",
      img: "/assets/img/boat-img/bcbc.jpg",
      length: 10,
      width: 20,
      draft: 50,
      crew: false,
      tender: true
    }
  ];
}

input.component.ts

import { Component, Input } from "@angular/core";

@Component({
  selector: "app-input",
  template: `
    <input
      type="text"
      placeholder="Search for a boat.."
      [(ngModel)]="searchText"
    />
  `,
  styles: [
    `
      h1 {
        font-family: Lato;
      }
    `
  ]
})
export class InputComponent {
  searchText: string;
}

filter.pipe.ts


import { Pipe, PipeTransform } from "@angular/core";

@Pipe({
  name: "filter"
})
export class FilterPipe implements PipeTransform {
  transform(items: any[], searchText: string): any[] {
    if (!items) return [];
    if (!searchText) return items;

    // Additional enhancements can be made to this filter
    // Currently, it only filters by boatType
    return items.filter(item => {
      return item.boatType.toLowerCase().includes(searchText.toLowerCase());
    });
  }
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What could be the reason for ngOnChanges lifecycle hook not getting invoked?

I am currently experimenting with Angular 2 in an effort to learn more about it. I noticed that ngOnChanges is not triggering in the code below: app.component.ts: import { Component, Input } from "@angular/core" import { FormsModule } from '@angular ...

What is the process of extracting information from a JSON file and how do I convert the Date object for data retrieval?

export interface post { id: number; title: string; published: boolean; flagged: string; updatedAt: Date; } ...

How can I verify that the value entered in an input field matches a specific date format such as "MM/dd/YYYY" using Angular?

I need to validate if a given value matches a specific date format such as "MM/dd/YYYY." Typescript file onValChange(event: Date) { const datePipe = new DatePipe('en-US'); const val = datePipe.transform(event, 'MM/dd/yyyy'); ...

Extracting Raw Body from Stripe Webhook in NextJS

I'm feeling frustrated trying to get a raw body passed for the Stripe webhook in NextJS! Despite trying numerous solutions from various sources, I just can't seem to get it to work. Calling upon the developers with special powers (of which I am ...

What is the best method to create a TypeScript dictionary from an object using a keyboard?

One approach I frequently use involves treating objects as dictionaries. For example: type Foo = { a: string } type MyDictionary = { [key: string]: Foo } function foo(dict: MyDictionary) { // Requirement 1: The values should be of type Foo[] const va ...

Guide on spinning a particle in three.js

I am encountering an issue with a particle that leaves a circle behind when rotated as an image. How can I eliminate this unwanted circle effect? Check out the code on this Fiddle: http://jsfiddle.net/zUvsp/137/ Here's the code snippet: var camera, ...

Guide to establishing a primary filter for my Json information with Angular.js?

After spending multiple days searching and reading, I am struggling to set an initial value for the data from a Rails JSON file in my application. The app focuses on incident tickets, and although I am able to retrieve all entries from the database using d ...

Tips on efficiently reusing shared components within recursive union types in TypeScript

Summary Here's a simple working example in the TypeScript playground: type SimpleExpression = number | string | AddOperator<SimpleExpression> | PrintOperator<SimpleExpression>; type ExtendedExpression = number | string | AddOperator<E ...

Retrieve the AJAX response, concatenate the data, and construct a dynamic table

I am facing an issue with assigning my AJAX return as a variable to concatenate. Here is the sample code: function FetchSex() { $.ajax({ url: '/SEX/GetAllSex/', success: function (responseDat ...

The utilization of *ngTemplateOutlet for conditional rendering is experiencing issues when used within a formGroup

Developed a reusable form input designed to be displayed within a form either as part of a parent formGroupName or independently as a regular input control. The code implementation is: child.component.html: <ng-container *ngIf="hasFormGroup; then f ...

Creating interactive JavaScript elements that can be moved around within a container

I recently faced a challenge while attempting to make draggable elements within a div. The issue arose when I realized that I couldn't figure out how to drag each element individually without affecting the others. My current code only allows for handl ...

I am looking to establish a connection with a dynamic open source database in real time. My goal is to capture and store data only if a specific key value is detected,

JSON format: [{"SH_MSG": {"time": "1657291114000", "area_id": "D1", "address": "54", "msg_type": "SH", "data": "8CFB0B00"}}, {"SF_MSG": ...

Building a single-page app optimized for mobile viewing with Foundation framework

Currently facing an issue with the scaling of the viewport on certain mobile devices when loading new content via ng-include in our responsive website built on Foundation. The problem arises as the width of the page breaks, leading to horizontal scrolling. ...

After the request.send() function is called, the request is not properly submitted and the page automatically redirects

I'm currently working on a basic ajax comment form that includes a textarea and a yes/no radio button. If the user selects 'yes', their comments are posted and then they are redirected to a new page. If the user selects 'no', th ...

Creating a dynamic polyline with custom data on Mapbox is a great way to enhance your mapping experience

Hey everyone, I'm looking to create a polyline or path on Mapbox using my own data. I came across an example on mapbox.com that shows how to draw a sine wave on the map. How can I customize this example to use my own data? <!DOCTYPE html> <h ...

JavaScript that is subtle and lacks function parameters

Suppose you have: <div id="data" onclick="handleData(1)">Datum 1</div> and you prefer late binding instead: <div id="data">Datum 1</div> <script> $("#data").click(function() { handleData(1); }) </script&g ...

Discover the best method for transferring MySQL data between pages

Can anyone help guide me in the right direction on how to allow a user to click a link within a PHP While Loop generated MySQL table and pass that data to another page? I've searched through similar questions but haven't found a solution that fit ...

Error: Unable to locate module: "./library". The parent module directory is "/"

I keep encountering an issue in my project when attempting to load a module. Whenever I try to import it from the node_modules folder, I receive the following error: Uncaught Error: Module not found: "./MyLibrary". Parent module folder was: "/" However, i ...

Is there a way to verify the presence of a selector in Puppeteer?

How can I use Puppeteer to check if #idProductType exists and if not, assign producttype to ""? I have tried multiple solutions but none seem to work. const urls = [myurls, ...] const productsList = []; for (let i = 0; i < urls.length; i++) ...

Create a scrollable div within a template

After discovering a template that I want to use for my personal project, I noticed a missing element... There's a div where content can be added. That's fine, but what if I add more content than fits in the space provided? The whole website beco ...