Angular 2: обновить представление компонента из сервиса

#angular

#angular

Вопрос:

У меня есть компонент, который отображает список вариантов, которые извлекаются из сервиса, как вы можете видеть здесь.

 export class SellingMenuVarietiesComponent implements OnInit {
    varieties: Variety[];

    constructor(public sellingMenuService: SellingMenuService) { }

    ngOnInit(): void {        
        this.getVarietyList();
    }
    // Get Variety List
    getVarietyList(): void {
        this.sellingMenuService.getVarieties().subscribe(res => {
            this.varieties = res;
        });
    }    
}
  

У меня есть другой компонент, который удаляет разновидности, как показано здесь:

 export class SellingVarietyEditComponent implements OnInit {
    constructor(private sellingMenuService: SellingMenuService) { }

    // Remove variety
    removeVariety(id: number) {        
        this.sellingMenuService.removeVariety(id).subscribe(res => {
            this.sellingMenuService.getVarieties();
        });        
    }
}
  

В этом примере оба компонента видны на странице одновременно, поэтому при удалении разнообразия я хочу, чтобы список автоматически обновлялся и отражал это. В настоящее время variety будет успешно удален из базы данных, но останется в списке до тех пор, пока я не обновлю страницу. Обратите внимание, что в removeVariety() функции из SellingVarietyEditComponent я повторно вызываю getVarieties() метод из своего сервиса в попытке обновить список, но это не работает.

Что я делаю не так? Как я могу это сделать?

Вот соответствующие функции из этой службы:

 @Injectable()
export class SellingMenuService {
    // Get Variety List
    public getVarieties(): Observable<any> {
        return this.http.get(this.varietyList).map(response => {            
            return response.json();
        }, (error: any) => {
            console.log(error);
        });
    }
    // Remove Variety
    public removeVariety(varietyId: any): Observable<any> {
        return this.http.get(this.removeVarietyUrl   varietyId).map(response => {
            return response;
        }, (error: any) => {
            console.log(error);
        });
    }
}
  

Редактировать:

Попытка решения EventEmitter:

В SellingMenuService я добавил этот код (обратите внимание, что я добавил this.updateVarietyList.emit(null); в getVarieties() ):

 @Output() updateVarietyList: EventEmitter<any> = new EventEmitter();

// Get Variety List
public getVarieties(): Observable<any> {
    return this.http.get(this.varietyList).map(response => {            
        this.updateVarietyList.emit(null);
        return response.json();
    }, (error: any) => {
        console.log(error);
        // TODO: implement error handling here.
    });
}
  

В SellingVarietyEditComponent моя кнопка удаления выглядит следующим образом:

 <a class="remove-button" (click)="removeVariety(varietyId)" (updateVarietyList)="onVarietyListUpdate($event)" >Remove</a> 
  

И, наконец, в SellingMenuVarietiesComponent я добавил это:

 onVarietyListUpdate() {
    console.log('test');
    this.getVarietyList();
}
  

Однако этот код не работает. Я не получаю никаких ошибок, но onVarietyListUpdate() метод никогда не выполняется. Я вообще на правильном пути? Как я могу это исправить? Найденный мной пример сбивает с толку, и у меня возникают проблемы с применением их к моему коду.

Ответ №1:

Я только что понял, что у вас разные компоненты. Таким образом, решения на самом деле меняются. Но я все еще сохранил старое решение, которое дает вам лучшее представление о том, как справиться с материалом, если вам понадобится в будущем.

НОВОЕ РЕШЕНИЕ

Вы можете создать component-interactions.service.ts, в котором

 updateVarieties = new Subject();
updateVarieties$ = this.updateVarieties.asObservable();
getVarieties(){
this.updateVarieties.next();
}
  

Здесь,

 export class SellingMenuVarietiesComponent implements OnInit {
    varieties: Variety[];

    constructor(private ciService:ComponentInteractionService, public sellingMenuService: SellingMenuService) { }

    ngOnInit(): void {        
        this.ciService.updateVarieties$.subscribe(()=> {
            this.getVarieyList();
      });
  this.getVarietyList();
    }
    // Get Variety List
    getVarietyList(): void {
        this.sellingMenuService.getVarieties().subscribe(res => {
            this.varieties = res;
        });
    }    
}
  

В редактируемом компоненте,

 export class SellingVarietyEditComponent implements OnInit {
    constructor(private ciService:ComponentInteractionService, private sellingMenuService: SellingMenuService) { }

    // Remove variety
    removeVariety(id: number) {        
        this.sellingMenuService.removeVariety(id).subscribe(res => {
            this.ciService.getVarieties();
        });        
    }
}
  

СТАРОЕ РЕШЕНИЕ: ЕСЛИ ОДИН КОМПОНЕНТ ОБРАБАТЫВАЕТ РЕДАКТИРОВАНИЕ И ПОКАЗЫВАЕТ

Дело в том, что вам нужно обновить пользовательский интерфейс новыми данными. Один из способов сделать это — вернуть обновленные варианты с ответом об успешном завершении из серверной части после удаления варианта.

Итак, я нажимаю на removeVariety API, выполняю операцию удаления с идентификатором, а вы делаете что-то вроде varieties.GetAll() в серверной части и отправляете обновленные varieties в успешном ответе. И затем вы просто делаете

 this.varieties = res;
  

Для интерфейса это просто сделать.

Другой подход заключается в сохранении идентификатора в переменной, прежде чем вы нажмете на delete API. Теперь у вас есть идентификатор, который вы удаляете, вы нажимаете на API, он успешен, а затем вы делаете

 export class SellingVarietyEditComponent implements OnInit {
constructor(private sellingMenuService: SellingMenuService) { }

// Remove variety
removeVariety(id: number) {
    let deleteItemId = id; 

    this.sellingMenuService.removeVariety(id).subscribe(res => {
         if(res.status=="SUCCESS"){ /* check if it was successful.(Good practice to include that in API Response*/
         this.deleteItemById(deleteItemId);
       }
     });        
    }

deleteItemById(id:number){
this.varieties.forEach((value)=> {
  if(value.varietyId==id){
      let index = this.varieties.indexOf(value);
      if(index>-1){
         this.varieties.splice(index, 1);
      }
   }
 });
}
  

Я думаю, что не стоит снова вызывать getVarieties. В вашем коде причина, по которой он не работает, заключается в том, что он возвращает вам наблюдаемое, а вы не подписываетесь на это и не обновляете массив varieties. Если вы все еще хотите вызвать get API. Вы можете сделать

  this.getVarietyList(); 
  

вместо

 this.sellingService.getVarieties();
  

и снова сделайте эту функцию в компоненте редактирования такой же, как у вас в другом компоненте.

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

1. Что мне нужно импортировать, чтобы использовать Subject?

2. Неважно, я использовал import { Subject } из ‘rxjs / Subject’;

3. Сработало ли это? Примите это, если это решение работает для вас!

4. Это сработало, спасибо! Хотя я не совсем понимаю это, не могли бы вы объяснить, как это работает?

5. Итак, вы создаете observable, который публикует данные, на которые вы подписываетесь и получаете данные. Вы вызываете метод, из которого хотите отправить данные, который вызывает next() для отправки этих данных и публикует эти данные, на которые вы подписываетесь и получаете данные. Параметр в next() в идеале содержит данные, но в вашем случае нам не нужен никакой обмен данными. Поэтому в идеале это getVarieties (данные), а затем next (данные). И вы получите эти данные в виде подписки. А затем используйте эти данные.

Ответ №2:

Вы могли бы использовать EventEmitter в своем SellingMenuService , чтобы выдавать событие при variety удалении / обновлении. Прослушайте это событие в SellingMenuVarietiesComponent и соответствующим образом обновите свой массив

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

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