Tips for preventing the ngbTypeahead input field from automatically opening when focused until all data is fully mapped

When clicking on the input field, I want the typeahead feature to display the first 5 results. I have created a solution based on the ngbTypeahead documentation.

app.component.html

<div class="form-group g-0 mb-3">
  <input id="typeahead-prevent-manual-entry" type="text" class="form-control"
  placeholder="Big dataset"
  formControlName="bigDataset"
  [ngbTypeahead]="search"
  [inputFormatter]="valueFormatter"
  [resultFormatter]="valueFormatter"
  [editable]="false"
  [focusFirst]="false"
  (focus)="stateFocus$.next($any($event).target.value)"
  (click)="stateClick$.next($any($event).target.value)"
  #instance="ngbTypeahead" />
</div>

app.component.ts

type BigDataset: {
  id: string,
  name: string
}

export class AppComponent implements OnInit {
  dataset: BigDataset[];

  @ViewChild('instance', {static: true}) instance: NgbTypeahead;
  focus$ = new Subject<string>();
  click$ = new Subject<string>();

  constructor(
    private formBuilder: FormBuilder,
  ) { }

  ngOnInit(): void {
    this.dataForm = this.formBuilder.group({
      bigDataset: ["", [Validators.required]],
    });
  }

  getBigDataset() {
    //Excluded for simplicity. This returns a set of objects (~3000)
    //of type BigDataset and assigns it to this.dataset.
  }

  valueFormatter = (value: any) => value.name;

  search: OperatorFunction<string, readonly BigDataset[]> = (text$: Observable<string>) => {
    const debouncedText$ = text$.pipe(debounceTime(100), distinctUntilChanged());
    const clicksWithClosedPopup$ = this.click$.pipe(filter(() => !this.instance.isPopupOpen()));
    const inputFocus$ = this.focus$;

    return merge(debouncedText$, inputFocus$, clicksWithClosedPopup$).pipe(map(term => (term === '' ? this.dataset
        : this.dataset.filter(data => data.name.toLowerCase().indexOf(term.toLowerCase()) > -1)).slice(0, 5))
    );
  };
}

Although the code works as intended, there is an issue when clicking on the input field immediately after page initialization, resulting in the following error:

ERROR TypeError: Cannot read properties of undefined (reading 'slice')
    at org-address.component.ts:93:109
    // The rest of the error messages follow...

The root cause seems to be that the typeahead attempts to display data before completing the map function. Since the mapping process duration can vary with dataset size, I am seeking a way to disable or implement an alternative until the mapping completes without having to wait indefinitely.

I attempted to programmatically disable and enable the form field using finalize(), but encountered difficulty as the field remained disabled even after the completion of mapping.

search: OperatorFunction<string, readonly BigDataset[]> = (text$: Observable<string>) => {
    this.dataForm.get('bigDataset')?.disable();
    // The remaining functionality and code snippets go here...
    return merge(debouncedText$, inputFocus$, clicksWithClosedPopup$).pipe(
      finalize(() => this.dataForm.get('bigDataset')?.enable()),
      map(term => (term === '' ? this.dataset
        : this.dataset.filter(data => data.name.toLowerCase().indexOf(term.toLowerCase()) > -1)).slice(0, 5))
    );
  };

If anyone can provide assistance or suggestions regarding this matter, it would be greatly appreciated.

Answer №1

I was fortunate enough to receive a helpful tip from a friend regarding this issue. The solution involved implementing optional chaining after data filtering, right before the splicing process. Simply adding '?' before invoking the slice method resolved the error seamlessly, preventing it from attempting to return a value prior to the completion of the filtering process.

search: OperatorFunction<string, readonly BigDataset[]> = (text$: Observable<string>) => {
    const debouncedText$ = text$.pipe(debounceTime(100), distinctUntilChanged());
    const clicksWithClosedPopup$ = this.click$.pipe(filter(() => !this.instance.isPopupOpen()));
    const inputFocus$ = this.focus$;

    return merge(debouncedText$, inputFocus$, clicksWithClosedPopup$).pipe(map(term => (term === '' ? this.dataset
        : this.dataset.filter(data => data.name.toLowerCase().indexOf(term.toLowerCase()) > -1))?.slice(0, 5))
    );
  };

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

The pagination in React using React Query will only trigger a re-render when the window is in

Currently, I am utilizing React-Query with React and have encountered an issue with pagination. The component only renders when the window gains focus. This behavior is demonstrated in the video link below, The video showcases how the component re-renders ...

Angular - The filter method cannot be used on Observables

I have a database with users who need to complete unique homework sessions. Each homework session has its own identifier, name, date, and other details. After fetching all the user's homework from the database, it is stored in a private variable call ...

ERROR: There was a problem with the NgbTabset class at line 12 in the inline template. This issue occurred because the 'templateRef' property could not be read as it was undefined

I am utilizing ng-bootstrap instead of ui-bootstrap in angular2 for my project. This is the HTML code I am using: <div class="row" style="height: 100%;"> <div class="col-12"> <div class="container" id="contentMain"> <div ...

Effective Management of Uploaded Files

I am currently working on an Angular2 application that interacts with a .NET WebApi to generate text files. Once these files are created, the goal is for users to be able to download them from the application. I am seeking guidance on the best practices ...

Leveraging NPM workspaces in combination with Expo and Typescript

I'm struggling to incorporate NPM 7 workspaces into a Typescript Expo project. The goal is to maintain the standard Expo structure, with the root App.tsx file, while segregating certain code sections into workspaces. I'm facing challenges compil ...

What is the evaluation process for conditions like someItem?.someField==somevalue in Angular?

Let's consider a simple condition in the markup: someItem?.someField==somevalue What does this mean? Is it equivalent to someItem!=null && someItem!=undefined && someItem==somevalue So essentially, if someItem is undefined, the ent ...

What is the best way to transfer a property-handling function to a container?

One of the main classes in my codebase is the ParentComponent export class ParentComponent extends React.Component<IParentComponentProps, any> { constructor(props: IParentComponent Props) { super(props); this.state = { shouldResetFoc ...

What could be the reason for the variable's type being undefined in typescript?

After declaring the data type of a variable in TypeScript and checking its type, it may show as undefined if not initialized. For example: var a:number; console.log(a); However, if you initialize the variable with some data, then the type will be display ...

Creating a data structure that filters out specific classes when returning an object

Consider the following scenario: class MyClass {} class MyOtherClass { something!: number; } type HasClasses = { foo: MyClass; bar: string; doo: MyClass; coo: {x: string;}; boo: MyOtherClass; }; type RemovedClasses = RemoveClassTypes& ...

What is preventing me from running UNIT Tests in VSCode when I have both 2 windows and 2 different projects open simultaneously?

I have taken on a new project that involves working with existing unit tests. While I recently completed a course on Angular testing, I am still struggling to make the tests run smoothly. To aid in my task, I created a project filled with basic examples f ...

What is the best way to create props that can accommodate three distinct types of functions in TypeScript?

I have been encountering a problem with the last function in my props interface that is supposed to support 3 different types of functions throughout the application. Despite adding parentheses as requested, I am still facing errors. // In Parent compon ...

What methods are typically used for testing functions that return HTTP observables?

My TypeScript project needs to be deployed as a JS NPM package, and it includes http requests using rxjs ajax functions. I now want to write tests for these methods. One of the methods in question looks like this (simplified!): getAllUsers(): Observable& ...

Setting the Formgroup status to Invalid will only occur if there are errors in multiple fields, not just one

I'm having an issue with my form where setting passportrank as error does not change the formgroup status to Invalid. Additionally, when I navigate to the next section, the inline error message of "You are not eligible" also gets cleared. ngOnInit() ...

What is the best way to send props (or a comparable value) to the {children} component within RootLayout when using the app router in Next.js

As I work on updating an e-commerce website's shopping cart to Next.js 13+, I refer back to an old tutorial for guidance. In the previous version of the tutorial, the _app.ts file utilized page routing with the following code snippet: return ( < ...

Show image using Typescript model in Angular application

In my Angular (v8) project, I have a profile page where I typically display the user's photo using the following method: <img class="profile-user-img" src="./DemoController/GetPhoto?Id={{rec.Id}}" /> However, I am considering an alternative ap ...

How to Eliminate Lower Borders from DataGrid Component in Material UI (mui)

I've been trying to customize the spacing between rows in a MUI Data Grid Component by overriding the default bottom border, but haven't had much success. I've experimented with different approaches such as using a theme override, adding a c ...

Converting an array of objects to an array based on an interface

I'm currently facing an issue with assigning an array of objects to an interface-based array. Here is the current implementation in my item.ts interface: export interface IItem { id: number, text: string, members: any } In the item.component.ts ...

What is the solution to the strict mode issue in ANGULAR when it comes to declaring a variable without initializing it?

Hi everyone! I'm currently learning Angular and I've encountered an issue when trying to declare a new object type or a simple string variable. An error keeps appearing. this_is_variable:string; recipe : Recipe; The error messages are as follows ...

Cleaning up HTML strings in Angular may strip off attribute formatting

I've been experimenting and creating a function to dynamically generate form fields. Initially, the Angular sanitizer was removing <input> tags, so I discovered a way to work around this by bypassing the sanitation process for the HTML code stri ...

Building a Dynamic Video Element in Next Js Using TypeScript

Is there a way to generate the video element in Next JS using TypeScript on-the-fly? When I attempt to create the video element with React.createElement('video'), it only returns a type of HTMLElement. However, I need it to be of type HTMLVideoEl ...