// IDL class hint (e.g. "aou")
@Input() idlClass: string;
- recId: any;
-
- // IDL record we are editing
- record: IdlObject;
-
// Permissions extracted from the permacrud defs in the IDL
// for the current IDL class
modePerms: {[mode: string]: string};
// Display within a modal dialog window or inline in the page.
@Input() displayMode: 'dialog' | 'inline' = 'dialog';
+ // Hide the top 'Record Editor: ...' banner. Primarily useful
+ // for displayMode === 'inline'
+ @Input() hideBanner: boolean;
+
// Emit the modified object when the save action completes.
- @Output() onSave$ = new EventEmitter<IdlObject>();
+ @Output() recordSaved = new EventEmitter<IdlObject>();
// Emit the original object when the save action is canceled.
- @Output() onCancel$ = new EventEmitter<IdlObject>();
+ @Output() recordCanceled = new EventEmitter<IdlObject>();
// Emit an error message when the save action fails.
- @Output() onError$ = new EventEmitter<string>();
+ @Output() recordError = new EventEmitter<string>();
@ViewChild('translator') private translator: TranslateComponent;
@ViewChild('successStr') successStr: StringComponent;
// 'view' for viewing an existing record without editing
@Input() mode: 'create' | 'update' | 'view' = 'create';
- // Record ID to view/update. Value is dynamic. Records are not
- // fetched until .open() is called.
+ // recordId and record getters and setters.
+ // Note that setting the this.recordId to NULL does not clear the
+ // current value of this.record and vice versa. Only viable data
+ // is actionable. This allows the caller to use both @Input()'s
+ // without each clobbering the other.
+
+ // Record ID to view/update.
+ _recordId: any = null;
@Input() set recordId(id: any) {
- if (id) { this.recId = id; }
+ if (id) {
+ if (id !== this._recordId) {
+ this._recordId = id;
+ this._record = null; // force re-fetch
+ this.handleRecordChange();
+ }
+ } else {
+ this._recordId = null;
+ }
+ }
+
+ get recordId(): any {
+ return this._recordId;
+ }
+
+ // IDL record we are editing
+ _record: IdlObject = null;
+ @Input() set record(r: IdlObject) {
+ if (r) {
+ if (!this.idl.pkeyMatches(this.record, r)) {
+ this._record = r;
+ this._recordId = null; // avoid mismatch
+ this.handleRecordChange();
+ }
+ } else {
+ this._record = null;
+ }
}
+ get record(): IdlObject {
+ return this._record;
+ }
+
+ initDone: boolean;
+
// Comma-separated list of field names defining the order in which
// fields should be rendered in the form. Any fields not represented
// will be rendered alphabetically by label after the named fields.
} else {
this.initRecord();
}
+ this.initDone = true;
+ }
+
+ // If the record ID changes after ngOnInit has been called
+ // and we're using displayMode=inline, force the data to
+ // resync in real time
+ handleRecordChange() {
+ if (this.initDone && !this.isDialog()) {
+ this.initRecord();
+ }
}
isDialog(): boolean {
return this.displayMode === 'dialog';
}
- // Set the record value and clear the recId value to
- // indicate the record is our current source of data.
+ // DEPRECATED: This is a duplicate of this.record = abc;
setRecord(record: IdlObject) {
- this.record = record;
- this.recId = null;
+ console.warn('fm-editor:setRecord() is deprecated. ' +
+ 'Use editor.record = abc or [record]="abc" instead');
+ this.record = record; // this calls the setter
}
// Translate comma-separated string versions of various inputs
if (this.mode === 'update' || this.mode === 'view') {
let promise;
- if (this.record && this.recId === null) {
+ if (this.record && this.recordId === null) {
promise = Promise.resolve(this.record);
- } else {
+ } else if (this.recordId) {
promise =
- this.pcrud.retrieve(this.idlClass, this.recId).toPromise();
+ this.pcrud.retrieve(this.idlClass, this.recordId).toPromise();
+ } else {
+ // Not enough data yet to fetch anything
+ return Promise.resolve();
}
return promise.then(rec => {
if (!rec) {
return Promise.reject(`No '${this.idlClass}'
- record found with id ${this.recId}`);
+ record found with id ${this.recordId}`);
}
- this.record = rec;
+ // Set this._record (not this.record) to avoid loop in initRecord()
+ this._record = rec;
this.convertDatatypesToJs();
return this.getFieldList();
});
//
// Create a new record from the stub record provided by the
// caller or a new from-scratch record
- this.setRecord(this.record || this.idl.create(this.idlClass));
+ // Set this._record (not this.record) to avoid loop in initRecord()
+ this._record = this.record || this.idl.create(this.idlClass);
+ this._recordId = null; // avoid future confusion
return this.getFieldList();
}
this.convertDatatypesToIdl(recToSave);
this.pcrud[this.mode]([recToSave]).toPromise().then(
result => {
- this.onSave$.emit(result);
+ this.recordSaved.emit(result);
this.successStr.current().then(msg => this.toast.success(msg));
if (this.isDialog()) { this.close(result); }
},
error => {
- this.onError$.emit(error);
+ this.recordError.emit(error);
this.failStr.current().then(msg => this.toast.warning(msg));
if (this.isDialog()) { this.error(error); }
}
}
cancel() {
- this.onCancel$.emit(this.record);
+ this.recordCanceled.emit(this.record);
this.close();
}