Как правильно отслеживать изменение данных сервиса и отрисовывать их в компоненте?
Имеется компонент, который работает с сервисом TableService. При срабатывании клика на кнопке и вызове функции actionHandler() должен срабатывать соответствующий метод сервиса, который изменяет состояние programmers, который хранится в сервисе. Как правильно в компоненте Ангуляра отслеживается изменение состояния данных? Если заметите, что я где то тут что то неправильно написал - попрошу поправить, так как я совершенно новенький в ангуляре. Учу Ангуляр по документации
@Component({
selector: 'app-table',
templateUrl: './table.component.html',
styleUrls: ['./table.component.scss'],
providers: [
TableService
]
})
export class TableComponent {
displayedColumns: Array<String> = ['id', 'Firstname', 'Lastname', 'Middlename', 'Position', 'Date Of Birth', 'Active', 'operations'];
dataSource: Array<Programmer> = this.tableService.getData();
constructor(private bottomSheet: MatBottomSheet, private tableService: TableService) {
}
actionHandler(action: string, element?: Programmer): any {
if (action === ActionType.EDIT) {
console.log(element);
const options = new MatBottomSheetConfig();
options.data = {element};
return this.bottomSheet.open(PopupComponent, options);
}
if (action === ActionType.ADD) {
return this.bottomSheet.open(PopupComponent);
}
return;
}
getData(): void {
this.dataSource = this.tableService.getData();
}
remove(id: number): void {
this.tableService.remove(id);
this.getData();
}
}
TableService
@Injectable({
providedIn: 'root'
})
export class TableService {
private programmers: Programmer[] = [
{
id: 1,
firstName: 'Павел',
lastName: 'Петров',
middleName: 'Валериевич',
position: Position.JUNIOR,
dateOfBirth: 'Thu Mar 10 2022 00:00:00 GMT+0600 (Омск, стандартное время)',
active: true
},
{
id: 12,
firstName: 'Павел',
lastName: 'Петров',
middleName: 'Иванович',
position: Position.JUNIOR,
dateOfBirth: 'Thu Jul 16 1998 00:00:00 GMT+0700 (Омск, летнее время)',
active: true
},
{
id: 13,
firstName: 'Павел',
lastName: 'Петров',
middleName: 'Петрович',
position: Position.SENIOR,
dateOfBirth: '11/01/2001',
active: true
}
]
constructor() {
}
getData(): Array<Programmer> {
return this.programmers;
}
remove(id: number) {
this.programmers = this.programmers.filter(programmer => programmer.id !== id);
}
add(programmer: Programmer) {
this.programmers.push(programmer);
console.log('added new programmer', this.programmers);
}
edit(id: Programmer) {
this.programmers.map((el, index) => {
if (el.id === id.id) {
this.programmers[index] = id;
return;
}
return;
});
}
}
Ответы (1 шт):
Наиболее распространенный способ - это использовать observable из rxjs и пайп async.
data.service.ts
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
@Injectable()
export class DataService {
// приватное поле с данными, чтобы нельзя было изменить извне, хранит сами данные
private _arrayList = [];
// приватный объект Subject, он осуществляет подписку, также заблокирован от внешних изменений
private arrayList$ = new BehaviorSubject<number[]>([]);
// метод, который возвращает подписку как `Observable`. Знак доллара на конце показывает, что это Observable или Subject и на него можно подписаться.
public getArrayList$() {
return this.arrayList$.asObservable();
}
public addItem() {
// изменяем данные, которые у нас хранятся в сервисе
this._arrayList.push(Math.random());
// через метод next() передаем обновленное значение в Subject
this.arrayList$.next(this._arrayList);
}
public removeItem() {
// аналогично методу добавления
this._arrayList.shift();
this.arrayList$.next(this._arrayList);
}
}
app.component.ts
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
providers: [DataService],
})
export class AppComponent implements OnInit {
// объявляем поле с типом Subject
array$: Observable<number[]>;
constructor(private readonly dataService: DataService) {}
ngOnInit() {
// задаем значение из сервиса, передаем его как Observable.
this.array$ = this.dataService.getArrayList$();
}
// тут просто вызываем методы сервиса
addItem() {
this.dataService.addItem();
}
removeItem() {
this.dataService.removeItem();
}
}
app.html
<button (click)="addItem()">+</button>
<button (click)="removeItem()">-</button>
<!-- Добавлем данные и через async-pipe подписываемся-->
<!-- Для удобства, полученные данные помещаем в переменную шаблона - array-->
<ng-container *ngIf="array$ | async; let array">
<!-- Тут уже используем данные из сервиса, обращаясь к array -->
<div *ngFor="let item of array">{{ item }}</div>
</ng-container>
В данном случае получаем следующие приемущества:
- Данные изолированны от внешнего воздействия напрямую
- Подписка и отписка на данные происходит сама, за счет async-пайпа
Подробнее можно почитать тут, и тут, и тут
Пример на stackblitz