Document the "bag in box" patterns
Closed this issue · 1 comments
I try to avoid Angular's bidirectional bindings ("bag in box" bindings), but sometimes they are required. They can be handled entirely by documentation, but there may be a call for helper functions.
Creating an Input/Output pair that supports "bag in box" binding should be easy enough:
@Component({
// …
})
export class MyExample extends PharkasComponent<MyExample> {
@Input() set test(value: string | Observable<string>) { this.setInput('test', value) }
@Output() readonly testChange = EventEmitter()
constructor(ref: ChangeDetectorRef) {
super(ref)
const test = this.useInput('test')
this.bindOutput(this.testChange, test)
}
}
On the other hand the direct way to create a template binding to consume some other component, won't work without a new helper:
@Component({
// …
template: `<example-component test=[(test)]></example-component>
})
export class MyExample extends PharkasComponent<MyExample> {
get test { return this.bindable<string>('test') }
set test(value: string | Observable<string>) { this.setInput('test', value) }
constructor(ref: ChangeDetectorRef) {
super(ref)
// Depending on order, one of these bindings will fail with an already bound error
const test = this.useInput('test')
this.bind('test', someObservable)
}
}
Alternatively, this can be easily accomplished eschewing the "bag in box" "shortcut" operator and documenting the "preferred" Pharkas approach, which may currently be better aligned as:
@Component({
// …
template: `<example-component [test]="test" (testChange)="handleTestChange"></example-component>
})
export class MyExample extends PharkasComponent<MyExample> {
get test { return this.bindable<string>('test') }
handleTestChange: (value: string) => void
constructor(ref: ChangeDetectorRef) {
super(ref)
this.handleTestChange = this.createCallback('handleTestChange')
const testChange = this.useCallback('handleTestChange')
const someObservable = combineLatest([testChange, /* … */]).pipe(
map(([test], /* … */) => { /* … */ })
)
this.bind('test', someObservable)
}
}
Action items:
- Should probably document these even if no helper added
- Should there be a helper function here? Would it be more like a
useBidiCallback
orbindBidi
?
Leaning more and more towards the documentation side of the fence, especially because everywhere I encounter a "bag-in-box" I end up dropping it for more native-feeling Observable patterns anyway. Case in point: dropping the update
Input and updateChanged
Output from a Highcharts wrapper (#16) because it seemed entirely redundant when the Highcharts options were already in an observable and directly pushing "hey, here's an update".
I don't want to add it to the current README, because it would feel entirely like bloat to me, so this should be a sub-task of #9.