0
votes

I have a problem with iteration of list items inside select.

What I'm trying to show are list items in child component

<li
  class="list-group-item clearfix" 
  (click)="onSelected()">
    <div class="pull-left">
      <h4 class="list-group-item-heading">{{project.name}}</h4>
    </div>
</li>

inside of select option

<div class="form-group">
  <select class="form-control" id="projects">
    <option *ngFor="let project of projects">
      <app-project-item
          *ngFor="let projectElement of projects"
          [project]="projectElement"
      ></app-project-item>
    </option>
  </select>
</div>

but dropdown shows both item.

It's important that I have to iterate list items from child component.

What's wrong? Stackblitz

2
It is because you iterate over the same collection in both loopsochs.tobi
An option is supposed to contain text, not HTML. developer.mozilla.org/en-US/docs/Web/HTML/Element/optionJB Nizet
why do you iterate the same collection twice with a nested for?Jota.Toledo

2 Answers

1
votes

You are looping over each project:

<app-project-item *ngFor="let projectElement of projects"
 [project]="projectElement"></app-project-item>

Which will cause each option to have all projects.

I'm not sure why you are doing it like this instead of just:

<option *ngFor="let project of projects">{{project.someLabel}}</option>
0
votes

@Corry, the last StackBitz that you have put is a example of comunicate parent and children via service: https://angular.io/guide/component-interaction#parent-and-children-communicate-via-a-service

So, your projectlist.component.html can be like

<select #project (change)="changeProject(project.value)">
  <option *ngFor="let projectElement of projects"
          [value]="projectElement.id">{{projectElement.name}}</option>
</select>

See that if the select change, we call the function changeProject as argument the "id" of the project selected

And in projectlist.component.ts

ngOnInit() {
    this.projects = this.projectService.getProjects();
    //See that this.projectService.getProject it's NOT an observable
    //just the elements. If this function was an observable 
    // we must subscribe to it

    //At first call the function with the first element
    this.changeProject(this.projects[0].id);
}
changeProject(value:any)
{
   //"emit" a new value in the observable of the service
   this.projectService.projectSelected.emit(this.projects.find(d=>d.id==value));
}

Anyway, it's a "bizarro" code. If you want to have two relationated select (and allways if the elements are not many, you can simply

export class ProjectsComponent implements OnInit {

  selectedProject: Project;
  projects:Project[];
  constructor(private projectService: ProjectService) { }

  ngOnInit() {

    this.projects = this.projectService.getProjects();
    this.selectedProject=this.projects[0];
  }
}

And your ProjectsComponent .html like

      <form>
        <select name="project" [(ngModel)]="selectedProject">
          <option *ngFor="let projectElement of projects"
              [ngValue]="projectElement">{{projectElement.name}}</option>
        </select>
        <select >
          <option *ngFor="let task of selectedProject?.tasks">{{ task.name }}
          </option>
        </select>
      </form>