0

I have a simple HTML list which I would like to populate using Angular, but for some reason it does not work. The console.log("getUserCollection() Data: ", data); prints out an array, which is ok, but console.log("getUser() Data: ", data); prints out an empty object, which is probably because the list is not populated. How do I fix this? P.S Should I add the async pipe in the code?

My Users.component.ts:

import { Component, OnInit } from '@angular/core';
import { AviorBackendService } from '../services/avior-backend.service';
import { UserCollection } from '../models/user-collection.model';
import { User } from '../models/user.model';

@Component({
  selector: 'app-users',
  templateUrl: './users.component.html',
  styleUrls: ['./users.component.css']
})
export class UsersComponent implements OnInit {

  selectedItem: string;

  users: UserCollection;
  user: User;
  firstname: string;
  selectedUser: User;

  constructor(private aviorBackend: AviorBackendService) { }

  ngOnInit() {
      this.aviorBackend.getUserCollection().subscribe(data => {
      // tslint:disable-next-line: no-string-literal
      this.users = data['firstname'];
      console.log(this.users);
      console.log("getUserCollection() Data: ", data);
    });
  }

  clickItem(firstname) {
      this.aviorBackend.getUser(firstname).subscribe(data => {
      // tslint:disable-next-line: no-string-literal
      this.selectedUser = data['user'];
      console.log(this.selectedUser);
      console.log("getUser() Data: ", data);
    });
  }
}

My Users.component.html:

<div class="list-area">

  <div class="col-lg-12">

    <p class="list-header">Element overview</p>

    <div class="form-group">
      <label for="filter" class="lb-sm">Filter</label>
      <input type="text" class="form-control input-sm" name="filter" id="filter">
    </div>

   <select size="20" multiple class="form-control" id="elementlist" [(ngModel)]="selectedItem" (click)="clickItem(firstname)">
      <!-- maybe add | async pipe -->
    <option *ngFor="let user of users">
        {{user?.lastName}}, {{user?.firstName}}
      </option>
    </select>

  </div>

</div>

<div class="content-area">

  <div class="col-lg-12" *ngIf="selectedUser?.id">

  <p>Element contents {{selectedUser?.id}}</p>

  <div class="col-lg-12">
    <div class="form-group">
      <label for="firstName" class="lb-sm">First Name</label>
      <input type="text" class="form-control input-sm" name="firstName" id="firstName" [(ngModel)]="selectedUser.firstName">
    </div>
  </div>

  </div>

</div>


Update My getUser() method:

// Get user
  getUser(firstname: string): Observable<any> {
    const API_URL = `${SERVICE_URL}user/firstname/${firstname}`;
    return this.client.get(API_URL, this.httpOptions).pipe(
      map((res: Response) => {
        return res || {};
      }),
      catchError(this.handleError())
    );
  }

UPDATE 2

My user.model.ts:

import { Role } from './role';

// was class and not interface!
export interface User {
    id?: number;
    mandator?: number;
    loginId?: string;
    lastName?: string;
    firstName?: string;
    password?: string;
    eMail?: string;
    group: string;
    role: Role;
    active?: boolean;
    token?: string;
}

My user-collection.model.ts:

import { User } from './user.model';

export interface UserCollection {

    user: User[];

}

8
  • 2
    If the data in the clickItem(firstname) method is an empty object, there is some problem with the aviorBackend.getUser() method. Commented Dec 2, 2019 at 9:27
  • 1
    check your chrome network tab and see if the api call has proper response Commented Dec 2, 2019 at 9:28
  • @JoelJoseph the network tab shows the proper response Commented Dec 2, 2019 at 9:46
  • @SunnyParekh I've added the getUser() method to the question Commented Dec 2, 2019 at 9:47
  • Can you provide a example of what the 'users' array looks like ? Commented Dec 2, 2019 at 10:16

4 Answers 4

1

Change in your getUserColletion().subscribe() service call:

this.users = data['firstname'];

to

this.users = data;

Also update your User interface:

export interface User {
    _id: string;
    loginId: string;
    lastname: string;
    firstname: string;
    password: string;
    eMail: string;
    group?: string;
    role?: Role;
    active?: boolean;
    token?: string;
}

This change is necessary, because it reflects the backend model which you get as response. Otherwise you can put an extra map() to map it to your frontend interface model

And then update your model in the .html accordingly to the names like e.g.:

{{user.lastname}}, {{user.firstname}}

And also update your click handler to (click)="clickItem(user.firstname)":

<select size="20" multiple class="form-control" id="elementlist" [(ngModel)]="selectedItem">
      <!-- maybe add | async pipe -->
    <option *ngFor="let user of users" (click)="clickItem(user.firstname)">
        {{user?.lastName}}, {{user?.firstName}}
      </option>
</select>
Sign up to request clarification or add additional context in comments.

17 Comments

It shows a comma for every item in the array now. And I also get two errors:Property 'user' is missing in type 'any[]' but required in type 'UserCollection'. and Property 'firstname' does not exist on type 'User'. Did you mean 'firstName'?
Could you provide the interface for the UserCollection?
Property 'user' is missing in type 'User[]' but required in type 'UserCollection'. :/
But it works! Now only the getUser() returns undefined
Ah okay, change the property in your component from users: UserCollection to users: User[];. This should do the trick
|
1
<select size="20" multiple class="form-control" id="elementlist" [(ngModel)]="selectedItem" (click)="clickItem(firstname)">
      <!-- maybe add | async pipe -->
    <option *ngFor="let user of users">
        {{user?.lastName}}, {{user?.firstName}}
      </option>
    </select>

I don't think firstname is defined when calling clickItem on click.

Try to remove the firstname param and access selectedItem of your component instead.

clickItem() {
      this.aviorBackend.getUser(selectedItem).subscribe(data => {
      // tslint:disable-next-line: no-string-literal
      this.selectedUser = data['user'];
      console.log(this.selectedUser);
      console.log("getUser() Data: ", data);
    });

Edit:

You can checkout a more reactive example here: https://stackblitz.com/edit/angular-scdzjq Maybe a new approach like this would help you.

3 Comments

the list does not populate in the first place.. There is something wrong with my code but I can't tell where it is exactly.
I added an example for a more reactive approach in my answer. Maybe it will help you.
Hmm this would require me to rewrite the code anew. I will take it as a last resort, even though the code quality is better (async is always superior in my books)
0

Try replacing this

this.users = data['firstname'];

with this one

this.users = data;

1 Comment

Property 'user' is missing in type 'User[]' but required in type 'UserCollection'.. It's because I have import { User } from './user.model'; export interface UserCollection { user: User[]; } in my user-collection.model.ts
-1

Try adding a name attribute to the select element, example name="userSelect"

UPDATE: Based on your example of what the 'users' array looks like. You should be using firstname not firstName, same with lastname and not lastName

you should also just say this.users = data; where data is a array of the user model

4 Comments

apparently it did nothing :/
and removing the click event still does not change anything ?
removing the click event does nothing as well
I tried changing it to firstname after seeing the array, but it somewhy still doesn't work

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.