Pankaj Parkar
Indian | 30 | Ex MVP | Angular GDE
Change propagation through dependencies tracking
FirstName | LastName | FullName |
---|---|---|
Adam | Clarke | Adam Clarke |
Phil | Smith | Phil Smith |
firstName = 'Adam';
lastName = 'Clarke';
fullName = `${this.firstName} ${this.lastName}`;
console.log(this.fullName); // Adam Clarke
updateFirstName() {
this.firstName = 'Mr. Adam';
}
this.updateFirstName();
console.log(this.fullName); // Adam Clarke
get fullName() {
return `${this.firstName} ${this.lastName}`;
}
pankajparkar
const count = signal(1); // WritableSignal<number>
const age = signal<number>(18); // WritableSignal<number>
const user = signal<User>({
id: 1,
name: 'Pankaj'
}); // WritableSignal<User>
pankajparkar
export type Signal<T> = {
() => T;
[SIGNAL]: unknown;
};
export interface WritableSignal<T> extends Signal<T> {
set(value: T): void;
update(updateFn: (value: T) => T): void;
asReadonly(): Signal<T>;
}
const count = signal(1); // WritableSignal<number>
pankajparkar
✍️ writable
🔢 📐🔀 computed
💥 effect
pankajparkar
const count = signal(0); // WritableSignal<number>
const count = signal<number>(0);
// Signals are getter functions
// calling them reads their value.
console.log('The count is: ' + count());
// Set value directly
count.set(3);
// Check count value is
console.log('The count is: ' + count()); // 3
// if want to update value based on last value
count.update(value => value + 1);
// Check count value again
console.log('The count is: ' + count()); // 4
Reference: Stackblitz
pankajparkar
const firstName = signal('Pankaj');
const lastName = signal('Parkar');
const fullName = computed(
() => `${firstName()} ${lastName()}`
);
console.log('Firstname is ', firstName()); // 'Pankaj Parkar'
function updateFirstName() {
firstName.set('Pankaj 1');
}
updateFirstName();
console.log('FullName is ', fullName()); // 'Pankaj 1 Parkar'
pankajparkar
Reference: Stackblitz
class TestComponent {
firstName = signal('Pankaj');
lastName = signal('Parkar');
constructor() {
effect(() => `First name is ${this.firstName()}`);
effect(() => `Last name is ${this.lastName()}`);
}
updateName() {
this.firstName.set('Pankajjj');
this.lastName.set('Parkarr');
}
}
pankajparkar
@Component({
...,
})
export class SignalComponent {
firstName = signal('Pankaj');
lastName = signal('Parkar');
fullName = computed(() =>
`${this.firstName()} ${this.lastName()}`
);
firstNameEffect = effect(() =>
console.log(`First Name is ${this.firstName()}`)
);
updateFirstName() {
this.firstName.set('Pankajj');
this.lastName.set('Pankajj');
}
}
<table>
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Full Name</th>
</tr>
<tr>
<td>{{firstName()}}</td>
<td>{{lastName()}}</td>
<td>{{fullName()}}</td>
</tr>
</table>
<button (click)="updateFirstName()">
Update FirstName
</button>
Reference: Stackblitz
Reference: Stackblitz
pankajparkar
fName | lName | fullName | Points |
---|---|---|---|
Adam | Clarke | Adam Clarke | 1 |
Phil | Smith | Phil Smith | 2 |
Total | 3 |
Emp
Spreadsheet
1st row
Clarke
Adam
1
Phil
Smith
2
2nd row
Total: 3
Adam Clarke
Phil Smith
pankajparkar
const obs$ = toObservable(mySignal);
obs$.subscribe(
value => console.log(value)
);
mySignal.set(1);
mySignal.set(2);
mySignal.set(3);
@Component(...)
export class SearchResults {
// query is signal stored in service
query = inject(QueryService).query;
query$ = toObservable(this.query);
results$ = this.query$.pipe(
switchMap(query =>
this.http.get('/search?q=' + query )
),
);
}
pankajparkar
import { Component } from '@angular/core';
import { toSignal } from '@angular/core/rx-interop';
import { interval } from 'rxjs';
@Component({
template: `{{ counter() }}`,
})
export class Ticker {
counterObservable = interval(1000);
// Get a `Signal` representing the `counterObservable`'s value.
counter = toSignal(this.counterObservable, {
initialValue: 0,
});
// another example
formValues = toSignal(this.form.valueChanges);
}
pankajparkar
pankajparkar
@Component({
signals: true,
selector: 'user-profile',
template: `
<p>Name: {{ firstName() }} {{ lastName() }}</p>
<p>Account suspended: {{ suspended() }}</p>
`,
})
export class UserProfile {
// Create an optional input without an initial value.
firstName = input<string>(); // Signal<string|undefined>
// Create an input with a default value
lastName = input('Smith'); // Signal<string>
// Create an input with options.
suspended = input<boolean>(false, {
alias: 'disabled',
}); // Signal<boolean>
updated = output<boolean>(); // EventEmitter<boolean>;
}
pankajparkar
pankajparkar
pankajparkar
pankajparkar
By Pankaj Parkar
Rethinking reactivity using Angular Signals