简体   繁体   中英

Calling an angular service from a child/sibling component?

I have a Select component which displays a list of students. When you select a student, I call a service to get some data and I navigate to a dashboard component where you can view all the data which is broken up into child components. I was using @Input() to pass data from dashboard to the child components, but the problem I am facing is that the user can also get to a specific component page without having to go through select, so in this case, the service would not be called. What I ended up doing was having a shared variable in my service to hold the data. In each component, I check if this variable is null. If it is null, I call the service, if not, I just return the data I already have. Here is code:

service.ts

@Injectable()
export class Service {


  private studentDataStore = new BehaviorSubject<Student>(null);
  public studentData$ = this.studentDataStore .asObservable();
  selectedStudentId: number;
  studentData: Student = null;
  constructor(private _httpClient: HttpClient) { }

  loadStudentDetails(studentId) {
    this.studentData= null;
    const headers = new HttpHeaders();
    headers.set('Content-Type', 'application/json');

    return this._httpClient.get<Student>('/students/' + studentId, { headers: headers }).toPromise().then(res => {
      this.studentData= res;

      this.studentDataStore .next(res);
    });
  }
}

Notice at the top I declared studentData to share my data among my components.

Select component

export class SelectComponent implements OnInit {


  constructor(private _service: Service, private _router: Router) { }

  ngOnInit() {}

  selectStudent(selectedStudent) {
    this._service.loadStudentDetails(selectedStudent.Id).then(x => {
      this._router.navigate(['/students', selectedStudent.Id]);
    });
  }

}

the above will navigate to something like http://localhost:4200/students/3 which will display the Dashboard component:

export class DashboardComponent implements OnInit {

  constructor(public _service: Service, private _route: ActivatedRoute) { }

  ngOnInit() {

    const Id= this._route.snapshot.params['Id'];
    if (!this._service.studentData) {
      this._service.loadStudentDetails(Id);
    }
  }
}

So by doing the above, the user can get to the dashboard for a student by either going through the select or directly going to the the dashboard for a specific student . Because of the above, I am not subscribing or using aysnc anywhere. Is there a proper way to handle the scenario above?

Your approach is perfectly fine for some cases.

Basically what you do is use service to store data, which means use service as a store. In this case it stores student details.

Now imagine that your application grows so big, that you have hundreds of such cases, and you use a lot of different services, to store a lot of different data. Nothing breaks yet, but you lose control of your application state. You no longer know what data you have, when you have it, and how you have obtained it.

For such cases @ngrx/store comes to the rescue. Basic idea is to take the data out of components/services and store it somewhere where components and services both can access it. Thus you divide the application logic and data management to make the state of the application more maintainable.

Here is a plunker to demonstrate basic idea based on your provided details(look at src/app.ts ): plunker

Also some good reading material can be found here: https://gist.github.com/btroncone/a6e4347326749f938510

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM