Могу ли я создать экземпляр службы для каждого загруженного компонента в Angular?

#angular #typescript #service

Вопрос:

У меня есть компонент edit-order.component со следующим именем ts-файла

 export class EditOrderComponent implements OnInit {

  constructor(private editOrderSrv: EditOrderService, private route: ActivatedRoute) { }

  ngOnInit(): void {
    this.editOrderSrv.getOrderById(this.route.snapshot.params.id);
  }
}

 

и в моем edit-order-service.service.ts у меня есть следующий код

 export class EditOrderService {
  order$: BehaviorSubject<any> = new BehaviorSubject(null);
  constructor(private http: HttpClient) { }

  getOrderById(id: string){
    this.http.get('url', {params: {id}}).subscribe(order => {
      this.order$.next(order);
    }, error => {console.error(error)});
  }
}
 

Клиент должен иметь возможность открывать более одного edit-order.component с разными id . В моем child.component я хочу подписаться на order$ подобное

 export class ChildComponent implements OnInit {
  order: any;
  constructor(private editOrderSrv: EditOrderService) { }

  ngOnInit(): void {
    this.editOrderSrv.order$.subscribe(order => {
      if(order) this.order = order;
    })
  }

}
 

Но поэтому у меня должны быть собственные экземпляры службы, чтобы каждый edit-order.component не перезаписывался order$ . Как бы я этого добился? Или это невозможно? А если это невозможно, что я могу сделать еще для достижения своей цели?

Комментарии:

1. Зачем использовать отдельный BehaviorSubject ? Вы можете просто вернуть наблюдаемое, возвращенное getOrderById() .

2. @rveerd На потом. У меня есть более одного дочернего компонента edit-order.component, и я должен хранить более одной переменной в службе для этого конкретного заказа. Вот почему мне нужны разные экземпляры, чтобы не перезаписывать переменные, чтобы я мог получить доступ к правильной переменной для соответствующего порядка.

3. Если вы используете угловую маршрутизацию, то вы можете использовать один и тот же компонент на основе идентификатора, а также один и тот же экземпляр службы. Текущая реализация кажется мне немного необычной.

4. @Invader Я не думаю, что вам следует хранить в сервисе данные, относящиеся к конкретным компонентам. Сохраните его в компоненте. Используйте службу только для «услуг», таких как получение данных из веб-сервиса.

5. Если вам действительно нужна услуга для каждого экземпляра компонента, вы можете сделать это с помощью поставщиков зависимостей .

Ответ №1:

Любопытно, почему бы вашей функции не

 getOrderById(id: string){
    return this.http.get('url', {params: {id}})
  }
 

А вы на что подписываетесь getOrderById ?

Вы можете передать(уловитель), если хотите

Обновление вы также можете использовать «кэш» в службе без использования массива субъекта, только массива объекта

   orders:any={}  //create an empty object where we store the result

  getOrderById(id: string){
    if (this.orders[id])
        return of(this.orders[id]

    return this.http.get('url', {params: {id}}).pipe(
      tap(res=>{
         this.orders[id]=res;
      })
    )
  }
 

Комментарии:

1. Я стараюсь свести к минимуму количество http-запросов, и мне нужен порядок в моих дочерних компонентах, поэтому я хотел вызвать функцию один раз, а затем всегда просто подписываться order$ на любой дочерний компонент, в котором мне нужен порядок, иначе я бы много раз вызывал функцию в разных дочерних компонентах. Я хотел как-то централизовать порядок. Я не совсем уверен, сколько http-запросов будет в порядке, поэтому я стараюсь делать все с как можно меньшим количеством запросов, а затем использовать данные во всем приложении.

2. Я обновляю ответ, чтобы использовать «кэш» или заказы с использованием pipe(tap)

3. @Eliseo Я также думал об этом решении, но предположим, что у вас есть 2 компонента с одинаковым идентификатором, и при изменении данных из первого компонента вы не получите уведомления во втором.

4. ::глюпы:: ты думаешь глубже меня, Это правда, в данном случае не сработает

Ответ №2:

Это действительно плохая идея-создавать разные экземпляры службы. Цель службы-быть однопользовательской, и именно так она разработана. Хороший способ использовать его-хранить объект «ключ-значение» для каждого наблюдаемого заказа. от родительских компонентов передайте this.route.snapshot.params.id дочерним компонентам в качестве входных данных. (Непроверенный код)

Обслуживание:

 export class EditOrderService {
   public orders$: { [orderid: string]: BehaviorSubject<any> } = {};

   constructor(private http: HttpClient) { }

   getOrderById(id: string): void {
      this.http.get('url', { params: { id } }).subscribe(order => {
         if (!this.orders$[id]) {
            this.orders$[id] = new BehaviorSubject<any>(null);
         }
         this.orders$[id].next(order);

      }, error => { console.error(error); });
   }
}
 

дочерний компонент:

 export class ChildComponent implements OnInit {
  order: any;
  @Input() orderId: any;
  constructor(private editOrderSrv: EditOrderService) { }

  ngOnInit(): void {
    this.editOrderSrv.orders$[orderId].subscribe(order => {
      if(order) this.order = order;
    })
  }

}
 

Комментарии:

1. Это хорошая идея, не думал об этом. Поэтому я просто создаю объект с идентификатором в качестве ключа для всех данных, которые я хочу сохранить для заказа. Я попробую, спасибо!

2. Это тот момент, о котором вы беспокоитесь, но вместо создания экземпляров службы вы создаете экземпляры объектов поведения.