شاید براتون سؤال پیش اومده باشه که بین resource و rxResource و httpResource چه تفاوتهایی وجود داره؟
با چند تصویر و توضیح که این تفاوت هارو بیان میکنه همراه بشید
#angularcafe
با چند تصویر و توضیح که این تفاوت هارو بیان میکنه همراه بشید
#angularcafe
❤4
Frontend Burger
لایههای مختلف کارهایی که یک Frontend developer در پروژه هاش انجام میده میتونه شامل این موارد باشه.
#angularcafe
لایههای مختلف کارهایی که یک Frontend developer در پروژه هاش انجام میده میتونه شامل این موارد باشه.
#angularcafe
🔥2😎2
https://ui.ng.guide/ui
x.com/katsuba_igor
یکی از توسعه دهنده های انگولار یه wrapper برای material 3 زده که هم signal first هست هم zoneless
و اینکه به نسبت خود سایت انگولار هم مستندات بهتری داره هم شخصی سازی بهتری میشه رو component ها داشت
بدون css framework و سبک درست شده
#angularmaterial
#angularsignal
#angularcafe
x.com/katsuba_igor
یکی از توسعه دهنده های انگولار یه wrapper برای material 3 زده که هم signal first هست هم zoneless
و اینکه به نسبت خود سایت انگولار هم مستندات بهتری داره هم شخصی سازی بهتری میشه رو component ها داشت
بدون css framework و سبک درست شده
#angularmaterial
#angularsignal
#angularcafe
👍2❤1👏1
کافه انگولار
Photo
با stable شدن API های Resource و httpResource برای مدیریت requestها، loading state و error state ها، برای componentها و serviceها خیلی کاربردی شده.
ولی این API های جدید برای Router Guard و Resolver ها مناسب نیستن!
حالا چرا؟
چون ذاتا Guardها و Resolverها تا مشخص شدن نتیجه شون Navigation رو متوقف میکنن، یعنی باید منتظر یه نتیجه ای مثل Boolean، Promise یا Observable بمونن.
ولی Resourceها ذاتا Reactive هستن و وقتی داخل Resolver و یا Guard ازشون استفاده کنیم مقدار اولیه value شون معمولا undefined هست و request در وضعیت loading قرار داره و ما اگه همون لحظه بخوایم value شون رو استفاده کنیم اون Guard ممکنه سریعا مقدار false رو برگردونه و Navigation رو Cancel کنه حتی قبل از اینکه API اصلا جواب رو برگردونه!
حالا راه درست چیه؟
برای Guard و Resolver فعلا همچنان از HttpClient و Observable یا Promise استفاده میکنیم که بشه از Async بودن شون این بهره رو برد تا جواب حاصل نشده، نتیجه ای برگردونده نشه قبل از Navigation کامل.
پس برای جمعبندی در حال حاضر Resource و httpResource برای UI و Reactive Data عالی هستن، اما برای Guard و Resolver درست هست که از همون روشهای فعلی Observable و Promise استفاده کنیم.
در واقع Resource برای Data binding استفاده بشه و Observable و Promise برای Control flow در Routing پروژه.
#angularsignal
#angularcafe
ولی این API های جدید برای Router Guard و Resolver ها مناسب نیستن!
حالا چرا؟
چون ذاتا Guardها و Resolverها تا مشخص شدن نتیجه شون Navigation رو متوقف میکنن، یعنی باید منتظر یه نتیجه ای مثل Boolean، Promise یا Observable بمونن.
ولی Resourceها ذاتا Reactive هستن و وقتی داخل Resolver و یا Guard ازشون استفاده کنیم مقدار اولیه value شون معمولا undefined هست و request در وضعیت loading قرار داره و ما اگه همون لحظه بخوایم value شون رو استفاده کنیم اون Guard ممکنه سریعا مقدار false رو برگردونه و Navigation رو Cancel کنه حتی قبل از اینکه API اصلا جواب رو برگردونه!
export const authGuard: CanActivateFn = () => {
const authResource = httpResource<boolean>(() => ({
url: '/api/auth/status',
}));
// This returns the signal's current value synchronously
// Which is `undefined` initially!
return authResource.value() ?? false;
};حالا راه درست چیه؟
برای Guard و Resolver فعلا همچنان از HttpClient و Observable یا Promise استفاده میکنیم که بشه از Async بودن شون این بهره رو برد تا جواب حاصل نشده، نتیجه ای برگردونده نشه قبل از Navigation کامل.
export const authGuard: CanActivateFn = () => {
const http = inject(HttpClient);
// An Observable cleanly blocks the Router until it completes or emits
return http.get<boolean>('/api/auth/status');
};پس برای جمعبندی در حال حاضر Resource و httpResource برای UI و Reactive Data عالی هستن، اما برای Guard و Resolver درست هست که از همون روشهای فعلی Observable و Promise استفاده کنیم.
در واقع Resource برای Data binding استفاده بشه و Observable و Promise برای Control flow در Routing پروژه.
#angularsignal
#angularcafe
👍4
کافه انگولار
Photo
خبر خوب اینکه تو Dialog در Angular Material 22 قابلیت input binding اضافه شده.
یعنی چی؟
قبلا برای پاس دادن مقادیری به Mat Dialog باید data رو پر میکردیم و داخل Component مورد نظر با inject کردن MAT_DIALOG_DATA اونو میگرفتید و استفاده میکردیم
حالا برای اینکه بتونیم از input و output و two-way binding استفاده کنیم قابلیت binding اضافه شده و میشه عین یه component که داخل html مینویسیم و بهش input و output پاس میدیم با component پاس داده شده به Dialog هم همون مدلی برخورد کنیم:
برای مثال:
code:
و با گرفتن MAT_DIALOG_DATA اون دیتا رو استفاده میکردیم.
حالا با قابلیت binding میتونیم همچین چیزی انتظار داشته باشیم:
code:
حالا چطوری؟
code:
داخل component ای هم که داخل Dialog مد نظر داریم مثل حالت عادی signal input و outout و two-way رو استفاده میکنیم:
code:
منبع
#angularsignal
#angularcafe
یعنی چی؟
قبلا برای پاس دادن مقادیری به Mat Dialog باید data رو پر میکردیم و داخل Component مورد نظر با inject کردن MAT_DIALOG_DATA اونو میگرفتید و استفاده میکردیم
حالا برای اینکه بتونیم از input و output و two-way binding استفاده کنیم قابلیت binding اضافه شده و میشه عین یه component که داخل html مینویسیم و بهش input و output پاس میدیم با component پاس داده شده به Dialog هم همون مدلی برخورد کنیم:
برای مثال:
code:
protected openSettingsDialog() {
this.dialog.open(NotificationSettingsComponent, {
width: '28rem',
panelClass: 'settings-dialog',
data: {user: this.user()}
});
}و با گرفتن MAT_DIALOG_DATA اون دیتا رو استفاده میکردیم.
حالا با قابلیت binding میتونیم همچین چیزی انتظار داشته باشیم:
code:
<app-notification-settings
[user]="user()"
[(enabled)]="notificationsEnabled"
(saved)="saveNotificationSettings($event)"
/>
حالا چطوری؟
code:
protected openSettingsDialog() {
this.dialog.open(NotificationSettingsComponent, {
width: '28rem',
panelClass: 'settings-dialog',
bindings: [
inputBinding('user', this.user),
outputBinding<NotificationSettingsSaved>('saved', settings => {
this.saveNotificationSettings(settings);
}),
twoWayBinding('enabled', this.notificationsEnabled),
],
});
}
داخل component ای هم که داخل Dialog مد نظر داریم مثل حالت عادی signal input و outout و two-way رو استفاده میکنیم:
code:
export class NotificationSettingsComponent {
readonly user = input<User | null>(null);
readonly enabled = model(false);
readonly saved = output<NotificationSettingsSaved>();
protected save() {
if (this.user()) {
this.saved.emit({
userId: this.user()!.id,
enabled: this.enabled(),
});
}
}
}منبع
#angularsignal
#angularcafe
Medium
Angular Material Dialogs Now Support Real Component Bindings
Angular Material dialogs just got a much cleaner way to work with reusable components!
❤3👏2
۱. مهاجرتهای خودکار
۲. برای تبدیل Observableها از bridge مربوطه یعنی toSignal() استفاده کنید.
نمونه بالا مقدار اولیه رو undefined ست میکنه که میشه مثل نمونه زیر با initialValue مقداردهی اولیه کرد signal مون رو:
۳. تبدیل Subjectها به Signal:
۴. جایگزین RXJS Operatorها با Computed:
بعضی موقعها، میخوایم بخشی از منطق RXJS رو نگه داریم چون خوب کار میکنه و از یه سری ویژگیهایی که معادل مستقیم مبتنی بر سیگنال ندارن مثل نمونه زیر که timer هست استفاده کنیم. تو این حالت، toSignal باز هم میتونه به عنوان یه Bridge عمل کنه و کل عملیات RX مون رو به signal تبدیل کنه:
نتیجهگیری به نظرم اینه که با جفت ویژگی ها تو صلح باشیم و از هرکدوم تو جای خودش استفاده کنیم و اگه از RXJS استفاده میکنیم از Memory leak جلوگیری کنیم و ازش اجتناب کنیم و البته که استفاده غیراصولی از Signal هم میتونه side effectهای Memory leak داشته باشه ولی مدیریتش راحتتر از RX هست و همچنین لذت استفاده از signal به نظرم، باعث جلوگیری از استفاده چندین operator و کم کردن تعداد boilerplateهای زیادی که قبلا مینوشتیم رو به ارمغان میاره برامون.
#angularsignal
#angularcafe
ng generate @angular/core:signal-input-migration
ng generate @angular/core:output-migration
ng generate @angular/core:signal-queries-migration
۲. برای تبدیل Observableها از bridge مربوطه یعنی toSignal() استفاده کنید.
// Before
data$ = this.http.get(this.API_URL);
// Converting to Signal
data = toSignal(this.data$);
نمونه بالا مقدار اولیه رو undefined ست میکنه که میشه مثل نمونه زیر با initialValue مقداردهی اولیه کرد signal مون رو:
// Without default value
rates: Signal<Rates | undefined> = toSignal(this.rates$);
// With default value
rates: Signal<Rates> = toSignal(this.rates$,
{initialValue: {USD: 1, EUR: 1, GBP: 1}}
);
۳. تبدیل Subjectها به Signal:
// Subject version
currentCurrency = new BehaviorSubject<CurrencySymbol>(DEFAULT_CURRENCIES[0]);
// Signal version
currentCurrency = signal<CurrencySymbol>(DEFAULT_CURRENCIES[0]);
۴. جایگزین RXJS Operatorها با Computed:
// RxJs code
currentExchangeRate$ = combineLatest([
this.exchangeRates$,
this.currentCurrency$
]).pipe(
map(([rates, current]) => rates[current.code as keyof ExchangeRates])
);
// Equivalent Signal based version
currentExchangeRate = computed(
() => this.exchangeRates()[this.currentCurrency().code]
);
بعضی موقعها، میخوایم بخشی از منطق RXJS رو نگه داریم چون خوب کار میکنه و از یه سری ویژگیهایی که معادل مستقیم مبتنی بر سیگنال ندارن مثل نمونه زیر که timer هست استفاده کنیم. تو این حالت، toSignal باز هم میتونه به عنوان یه Bridge عمل کنه و کل عملیات RX مون رو به signal تبدیل کنه:
// RxJs code
exchangeRates$: Observable<ExchangeRates> = timer(0, 3600000)
.pipe(
switchMap(() => this.http.get<any>(this.API_URL)),
map(data => ({
USD: 1,
EUR: data.rates.EUR,
GBP: data.rates.GBP
}))
);
// Simple Signal conversion with toSignal()
exchangeRates = toSignal(this.exchangeRates$);
نتیجهگیری به نظرم اینه که با جفت ویژگی ها تو صلح باشیم و از هرکدوم تو جای خودش استفاده کنیم و اگه از RXJS استفاده میکنیم از Memory leak جلوگیری کنیم و ازش اجتناب کنیم و البته که استفاده غیراصولی از Signal هم میتونه side effectهای Memory leak داشته باشه ولی مدیریتش راحتتر از RX هست و همچنین لذت استفاده از signal به نظرم، باعث جلوگیری از استفاده چندین operator و کم کردن تعداد boilerplateهای زیادی که قبلا مینوشتیم رو به ارمغان میاره برامون.
#angularsignal
#angularcafe
👍3❤1