Use case: You have a list of entities rendered by
<xt-render> and want clicking an item to populate an
edit form — without the list and editor knowing about each other.
Prerequisite: Describe an entity type, Edit any object
(outputs)
on the list<xt-render displayMode="LIST_VIEW" valueType="bookType"
[value]="entities()"
(outputs)="onOutput($event)">
</xt-render>valueSelectedimport {XtComponentOutput} from 'xt-components';
onOutput(output: XtComponentOutput | null) {
if (output?.valueSelected != null) {
output.valueSelected.subscribe(selected => {
this.selectedEntity.set(selected);
this.rebuildForm(); // Populate the edit form
this.selectedIndex = this.entities().indexOf(selected);
});
}
}The valueSelected observable emits every time the user
clicks a row in the list.
protected rebuildForm() {
const form = this.formBuilder.group({});
updateFormGroupWithValue(form, this.selectedEntity() ?? {},
'bookType', this.resolver.typeResolver);
this.bookForm.set(form); // bookForm is a signal<FormGroup>
}The form must be a signal<FormGroup> because it
gets rebuilt each time the selection changes.
<form [formGroup]="bookForm()" (ngSubmit)="save()">
<xt-render displayMode="FULL_EDITABLE" valueType="bookType"
[formGroup]="bookForm()"> </xt-render>
<p-button label="Save" type="submit" />
</form>
<p-button label="Create" (onClick)="create()" />protected create() {
this.selectedEntity.set({});
this.selectedIndex = -1;
this.rebuildForm();
}
protected save() {
if (this.selectedIndex === -1) {
// Create new
this.entities.update(list => [...list, this.bookForm().value]);
} else {
// Update existing
this.entities.update(list => {
list[this.selectedIndex] = this.bookForm().value;
return [...list];
});
}
}XtRenderComponent instantiates a child component
internally and proxies its outputs. When the child emits
valueSelected (e.g. the list component signals a row
click), the (outputs) emitter on
<xt-render> fires. Your handler receives the full
output object and can subscribe to individual events.