Избегайте изменения наблюдаемого источника

#angular #rxjs #angular2-observables #mutability

Вопрос:

Я создаю приложение Angular, в котором у меня следующая ситуация: компонент подписывается на Observable услугу value on и отображает данные с помощью async pipe . Он вводит значения во вложенный компонент редактирования, который, в свою очередь, отображает a reactive form .

Моя проблема в том, что, похоже, отправка значения из формы напрямую изменяет наблюдаемый источник ( BehaviorSubject ). Есть какой-нибудь способ избежать этого? Код приведен ниже, хотя имена изменены.

data.service.ts:

 export class DataService {
    private dataSource = new BehaviorSubject<MyData[]>(null);
    private data$ = this.dataSource.asObservable();

    getDataObservable(): Observable<MyData> {
        // fetch data from api, subscribe to it
        // and call dataSource.next() on subscription result
    }
    
    update(data: MyData) {
        // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        // dataSource.value IS ALREADY MUTATED HERE
        // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    }
}
 

список.компонент.ts:

 export class ListComponent implements OnInit {
    @Input() userId: string;
    data$: Observable<MyData[]>;
    dataInEditing: MyData;

    constructor(private dataService: DataService ) { }

    ngOnInit() {
        this.data$ = this.dataService.getDataObservable();
    }

    onDataSelected(data: MyData): void {
        this.dataInEditing = data;
    }

    onDataEdited(data: MyData): void {
        this.dataService.update(data);
        this.dataInEditing = null;
    }
}
 

list.component.html:

 <div *ngIf="data$ | async as data; else loading">
    <data-table</data-table> <!--inputs/outputs ommited-->
    
    <data-edit
        *ngIf="!!dataInEditing "
        [data]="dataInEditing "
        (dataChangedEvent)="onDataEdited($event)"></data-edit>
</div>
<ng-template #loading>Loading...</ng-template>
 

данные-редактировать.компонент.ts

 export class DataEditComponent implements OnChanges {
    @Input()  data: MyData;
    @Output() dataChangedEvent = new EventEmitter<MyData>();
    form: FormGroup;

    constructor(private fb: FormBuilder) { }
    ngOnChanges(changes: SimpleChanges): void {
        this.form = this.createForm();  
    }

    updateData(): void { // onSubmit
        if (this.form.valid) {
            // update data
            this.dataChangedEvent.emit(this.data);
        }
    }

    private createForm(): FormGroup {
        return this.fb.group({/**/});
    }
}
 

Чтобы повторить: DataService.dataSource.value изменились ли элементы еще до того, как я попробую сделать это вручную DataService.update() . Это говорит мне о том, что компоненты получают ту же ссылку, которая BehaviourSubject сохраняется. Должен ли я map перенести наблюдаемые данные в совершенно новый массив или что-то в этом роде? Или я подхожу к этому совершенно неправильно?

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

1. Действительно, объект BehaviorSubject дает вам точный элемент, а не копию. Вы не должны изменять его содержание. Вы можете использовать оператор распространения в операторе карты, как вы предложили.