Angular displays a datalist input as "[object Object]" once a value has been selected

In my form, I have the following section:

<div formArrayName="studentPublishing" *ngFor="let all of getstudentPublishing().controls; index as i">
    <div class="form-group data">
        <input type="text" list="options" class="form-control" placeholder="Students" (change)="getAuthor($event,i)" [formControlName]="i" required>

        <datalist id="options">
        <option *ngFor="let c of dataStudent" [value]="c.name">{{ c.name }}</option>
        </datalist>

        <div class="rem"><button (click)="removeAuthor(i)">-</button></div>

        <div *ngIf="!formPublic.get('studentPublishing')?.valid && formPublic.get('studentPublishing')?.touched" class="validation-error">
            <p>Authors are mandatory</p>
        </div>

    </div>
</div>
<div id="add" class="add"><button type="button" (click)="addAuthor()">Author +</button></div>

Everything is functioning correctly. The value displayed in the input is the Student object retrieved from the database. However, when a student is selected, it only shows [object Object].

Below is my TypeScript function that receives the value from the datalist and assigns it to the "student" array variable in the form:

getAuthor(e: any, id:number){
    const studentName = e.target.value;
    const studentSelected = this.dataStudent.find(x => x.name === studentName);
    if (studentSelected) {
      this.getstudentPublishing().at(id).setValue(studentSelected);
    }
}

I tried using ngValue and also attempted to stringify the value using the json pipe:

<option *ngFor="let c of dataStudent" [ngValue]="c">{{ c.name | json }}</option>

I even tried passing the value as a string with just the name of the selected object:

<option *ngFor="let c of dataStudent" value="{{ c.name }}"></option>

However, when saving the value in the variable, only the name is stored instead of the entire object.

Here is how the input appears when a student is selected:

input datalist image showing [object Object]

This is the desired appearance after selecting a student:

input datalist image displaying selected student's name

Solution

Thanks to Daniel Gimenez's helpful response, I managed to resolve the issue. The solution looked like this:

this.formPublic.updateValueAndValidity();
if(this.formPublic.valid){
  const studentControls = this.getstudentPublishing().controls;
  const students = studentControls.map(y => {
    const name = y.value;
    console.log(name);
    return this.dataStudent.find(student => student.name === name);
  });

  for (let i = 0; i < students.length; i++) {
    this.getstudentPublishing().at(i).setValue(students[i]);
    console.log(students[i]?.name);
  }
}

Answer №1

The problem lies in the fact that the FormControl is being used for two different purposes - to store either a string name or a Student object. Below is just one approach you can take to address this issue.

Adjusting the FormControl elements to hold string values

In this scenario, each control should be of type FormControl<string>. You may already have a Required Validator on the control, but consider adding a custom validator for checking existing student names as well. Here's an example of how it could be implemented:

export function existingStudentValidator(students: Student[]): ValidatorFn {
  return (control: AbstractControl): ValidationErrors | null => {
    const isExisting = students.some(x => x.name === control.value);
    return !isExisting ? { existingStudent: {value: control.value} } : null;
  };
}

When you need to retrieve the FormArray value as an array of Student objects, simply ensure that the form is valid and then convert the values using Array.map().

this.form.updateValueAndValidity(); // Update form validity.
if (this.form.valid) {
  const students = this.form.studentPublishing.map(x => 
    this.dataStudent.find(y => y.name === x.name)!); // Assume name isn't null.
  /* ... Perform actions with 'students' ... */
}

There are additional considerations to keep in mind, such as whether the name matching should be case insensitive or handling scenarios where multiple students share the same name. However, this guidance should help you get started.

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

This TypeScript error indicates that the variable may be undefined (Error code: 18048)

One of the challenges I encountered in my Angular project was with an interface defined in userinterface.ts export interface Done { wordlen: number; word: string; }; I utilized this interface to populate an array like so donearr: Done[] = []; ...

Stop allowing the entry of zero after a minus sign

One of the features on our platform allows users to input a number that will be automatically converted to have a negative sign. However, we want to ensure that users are unable to manually add a negative sign themselves. We need to find a solution to pre ...

Is it possible to align a row so that it is centered based on one of the columns in the row?

Calling all experts in CSS and HTML: Let's say I have 3 columns in a row, each with a different size (refer to the image). Now, picture this - I want to center the 2nd column right in the middle of my page. If I simply use justify-content: center to ...

Button in Angular gets stuck when a touchscreen is long pressed

In my Angular2 application, I am facing an issue with a button when running on a Windows 10 touchscreen PC in Chrome. Normally, the button works fine and executes the click function. However, if the button is held for 1-2 seconds, it gets stuck and fails t ...

Tips for avoiding recursive error function calls in Angular 5

Is there a way to avoid repetitive function calls within a recursive function? Take a look at the following code snippet: loadFinalData(id, color){ this.data = this._test.getUrl(id, "white"); this.dataHover = this._test.getUrl(id, "blue"); } pri ...

Scrolling with React Event

I am attempting to create a scrollbar that only appears when I scroll within a particular area using React. I am utilizing debounce and useState in my implementation. The issue: When I reach the end of the scroll, the event continues to repeat indefinitel ...

Can TypeScript provide a way to declare that a file adheres to a particular type or interface?

Experimenting with different TypeScript styles has been quite enjoyable, especially the import * as User from './user' syntax inspired by node. I've been wondering if there is a way to specify a default type as well. Suppose I have an interf ...

Validating Credit Card Numbers with Spaces

Currently, I am in the process of creating a credit card form that requires validation using checkValidity to match the specific card pattern that is dynamically added to the input field. For example, if a user enters a Mastercard number such as 545454545 ...

Enhancing Angular with Plotly: Implementing click events on bar chart legends

I'm currently working on implementing color pickers for my plotly-plot charts within an Angular template. I am looking to add a function that triggers when the chart legend is clicked. How can I achieve this and get a click event for the chart legends ...

Testing a callback function within a method in Angular

I am currently working with Angular 11 using TypeScript and I am unsure how to properly test scenarios where an exception is raised within my method. myMethod() { this.myService.callBackend(id).subscribe(() => { // do something when success ...

Angular project seems to be stuck in a continuous cycle of

Currently, my application consists of spring boot as the backend and Angular as the front end. However, when I try to access the application through localhost:4200, the page continuously refreshes every few seconds. This issue did not occur previously, so ...

Angular will continue to stay on the current page unless the form is completed

Once a user logs in, they are directed to a form where they can enter their name and username. http://localhost:4200/form I need to ensure that the user fills out the form before being redirected to another page, even if they try to change the URL. In m ...

Ways to receive a reply from EventEmitter

From the child component, I made a call to a certain method. Here is the code in the child component: @Output() parentEvent = new EventEmitter<any>(); click1() { //calling the specified method from the child this.parentEvent.emit(myObj1); ...

View the Sub content from a ngFor Array upon clicking

For my project, I have a scenario where each card value is displayed on the screen by looping over JSON data using ngFor. The objective is to show specific information from the JSON when a user clicks on a card, utilizing *ngIf to display content only in a ...

Encountering a runtime issue when implementing Ng2-charts within an Angular/Node.js project

I encountered an error while running my Angular4 - Node.js application. The error message states: Can't bind to 'data' since it isn't a known property of 'canvas'. ("iv> ][data]="doughnutChartData" [labels]="doughnutChart ...

Angular is able to successfully retrieve the current route when it is defined, but

Here's the code snippet I am working with: import { Router } from '@angular/router'; Following that, in my constructor: constructor(router: Router) { console.log(this.router.url); } Upon loading the page, it initially shows the URL a ...

What is the best way to hide the back arrow in Cordova UWP for Ionic 4?

I am currently developing a Windows 10 (UWP) application using Ionic 4 (Angular). I want to remove the back arrow from the interface: Example of back arrow I have attempted various solutions, such as implementing in the app.component constructor with in ...

Using Reactive Forms group in router-outlet

I'm encountering a problem while trying to share my Reactive Forms among multiple components, specifically in the context of routing. The error message I see is: 'Can't bind to 'group' since it isn't a known property of &apos ...

Identifying input value changes without needing to manually enter key values

As an example: <input class="table-input" type="number" name="qty" [(ngModel)]="cpy.qty" matInput min="1" max="{{cpy.qty}}" where cpy represents an object that is constantly changing. Currently, I need to execute a certain operati ...

Performing DTO validation in the controller before passing data to the service

My current challenge involves implementing validation in a PUT request to update data stored in MongoDB: DTO: export enum reportFields { 'startDate', 'targetDateOfCompletion', 'duration', } export class updateS ...