Angular 5 Recommendations Guide

In my application, I have a FormGroup containing a FormArray with populated FormControl entries. To enhance user experience, I created a service that utilizes an Observable for value changes. This service looks up similar words in a predefined "dictionary" array and returns an array of objects to populate a suggestion list below the input field.

The suggestion list displays three terms similar to the given input string. For example, if the input is 'table', the suggestions could be:

  [
    {distance: 1, match : 'Table'},
    {distance: 3, match : 'Fabules'},
    {distance: 5, match : 'Ramioles'},
  ]

The Levenstein algorithm calculates the distance, representing the number of changes needed to transform one word into another.

To implement the desired behavior, clicking on a suggestion should update the value in the input field and hide the suggestion list.

An important feature is that the service initiates upon focusing on each input field, providing real-time suggestions.

component.html

 <form [formGroup]="myForm">
     <fieldset formArrayName="parameters">
         <ng-container *ngFor="let par of parameters.controls" [formGroup]="par">
             <input formControlName="name" />
             <ul class="filter-select">
                <li *ngFor="let r of results" class="filter-select-list">
                   {{ r.match }}
                </li>
            </ul>
         </ng-container>        
     </fieldset>
 </form>

I aim to achieve this functionality without relying on external libraries like ng2-completer or material autocomplete. Additionally, using datalist poses limitations when matching strings that contain multiple dictionary words.

Moreover, HTML5 datalist has cross-browser compatibility issues.

How can I effectively implement this behavior?

RECAP:

  1. Each input in the array must connect to a service triggered ON FOCUS to search for relevant words in the dictionary (successfully implemented)
  2. The service returns an array to populate the suggestion list (completed)
  3. Clicking on a suggestion updates the value
  4. The suggestion list disappears after selection

component.html

    <input [formControl]="queryField" type="text" />

service.ts

   this.queryField.valueChanges
    .debounceTime(200)
    .distinctUntilChanged()
    .subscribe( value => {  
     this.results = this._searchService.spell(value)
  })

SECOND PART

I devised a solution utilizing an Observable triggered by input focus to populate the suggestion list.

   @Component({
    selector: 'my-autocomplete-input',
    styleUrls: ['./app.component.css'],
    template: `
  <ng-content></ng-content>
  <ul class="filter-select">
      <li *ngFor="let r of autosuggestList" class="filter-select-list">
          <div (click)="editInput(r.match)">{{ r.match }}</div>
      </li>
  </ul>
  `
  })
  export class AutocompleteComponent  {
    @ContentChild("input") input: ElementRef;
    @Input() autosuggestList;


    constructor(
      private _searchService: SearchService,
    ) {}

    editInput(res) {
      this.input.nativeElement.value = res;
      this.autosuggestList = [];
    }

    ngAfterViewInit() {
      Observable.fromEvent(this.input.nativeElement, 'focus')
          .subscribe((data: KeyboardEvent) => {
            this.autosuggestList = this._searchService.spell(this.input.nativeElement.value)
          });
    }

  }

However, updating the form array does not occur simultaneously. The Form Control needs manual intervention to reflect changes in the input data.

Is there a way to patch/update the form from the contentChild element, specifically within the editInput function?

Answer №1

It seems unnecessary to have two inputs, one for name and one for value. Perhaps a single input with an accompanying dropdown selection would suffice for both? What do you think?

To keep your code organized, consider creating an AutocompleteInputComponent. Within this component, ensure that there is always an <input> element by declaring

@ContentChild('input') input: ElementRef;
.

In your parent component, you can then use the following structure:

<ng-container *ngFor="let par of parameters.controls" [formGroup]="par">
    <my-autocomplete-input [autosuggestList]="valuechange">
        <input formControlName="name"/>
    </my-autocomplete-input>
</ng-container>

If you find a need for a second input, you can differentiate between content children using CSS selectors: https://scotch.io/tutorials/angular-2-transclusion-using-ng-content

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

invoking a form utilizing the provided inputs in PHP

While this question may seem simple to many of you, I am struggling to implement it myself. As I work on generating reports, I have both monthly and daily reports. There is a drop down list to select between monthly and daily options. My main issue is fig ...

Dealing with Angular 2: Issues with Observables failing to return nested objects from services

I have an angular service that handles the retrieval of user objects. These user objects contain various attributes along with an array of walls. The service returns an observable to the component that calls it. While I am able to successfully create a u ...

Dealing with the name attribute in an array of ngModels in Angular 4

In this scenario, I have a class that defines hobbies and a user. Here is the structure: interface IHobby { name: string; type: string; } class User { constructor(public name: string, public hobbies: IHobby[]) { } } Now, when implementing a templa ...

Issue with Angular 2 - Basic form validation no longer functioning

The Angular 2 application I've been working on includes a simple form with input fields and basic HTML validation. Here's an example: <form (onSubmit)="submit()"> <input type="email" /> <input type="submit" value="save" /> ...

Automatically insert a hyphen (-) between each set of 10 digits in a phone number as it is being typed into the text

I'm attempting to automatically insert a hyphen (-) in between 10 digits of a phone number as it is being typed into the text field, following North American standard formatting. I want the output to look like this: 647-364-3975 I am using the keyup ...

Restrict the number of subscriptions allowed for an rxjs observable

Seeking a replacement for observable, subject, or event emitter that allows only one subscription at a time. The first subscriber should have priority to execute its subscribe function, with subsequent subscribers waiting their turn until the first unsubsc ...

Angular processes data and then uses subscribe to return the Observable

Can anyone help with how to make an HTTP GET call in Angular 5, process the output, and then return that processed output as an Observable? I'm currently struggling with this concept. Currently, my code looks like this: this.http.get<BarcodeRespons ...

Is there a way to implement imports based on a specific condition?

I'm just starting to learn Angular and TypeScript. My goal is to redirect multiple hostnames to a single Angular 6 project because most aspects are the same, with only language and URLs varying. For example, here's what I have implemented in ap ...

Why isn't TypeScript acknowledging my string literal declaration?

Below is the code snippet I am working with: type Timeframe = "morning" | "afternoon" | "evening"; let myTimeframe: Timeframe = "morning"; const someValue: any = {time: "incorrect"}; myTimeframe = someValue.time; console.log(myTimeframe); I want myTim ...

What causes the *ngIf to return true when compared to an observable that is either undefined or an empty object {}?

Why does this not result in false when the error$ object is undefined or an empty object represented as {}? Instead, it evaluates to true and shows the "Something went wrong" message. `<div *ngIf="(error$ | async) != null"> <span>Something w ...

I'm looking to display the message between the specified start date and end date that is selected in the input field

Is it possible to utilize ngOnChange? <div> <label for="start">Start date:</label> <input type="time" name="starts" [(ngModel)]="starts"> <label for="end">End date: </label> <input type="time" name="end" [(ng ...

Error: Spy creation was anticipated to have been invoked

Currently, I am in the process of writing unit test cases for an Angular 7 Component that utilizes an async service. Unfortunately, I encountered the following error: Error: Expected spy create to have been called once. It was called 0 times. Below is t ...

Activate the datepicker in Angular by clicking on the input field

This is my html file: <mat-form-field> <input matInput [matDatepicker]="picker" placeholder="Choose a date"> <mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle> <mat-datepicker #picker></mat-date ...

A utility type in Typescript for managing default database schema values

I am currently exploring a method for incorporating default and virtual values in a database schema. The concept involves using a utility type to automatically convert a schema for insertion (props with defaults or generated by virtuals aren't necessa ...

Angular-template static functions refer to functions that do not require an

Our project utilizes the linting-config provided by AirBnB. There is a rule that stipulates class methods must utilize this or be declared as static. While this rule theoretically makes sense, it seems to present challenges within an angular context. Consi ...

Dealing with a missing item in local storage in an Angular application

When working with local storage, I have a function that saves certain values and another method that reloads these values. However, what is the best approach to handle missing items in the local storage? This could happen if a user deletes an item or if it ...

What is the most effective method for preserving a record of information using MongoDB?

In my users collection, there is an attribute called "weight" that includes both a number value and a date. Users have the ability to update their weight, but I also want to store a historical record of all previous weights and the dates they were update ...

A wrapper component for React Native TextInput that allows clearing the value from an external source

For my App, I needed a component that wraps the TextInput element to ensure all text inputs have a uniform style and include a trash-can icon for clearing text. This is the code for my custom component: import React from 'react'; import { Te ...

Optimize your button clicks with the most effective method for passing query parameters

I have been working on a project where I came across an existing bootstrap button on a JSP page: <nav class="navbar navbar-dark bg-primary"> <div class="container-fluid pr0"> <button class="btn btn-primar ...

Typescript error: Undefined reference to 'DhImportKeyParams'

Working on a project, I encountered an issue with a third-party library written in Typescript 3.7. The outdated library depended on the 'lib' that contained an interface called DhImportKeyParams. However, my current project uses Typescript 4.6 wh ...