6

In my Angular 7 project, I have a reactive form with select and *ngFor blocks. ngFor values are filtered based selected value from the options and custom pipe takes care of filtering. Whenever I select a value from options, all I see is "[object Object]" output. I tried (ngModelChange)=fun(), change events. They did not work.

Form:

    <div class="container container-fluid">
      <h3 style="text-align: center"> BCMC CyberSecurity Jobs</h3>
      <form [formGroup]="jobsForm">
      <div class="row" style="margin-top: 40px">
        <div class="col-xs-6 col-sm-6 col-md-6 col-lg-6">
            <label> Job Type:
              <select class="custom-select" formControlName="jobTypeControl" (ngModelChange)="updateFilterValue($event)">
                <option *ngFor="let jobType of jobTypeObservable" [value]="jobType"> {{jobType.name}}</option>
              </select>
            </label>
        </div>
    
        <div *ngIf="jobsDataAvailable()" class="col-xs-6 col-sm-6 col-md-6 col-lg-6">
          <div class="has-text-centered">
            <pagination-controls (pageChange)="page = $event" class="my-pagination" directionLinks="true" maxSize="5"
                                 nextLabel="" previousLabel=""></pagination-controls>
          </div>
        </div>
      </div>
    
      <div *ngIf="jobsDataAvailable()">
        <div *ngFor="let job of (jobsObservable) | stringFilter: this.jobsForm.controls['jobTypeControl'].value  | paginate: { itemsPerPage: 10, currentPage: page }" class="row" style="margin-top: 10px">
          <div class="col-xs-12 col-sm-12 col-md-12 col-lg-12">
            <div class="card">
              <div class="card-body">
                <h5 class="card-title">{{job.title}}</h5>
                <h6 class="card-subtitle mb-2 text-muted">{{job.city}}, {{job.state}}</h6>
                <p class="card-text">This text will be replaced by clearance value in future</p>
                <a class="btn btn-primary" href="https://bcmcllc.applytojob.com/apply/{{job.board_code}}">View and Apply</a>
              </div>
            </div>
          </div>
        </div>
      </div> <!-- End of ngIf-->
      </form>
    
    </div>

Custom Filter:

     import {Pipe, PipeTransform} from "@angular/core";
        @Pipe({
          name: 'stringFilter'
        })
        export class StringFilterPipe implements PipeTransform
        {
          transform(value: string[], filterValue: any)
          {
            if (!filterValue || filterValue === '')
            {
              return value;
            }
            return value.filter(item => -1 < item.toLowerCase().indexOf(filterValue.toLowerCase()));
          }
        }
**JobsListComponent**
    import {Component, OnChanges, OnInit, SimpleChanges} from '@angular/core';
    import {JobsService} from './services/jobs.service';
    import {SERVER_API_URL} from '../../app.constants';
    import {Observable} from 'rxjs';
    import {Job} from './model/job';
    import {FormControl, FormGroup} from '@angular/forms';
    import {JobType} from './model/job-type';
    
    @Component({
      selector: 'app-jobs-list',
      templateUrl: './jobs-list.component.html',
      styleUrls: ['./jobs-list.component.css']
    })
    
    export class JobsListComponent implements OnInit
    {
      jobsObservable: Observable<Job[]>;
      jobTypeObservable: Observable<JobType[]>;
      page: number = 1;
    
      jobsForm = new FormGroup({
        jobTypeControl: new FormControl({value: '', disabled: false})
      });
    
      //this.form.controls['jobTypeControl'].value
      //jobsForm.get('jobTypeControl').value
      constructor(private jobsService: JobsService) {
      }
    
      ngOnInit()
      {
        this.getAllJobTypes();
        this.getAllJobs();
      }
    
      getAllJobs() {
        let url = SERVER_API_URL + 'jobs/all';
    
        this.jobsService.getAllJobs(url).subscribe(
          data => {
            // @ts-ignore
            this.jobsObservable = data;
          },
          error => console.error('Failed to retrieve values from backend, error=> ' + error),
          () => console.log('Jobs retrieved from backend'));
        return this.jobsObservable;
      }
    
      getAllJobTypes() {
        let url = SERVER_API_URL + 'jobtypes/all';
    
        this.jobsService.getAllJobTypes(url).subscribe(
          data => {
            // @ts-ignore
            this.jobTypeObservable = data;
          },
          error => console.error('Failed to retrieve values from backend, error=> ' + error),
          () => console.log('Job Types retrieved from backend'));
        return this.jobTypeObservable;
      }
    
      jobsDataAvailable() {
        return this.jobsObservable !== undefined;
      }
    
    
      updateFilterValue(event)
      {
        console.log("Emitted Value "+event);
      }
    }

3 Answers 3

5

Two things.

First: In your options you have

    <option *ngFor="let jobType of jobTypeObservable" [value]="jobType"> 
          {{jobType.name}}
    </option>

So, the value is an object of type jobType. You can use, eg. if your jobType has a property called "id" [value]=jobType.id

    <option *ngFor="let jobType of jobTypeObservable" [value]="jobType.id"> 
          {{jobType.name}}
    </option>

So, you received in your function the "id", not the whole object.

Second: In reactive Form, usually you subscribe to values changes -it's not used (changed)- then, after create the form

    jobsForm.get('jobTypeControl').valueChanges.subscribe(value=>
       { //here you has the value of jobTypeControl
          console.log(value)
       }
    )
Sign up to request clarification or add additional context in comments.

2 Comments

What if I want to store entire jobType object as value, and stilll don't want to get [Object, Object]?
Got it! I need to use [ngValue] instead of [value].
3

To whoever ends up here and wants the whole object as the value, you need to use [ngValue] instead of [value].

Credits to @Shrinivas whose comment saved me a lot of time.

1 Comment

Is this difference now with typed forms? I am sure it worked with just [value] before 🤔
0

In my case I had following form field (for textarea):

comment: [{
  value: this.form.comment
}, Validators.maxLength(300)],

and that resulted in [object Object] being seen in the UI.

I didn't investigate why the following change fixed problem in my case, but what I did (and it helped) was adding disabled property, like this:

comment: [{
  value: this.form.comment,
  disabled: false
}, Validators.maxLength(300)],

I just saw it's done this way in some example. Of course it can be conditional, for example:

disabled: this.form.comment?.length > 0 ? false : true

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.