Angular 如何基于用户单击父组件中的对象在共享服务的子组件中显示数据?

Angular 如何基于用户单击父组件中的对象在共享服务的子组件中显示数据?,angular,Angular,首先,我将从概述开始,以便更容易理解我的问题 我有一个projects页面,其中列出了使用Spring-Boot-RESTcontroller和数据库从后端获取的多个project对象。每个项目可以有多个模块对象 这里是Project.ts: import { Module } from './module'; export class Project { projectId: number; name: string; description: string;

首先,我将从概述开始,以便更容易理解我的问题

我有一个
projects
页面,其中列出了使用Spring-Boot-RESTcontroller和数据库从后端获取的多个
project
对象。每个
项目
可以有多个
模块
对象

这里是Project.ts

import { Module } from './module';

export class Project {

    projectId: number;
    name: string;
    description: string;
    module: Module[];

}
import { Project } from './project';
import { TestCase } from './test-case';

export class Module {

    moduleId: number;
    project: Project;
    name: string;
    createdBy: string;
    referenceDocument: string;
    testCase: TestCase[];

}
和Module.ts

import { Module } from './module';

export class Project {

    projectId: number;
    name: string;
    description: string;
    module: Module[];

}
import { Project } from './project';
import { TestCase } from './test-case';

export class Module {

    moduleId: number;
    project: Project;
    name: string;
    createdBy: string;
    referenceDocument: string;
    testCase: TestCase[];

}
所以,我希望实体结构是清晰的

现在,用户可以单击“项目”页面上的表行。单击将获取
项目
对象并将其发送到另一个组件(
搜索模块
组件),该组件用于搜索与单击的
项目
相关的
模块。用户单击项目后,URL应更改为
searchModules
HTML模板,其中将显示与该项目相关的所有模块

以下是组件及其HTML模板:

搜索模块.component.ts

import { Component, OnInit, Input } from '@angular/core';
import { Module } from '../module';
import { Project } from '../project';
import { ProjectService } from '../project.service';
import { HttpClient } from '@angular/common/http';

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

  projectModules: Module[];
  errorMessage: any;
  public project: Project;

  constructor(private projectService: ProjectService, private http: HttpClient) { }

  ngOnInit() {
  }

  receiveAndSetClickedProject(project: Project) {
    console.log("In Search Component Module: ", this.project);
    this.project = project;
  }

  findModulesForProject(): void {
    console.log("Finding modules for Project: ", this.project, " in SearchModules...")
    this.projectService.findModulesByProject(this.project).subscribe(responseData => {
      this.projectModules = responseData;
      console.log(this.projectModules);
      if (this.projectModules.length == 0)
        alert("This project doesn't have a module yet.")
    }, error => 
    {
      this.errorMessage = error;
      window.alert(this.errorMessage);
    })
  }

}
<div>
  <br />
  <div class="card" (click)="findModulesForProject()">
    <div class="card-header">
      <h4 *ngFor="let module of projectModules"> Modules in Project: {{module.project.name}}</h4>
      <div class="col-md-7 float-right"></div>
      <a [routerLink]="['/modulesForm']" routerLinkActive="router-link-active" class="btn btn-outline-primary"
        style="float: right;"> + New Module</a>
    </div>
    <div class="card-body">
      <table class="table table-bordered table-hover">
        <thead class="thead-dark">
          <tr>
            <th scope="col">Module ID</th>
            <th scope="col">Module Name</th>
            <th scope="col">Project</th>
            <th scope="col">Reference Document</th>
            <th scope="col">Created By</th>
          </tr>
        </thead>
        <tbody>
          <tr *ngFor="let module of projectModules">
            <td>{{module.moduleId}}</td>
            <td>{{module.name}}</td>
            <td>{{module.project.name}}</td>
            <td>{{module.referenceDocument}}</td>
            <td>{{module.createdBy}}</td>
          </tr>
        </tbody>
      </table>
    </div>
  </div>

  <br />
  <br />
</div>
<app-project (sendProject)="receiveAndSetClickedProject($event)"></app-project>
搜索模块.component.html

<div>
  <br />
  <div class="card" (click)="findModulesForProject()">
    <div class="card-header">
      <h4 *ngFor="let module of projectModules"> Modules in Project: {{module.project.name}}</h4>
      <div class="col-md-7 float-right"></div>
      <a [routerLink]="['/modulesForm']" routerLinkActive="router-link-active" class="btn btn-outline-primary"
        style="float: right;"> + New Module</a>
    </div>
    <div class="card-body">
      <table class="table table-bordered table-hover">
        <thead class="thead-dark">
          <tr>
            <th scope="col">Module ID</th>
            <th scope="col">Module Name</th>
            <th scope="col">Project</th>
            <th scope="col">Reference Document</th>
            <th scope="col">Created By</th>
          </tr>
        </thead>
        <tbody>
          <tr *ngFor="let module of projectModules">
            <td>{{module.moduleId}}</td>
            <td>{{module.name}}</td>
            <td>{{module.project.name}}</td>
            <td>{{module.referenceDocument}}</td>
            <td>{{module.createdBy}}</td>
          </tr>
        </tbody>
      </table>
    </div>
  </div>

  <br />
  <br />
</div>
<app-project (sendProject)="receiveAndSetClickedProject($event)"></app-project>
import { Component, OnInit, Output, EventEmitter } from '@angular/core';
import { Project } from '../project';
import { Router } from '@angular/router';
import { ProjectService } from '../project.service';

import { HttpClient } from '@angular/common/http';
import { Module } from '../module';

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

  project: Project = new Project();
  listOfAllProjects: Project[];
  listOfModulesByProject: Module[];
  errorMessage: any;

  constructor(private router: Router, private projectService: ProjectService, private http: HttpClient) { }

  ngOnInit() {
    this.projectService.findAllProjects().subscribe(responseData => 
      {
        this.listOfAllProjects = responseData;
      }, error => 
      {
        this.errorMessage = error;
        window.alert(this.errorMessage);
      })
  }

  updateProject(): void {
    // this should call ProjectFormUpdateComponent's actual updateProject() method
  }

  deleteProject(project:Project): void {
    // Shouldn't use this.project here. In that case it will refer to the null object created in this file.
    // Without this, it refers to the object received from the HTML element.

    this.projectService.deleteProject(project).subscribe(responseData => {
      alert("Project ID: " + project.projectId + " has been deleted successfully.");
    })
  }

  @Output()
  sendProject:EventEmitter<Project> = new EventEmitter<Project>();     // creates the emitter to emit the clicked project.

  onSelectProject(project: Project){
    console.log("In Project Component: ", project);
    this.sendProject.emit(project);                          // emits the project to the search-modules component
    this.router.navigate(['/moduleSearch']);                 //redirects url to search-modules component
  }

}


项目中的模块:{{module.Project.name} 。它有点粗糙,因为我以前从未玩过

我已经尽可能清楚地说明了我的问题,但如果仍然不清楚,请要求进一步澄清


非常感谢您阅读这个大问题。:)

我试着给你举个StackBlitz的例子。希望这能澄清一点问题。它仍然非常简单:)

此外,我在这里添加了我的解决方案的主要部分,作为注释中建议的代码片段

  • 使用附加参数为searchModule组件添加特定路由
  • 在projectList组件中,向每个项目条目添加routerLink,并将实际的projectId传递给路由器

  • 当然,几分钟后就可以在StackBlitz上发布了……为什么你的
    重定向函数this.router.navigate(['/moduleSearch'])导航到moduleSearch时,可以将projectId作为参数传递。然后在模块搜索中,您可以从后端获取模块。如果我不使用
    this.router.navigate(['/moduleSearch']),这里就没有多余的emit了。@BhargavChudasama,数据不会传递到其他组件。如果您像这样导航:
    this.router.navigate(['/moduleSearch'],{queryParams:{projectId:project.Id})
    然后在
    搜索模块中
    组件将
    projectId
    作为查询参数。使用它来获取项目和项目模块。感谢StackBlitz。我想,多亏了你和其他人的帮助,我也许能够启动并运行我的项目。我会随时通知你的。请在你的答案中注明相关代码。您应该使用StackBlitz作为参考,而不是答案。@IftifarTaz只是在这里提供我的意见,但是,我认为完整的StackBlitz有助于像我这样的noobs更好地理解上下文和实现潜在解决方案的正确步骤。@IftifarTaz感谢您的建议。我用一些代码片段更改了答案。非常感谢您的帮助。我已经成功地解决了我的问题。事情完成得如此简单,但我们却采取了更复杂的方法,这真是不可思议。
    constructor( private route: ActivatedRoute ) {
        this.id = parseInt(this.route.snapshot.paramMap.get('projectId'));
    }