import * as clone from 'clone'; import { Observable } from 'rxjs'; import { Command, Property, ReadOnlyProperty } from '../../../WebRx'; import { BaseViewModel } from '../../React'; export class InlineEditViewModel extends BaseViewModel { public static displayName = 'InlineEditViewModel'; public readonly value: Property; public readonly editValue: Property; public readonly isEditing: ReadOnlyProperty; public readonly hasSavingError: ReadOnlyProperty; public readonly edit: Command; public readonly save: Command; public readonly cancel: Command; public readonly setError: Command; constructor( value?: Property | T, protected readonly onSave: ( value: T, viewModel: InlineEditViewModel, ) => T | Observable = x => x, ) { super(); if (this.wx.isProperty(value)) { this.value = value; } else { this.value = this.wx.property(value); } this.editValue = this.wx.property(); this.edit = this.wx.command(() => { return clone(this.value.value); }); this.save = this.wx.command(() => { return Observable.defer(() => this.wx.asObservable(this.onSave(this.editValue.value!, this)), ).do({ error: e => { this.alertForError(e, 'Unable to Save'); }, }); }); this.cancel = this.wx.command( // prevent cancel from being executed while we are waiting for save to respond this.save.isExecutingObservable.map(x => x === false), // this is intentionally returning undefined to 'reset' the editValue () => undefined, ); this.setError = this.wx.command(); this.addSubscription( Observable.merge( this.edit.results, this.save.results.map(x => undefined), this.cancel.results, ).subscribe(x => { this.editValue.value = x; }), ); this.isEditing = Observable.merge( this.edit.results.map(() => true), this.save.results.map(() => false), this.cancel.results.map(() => false), ).toProperty(false); this.hasSavingError = Observable.merge( this.save.results.map(() => false), this.save.thrownErrors.map(() => true), this.cancel.results.map(() => false), ) .startWith(false) .combineLatest( this.setError.results.startWith(false), (hasError, hasManualError) => hasManualError || hasError, ) .toProperty(false); this.addSubscription( this.save.results.subscribe(x => { this.value.value = x; }), ); } }