I'm refactoring an Angular component to use signals throughout, but I'm stuck on how to properly initialize a signal that depends on required inputs without using ngOnInit. I am trying to see in this experiment that how it behaves without using any lifecycle hooks.
The processedData signal needs to be mutable, but its initial state must be derived from the required inputs which aren't available in the constructor.
What's the recommended Angular signals pattern for deriving initial signal state from required inputs while keeping the signal mutable for user interactions? I don't want to see this error if not using ngOnInit lifecycle:
RuntimeError: NG0950: Input "items" is required but no value is available yet. Find more at https://angular.dev/errors/NG0950
Current approach (works but uses ngOnInit):
import { Component, input, output, signal } from '@angular/core';
import { explicitEffect } from 'ngxtension/explicit-effect';
interface DataItem {
id: string;
name: string;
status: string;
}
type ProcessedData = Record<string, {
item: DataItem;
selected: boolean;
displayName: string;
}>;
@Component({
selector: 'app-example',
template: `<div>{{ processedData() | json }}</div>`
})
export class ExampleComponent {
items = input.required<DataItem[]>();
mode = input.required<'add' | 'remove'>();
processedData = signal<ProcessedData>({});
dataChanged = output<ProcessedData>();
constructor() {
explicitEffect([this.processedData], ([data]) =>
this.dataChanged.emit(data)
);
}
ngOnInit(): void { //trying to avoid lifecycles
this.processedData.set(
this.items().reduce((acc, item) => ({
...acc,
[item.id]: {
item,
selected: this.getInitialState(item),
displayName: item.name.toUpperCase()
}
}), {})
);
}
updateSelection(id: string): void {
this.processedData.update(data => ({
...data,
[id]: { ...data[id], selected: !data[id].selected }
}));
}
private getInitialState(item: DataItem): boolean {
return this.mode() === 'add'
? item.status === 'ACTIVE'
: item.status === 'FINAL';
}
}
Input "selectionData" is requiredbut the code is something different!