برنامه نویسیبک اند

نحوه استفاده از پارامترهای Query با Angular Router

مقدمه

پارامترهای Query در Angular به شما اجازه می‌دهند وضعیت اختیاری را از طریق URL بدون تأثیر بر اینکه کدام Route تطبیق می‌یابد، پاس دهید. برخلاف پارامترهای Route—که بخشی از تعریف مسیرند و برای فعال شدن Route الزامی‌اند—پارامترهای Query بعد از کاراکتر ? ظاهر می‌شوند و می‌توانند بدون هیچ اثری بر ناوبری غایب باشند. آن‌ها سازوکار استاندارد برای کدگذاری تنظیمات فیلتر، وضعیت صفحه‌بندی (Pagination) و ترتیب مرتب‌سازی در اپلیکیشن‌های Angular هستند.

در این آموزش، از سناریوی فهرست محصولات استفاده می‌کنید تا یاد بگیرید چطور با Router.navigate و RouterLink پارامترهای Query تنظیم کنید؛ با queryParamsHandling پارامترها را بین ناوبری‌های متعدد حفظ یا ادغام کنید؛ و با ActivatedRoute مقادیر را در کامپوننت بخوانید. هم‌چنین بده‌بستان‌های بین استراتژی‌های خواندن Snapshot و Observable و نحوه اتصال مستقیم پارامترهای Query به Inputهای کامپوننت در Angular 16+—بدون تزریق ActivatedRoute—را می‌آموزید.

نکات کلیدی

  • پارامترهای Query اختیاری‌اند، بعد از ? در URL ظاهر می‌شوند و بر تطبیق Route اثر نمی‌گذارند.
  • از queryParams با Router.navigate یا [queryParams] با RouterLink برای الصاق پارامترها به هر هدف ناوبری استفاده کنید.
  • queryParamsHandling: 'preserve' رشته Query موجود را بدون تغییر به Route بعدی می‌برد؛ 'merge' پارامترهای موجود را با جدیدها ترکیب می‌کند و کلیدهای تکراری را با مقدار جدید بازنویسی می‌نماید.
  • وقتی queryParamsHandling حذف شود، Angular همه پارامترهای Query قبلی را در ناوبری بعدی دور می‌ریزد.
  • ActivatedRoute.snapshot.queryParams فقط وقتی امن است که کامپوننت همیشه با هر ناوبری.destroy و بازسازی شود.
  • برای کامپوننت‌هایی که Angular در ناوبری‌های به همان Route زنده نگه می‌دارد، در ActivatedRoute.queryParams یا queryParamMap مشترک (Subscribe) شوید.
  • queryParamMap.get('key') برای پارامترهای غایب مقدار null برمی‌گرداند؛ همیشه قبل از استفاده از مقدار، چک null یا فالبک ?? اعمال کنید.
  • Angular 16+ از withComponentInputBinding() پشتیبانی می‌کند؛ که به شما اجازه می‌دهد پارامترهای Query را به‌عنوان ویژگی‌های @Input()—بدون تزریق ActivatedRoute—دریافت کنید.
  • پارامترهای Query برای فیلترهای جستجو، صفحه‌بندی و هر وضعیت اپلیکیشنی که کاربران باید بتوانند از طریق URL بوکمارک یا اشتراک بگذارند ایده‌آل‌اند.

پیش‌نیازها

برای دنبال کردن این آموزش به این موارد نیاز دارید:

  • آشنایی با Angular Router، RouterLink و ActivatedRoute.
  • Angular 16 یا جدیدتر.

پارامترهای Query در Angular چیستند؟

پارامترهای Query، جفت‌های کلید-مقداری‌اند که بعد از ? به URL الصاق می‌شوند؛ با جفت‌های متعدد با & جدا می‌شوند. با URL زیر، order و price-range پارامترهای Query هستند:

http://localhost:4200/products?order=popular&price-range=not-cheap

Router مربوط به Angular این جفت‌ها را خودکار پارس و از طریق ActivatedRoute افشا می‌کند. چون پارامترهای Query بخشی از مسیر Route نیستند، Route همچنان فارغ از اینکه چه چیزی در رشته Query ظاهر می‌شود، با /products تطبیق می‌یابد.

پارامترهای Query در مقابل پارامترهای Route

جدول زیر پارامترهای Query را با پارامترهای Route مقایسه می‌کند تا به انتخاب ابزار درست برای مورد استفاده‌تان کمک کند:

ویژگیپارامترهای Queryپارامترهای Route
ظاهر URLبعد از ?، مثلاً /products?order=popularبخشی از مسیر، مثلاً /products/123
الزامینه، همیشه اختیاریبله، برای تطبیق Route الزامی
تطبیق Routeبر تطبیق Route اثر نمی‌گذارندبرای فعال شدن Route باید موجود باشند
API ناوبریqueryParams در NavigationExtrasعنصر آرایه مسیر در Router.navigate
اتصال RouterLink[queryParams]="{ key: value }"عنصر مسیر، مثلاً [routerLink]="['/products', id]"
مورد استفاده معمولفیلترها، ترتیب مرتب‌سازی، صفحه‌بندی، وضعیت مشترکشناسه‌های منبع مانند ID یا Slug

تمایز کلیدی این است که پارامترهای Route منبعِ در حال بارگذاری را تعریف می‌کنند؛ در حالی که پارامترهای Query نحوه ارائه یا فیلتر شدن آن منبع را تغییر می‌دهند.

چه زمانی از پارامترهای Query استفاده کنیم

پارامترهای Query انتخاب درستی هستند وقتی مقدار اختیاری است (Route باید با یا بدون آن فعال شود)، قابل‌اشتراک است (کاربر باید بتواند نمای فیلترشده‌ای را بوکمارک کند و در همان وضعیت فرود بیاید)؛ یا بین Routeها قابل استفاده مجدد است (ممکن است مقدار لازم باشد حین ناوبری به مسیر دیگری باقی بماند). الگوهای رایج دنیای واقعی شامل صفحات جستجو (/search?q=angular)، فهرست‌های صفحه‌بندی‌شده (/products?page=2&pageSize=20) و پنل‌های فیلتر چندوجهی (/items?category=books&sort=price) هستند.

استفاده از پارامترهای Query با Router.navigate

برای پاس دادن پارامترهای Query حین ناوبری از طریق کد، شیء queryParams را در آرگومان NavigationExtras به Router.navigate بگنجانید. NavigationExtras (ایمپورت‌شده از @angular/router) اعضایی مانند queryParams، queryParamsHandling، fragment و گزینه‌های دیگر را می‌پذیرد.

مثال زیر به /products ناوبری می‌کند و order=popular را به URL الصاق می‌کند:

import { Component } from '@angular/core';
import { Router } from '@angular/router';

@Component({ ... })
export class ProductListComponent {
  constructor(private router: Router) {}

  goProducts() {
    this.router.navigate(
      ['/products'],
      { queryParams: { order: 'popular' } }
    );
  }
}

این ناوبری URLای شبیه این تولید می‌کند:

Output
http://localhost:4200/products?order=popular

برای پاس دادن چند پارامتر Query، کلیدهای بیشتری به شیء queryParams اضافه کنید. مثال زیر هم پارامتر order و هم price-range را اضافه می‌کند:

goProducts() {
  this.router.navigate(
    ['/products'],
    { queryParams: { order: 'popular', 'price-range': 'not-cheap' } }
  );
}

این ناوبری URL زیر را تولید می‌کند:

Output
http://localhost:4200/products?order=popular&price-range=not-cheap

حفظ یا ادغام پارامترهای Query با queryParamsHandling

به‌طور پیش‌فرض، Angular همه پارامترهای Query را وقتی به Route جدیدی ناوبری می‌کنید پاک می‌کند. گزینه queryParamsHandling در NavigationExtras این رفتار را به دو شکل Override می‌کند: 'preserve' پارامترهای URL فعلی را کاملاً نگه می‌دارد؛ و 'merge' پارامترهای فعلی را با جدیدهایی که تأمین می‌کنید ترکیب می‌کند.

از 'preserve' استفاده کنید وقتی به صفحه مرتبطی ناوبری می‌کنید که باید زمینه فعلی را بدون افزودن یا تغییر چیزی به ارث ببرد. در این مثال، کاربری روی /products?order=popular بدون از دست دادن پارامتر order به /users ناوبری می‌کند:

goUsers() {
  this.router.navigate(
    ['/users'],
    { queryParamsHandling: 'preserve' }
  );
}

URL حاصل پارامتر اصلی را نگه می‌دارد:

Output
http://localhost:4200/users?order=popular

از 'merge' استفاده کنید وقتی می‌خواهید پارامتر خاصی را بدون دور ریختن بقیه اضافه یا به‌روزرسانی کنید. مثال زیر پارامتر فیلتر جدیدی را با پارامتر order موجود ادغام می‌کند:

goUsers() {
  this.router.navigate(
    ['/users'],
    {
      queryParams: { filter: 'new' },
      queryParamsHandling: 'merge'
    }
  );
}

URL ادغام‌شده شامل هر دو پارامتر است:

Output
http://localhost:4200/users?order=popular&filter=new

نکته: گزینه preserveQueryParams در Angular 4 منسوخ و در Angular 8 حذف شد. به‌جایش از queryParamsHandling: 'preserve' استفاده کنید.

سناریوی عملی برای 'merge'، روند کاری فیلتر چندمرحله‌ای است؛ جایی که کاربُر دسته‌ای را روی یک کامپوننت و بازه قیمتی را روی دومی انتخاب می‌کند. هر ناوبری می‌تواند انتخابش را بدون بازنویسی انتخاب‌های قبلی در URL ادغام کند.

استفاده از پارامترهای Query با RouterLink

دستور RouterLink همان اتصال‌های queryParams و queryParamsHandling را مثل Router.navigate پشتیبانی می‌کند. از اتصال [queryParams] برای تنظیم پارامترها و ویژگی queryParamsHandling برای کنترل سرنوشت موجودها استفاده کنید.

برای تنظیم پارامتر Query در قالب، [queryParams] را به شیء Literal متصل کنید:

<a
  [routerLink]="['/products']"
  [queryParams]="{ order: 'popular' }"
>
  Products
</a>

برای حفظ یا ادغام پارامترها حین ناوبری قالب، queryParamsHandling را اضافه کنید. مثال زیر رشته Query فعلی را با پارامتر فیلتر جدیدی ادغام می‌کند:

<a
  [routerLink]="['/users']"
  [queryParams]="{ filter: 'new' }"
  queryParamsHandling="merge"
>
  Users
</a>

دقت کنید queryParamsHandling اینجا مقدار رشته ساده‌ای می‌گیرد (نه اتصال)؛ پس براکت‌های مربعی را حذف می‌کنید.

دسترسی به مقادیر پارامترهای Query

سرویس ActivatedRoute دو روش اصلی برای خواندن پارامترهای Query در کامپوننت فراهم می‌کند: از طریق Snapshot که وضعیت را در مقداردهی اولیه ثبت می‌کند؛ و از طریق Observableها که هر وقت URL تغییر کند انتشار می‌یابند. Angular 16 گزینه سومی اضافه کرد که پارامترها را خودکار به Inputهای کامپوننت متصل می‌کند.

خواندن با ActivatedRoute.snapshot.queryParams

ActivatedRoute.snapshot یک ActivatedRouteSnapshot است که وضعیت Route را در لحظه ساخته شدن کامپوننت منعکس می‌کند. خواندن snapshot.queryParams همگام است و اشتراکی لازم ندارد:

import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';

@Component({ ... })
export class ProductComponent implements OnInit {
  order: string | null = null;

  constructor(private route: ActivatedRoute) {}

  ngOnInit() {
    // مقدار را یک‌بار، هنگام ساخت کامپوننت می‌خواند
    this.order = this.route.snapshot.queryParams['order'] ?? null;
    console.log(this.order);
  }
}

اجرای این، وقتی URL برابر http://localhost:4200/products?order=popular است، لاگ زیر را می‌سازد:

Output
popular

رویکرد Snapshot فقط وقتی امن است که کامپوننت همیشه با هر ناوبری destroy و بازسازی شود. محدودیتش این است که اگر همان Instance کامپوننت حین تغییر رشته Query زنده بماند (مثلاً وقتی کاربر ستون مرتب‌سازی را بدون ترک صفحه تاگل می‌کند)، Snapshot به‌روز نمی‌شود.

خواندن با Observable مربوط به queryParams

اشتراک در ActivatedRoute.queryParams به شما جریانی می‌دهد که هر بار URL حین فعال بودن کامپوننت تغییر کند، شیء کامل پارامترهای Query را منتشر می‌کند. این رویکرد درست برای کامپوننت‌هایی است که Angular ممکن است بین ناوبری‌ها بازاستفاده‌شان کند:

import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { filter } from 'rxjs';

@Component({ ... })
export class ProductComponent implements OnInit {
  order: string = '';

  constructor(private route: ActivatedRoute) {}

  ngOnInit() {
    this.route.queryParams
      .pipe(filter(params => params['order'] !== undefined))
      .subscribe(params => {
        this.order = params['order'];
        console.log(this.order);
      });
  }
}

با URL برابر http://localhost:4200/products?order=popular، اشتراک لاگ می‌کند:

Output
popular

Observable مربوط به queryParams، انتخاب استاندارد وقتی است که کامپوننتی لازم است به تغییرات پارامترهایی که بدون بازسازی کامل صفحه اتفاق می‌افتند واکنش نشان دهد. برای دسترسی Type-Safe و پشتیبانی چندمقداری، Observable مربوط به queryParamMap که بعدش توضیح داده می‌شود مناسب‌تر است.

خواندن با queryParamMap

ActivatedRoute.queryParamMap Observableای از شیء ParamMap را برمی‌گرداند؛ که متدهای Accessor تایپ‌شده افشا می‌کند. این رویکرد ترجیح‌داده‌شده برای دسترسی به مقادیر منفرد است؛ چون ParamMap.get() برای کلیدهای مفقود null برمی‌گرداند (نه undefined)؛ و ParamMap.getAll() پارامترهایی که بیش از یک‌بار ظاهر می‌شوند را مدیریت می‌کند. مثلاً، URL برابر /products?tag=angular&tag=router شامل دو پارامتر tag است. در این حالت، getAll('tag') هر دو مقدار را به‌صورت آرایه برمی‌گرداند.

با URL برابر http://localhost:4200/products?order=popular&filter=new، می‌توانید هر پارامتر را با paramMap.get() بخوانید:

this.route.queryParamMap.subscribe(params => {
  const order = params.get('order');      // 'popular'
  const filterVal = params.get('filter'); // 'new'
  const keys = params.keys;               // ['order', 'filter']
  console.log(order, filterVal, keys);
});

اشتراک، مقدار order و filter و فهرست نام‌های پارامترهای فعال را لاگ می‌کند:

Output
popular new ['order', 'filter']

queryParamMap آینده‌خوش‌ترین راه خواندن پارامترهای Query در Angular است؛ چون get() و getAll() مدیریت null را صریح و چک حضور پارامتر را آسان می‌کنند.

Snapshot در مقابل Observable: کدام رویکرد را استفاده کنیم

از snapshot.queryParams (یا snapshot.queryParamMap) استفاده کنید وقتی می‌دانید کامپوننت همیشه با هر ناوبری تازه ساخته می‌شود و لازم نیست به تغییرات URL در میانه چرخه حیات واکنش نشان دهد. این کد را ساده نگه می‌دارد و از منطق مدیریت Reactive اضافی اجتناب می‌کند.

در queryParams یا queryParamMap مشترک شوید وقتی کامپوننت می‌تواند بین ناوبری‌های به همان Route با رشته‌های Query متفاوت بازاستفاده شود. صفحه فهرستی با ستون‌های قابل مرتب‌سازی مثال رایجی است: کاربر ترتیب مرتب‌سازی را تغییر می‌دهد، URL به‌روز می‌شود؛ اما Angular ممکن است همان Instance کامپوننت را فعال نگه دارد. اتکا به Snapshot در این سناریو، کامپوننت را در نمایش داده‌های کهنه بعد از ناوبری دوم رها می‌کند. رویکرد Observable این را با واکنش به هر تغییر URL—تا وقتی کامپوننت زنده است—رفع می‌کند.

رویکرد مدرن: اتصال پارامترهای Query با @Input()

Angular 16 ویژگی withComponentInputBinding() را معرفی کرد؛ ویژگی Routerای که پارامترهای Query (و سایر داده‌های Route) را خودکار به ویژگی‌های @Input() روی کامپوننت Route-شده متصل می‌کند. فعال کردن این ویژگی، نیاز به تزریق ActivatedRoute برای موارد خواندنِ سرراست را حذف می‌کند.

برای فعال کردنش، withComponentInputBinding() را به provideRouter() در app.config.ts اضافه کنید:

// app.config.ts (Angular 16+، اپلیکیشن Standalone)
import { ApplicationConfig } from '@angular/core';
import { provideRouter, withComponentInputBinding } from '@angular/router';
import { routes } from './app.routes';

export const appConfig: ApplicationConfig = {
  providers: [
    provideRouter(routes, withComponentInputBinding())
  ]
};

با فعال بودن این ویژگی، ویژگی @Input()ای با نام منطبق بر کلید پارامتر Query تعریف کنید:

import { Component, Input } from '@angular/core';

@Component({
  selector: 'app-product',
  standalone: true,
  template: `<p>Order: {{ order }}</p>`,
})
export class ProductComponent {
  // Angular پارامتر Query ?order=... را خودکار به این ویژگی متصل می‌کند
  @Input() order: string | undefined;
}

Angular مقدار order را از رشته Query هر وقت کامپوننت فعال می‌شود یا پارامتر تغییر می‌کند، تنظیم می‌کند. برای پروژه‌های Angular 16+ که به‌طور پیش‌فرض از کامپوننت‌های Standalone استفاده می‌کنند، این تمیزترین رویکرد برای دسترسی فقط-خواندنی به پارامترهای Query است.

اگر به‌جای @Input() به Signal واکنشی نیاز دارید، می‌توانید Observable مربوط به queryParamMap را با toSignal() از @angular/core/rxjs-interop به Signal تبدیل کنید. تابع inject() (موجود از Angular 14) راه تمیزی برای دسترسی به ActivatedRoute بدون تزریق Constructor فراهم می‌کند:

import { Component, inject } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { toSignal } from '@angular/core/rxjs-interop';
import { map } from 'rxjs';

@Component({
  selector: 'app-product',
  standalone: true,
  template: `<p>Order: {{ order() }}</p>`,
})
export class ProductComponent {
  private route = inject(ActivatedRoute);

  // سیگنال فقط-خواندنی که هر وقت ?order= تغییر کند به‌روز می‌شود
  readonly order = toSignal(
    this.route.queryParamMap.pipe(map(p => p.get('order')))
  );
}

ویژگی order سیگنال فقط-خواندنیِ سازگار با تشخیص تغییر مبتنی بر Signal مربوط به Angular—معرفی‌شده در Angular 16—است. وقتی پارامتر Query تغییر کند خودکار دوباره ارزیابی می‌شود؛ و قالب بدون اشتراک دستی دوباره رندر می‌شود.

موارد استفاده دنیای واقعی

درک اینکه کِی پارامترهای Query ابزار درستی هستند به اندازه دانستن API مهم است. سه الگو در تقریباً هر اپلیکیشن Angular ظاهر می‌شوند.

صفحات جستجو و فیلتر وضعیت فیلتر فعال را در URL کدگذاری می‌کنند تا کاربران بتوانند نمای خاصی را اشتراک بگذارند یا بوکمارک کنند. URLای مثل /items?category=books&sort=price را می‌توان در تب جدیدی پیست کرد و همان نتیجه فیلترشده را بازتولید می‌کند. بدون پارامترهای Query، آن وضعیت فقط در حافظه کامپوننت وجود دارد و با ریلود از بین می‌رود.

صفحه‌بندی از پارامترهای page و pageSize استفاده می‌کند تا به کاربران اجازه دهد مستقیم به صفحه خاصی ناوبری کنند و جایگاهشان را بعد از رفرش مرورگر بازیابند. قرارداد رایجی /products?page=2&pageSize=20 است؛ که pageSize وقتی غایب است به پیش‌فرض منطقی برمی‌گردد.

روند کاری چندمرحله‌ای از queryParamsHandling: 'merge' برای انباشت انتخاب‌ها بین مراحل ناوبری—بدون سرویس مشترک—استفاده می‌کند. کاربری که بازه تاریخ را در صفحه‌ای و مکان را در بعدی انتخاب می‌کند، می‌تواند هر دو مقدار را در URL به جلو ببرد؛ تا وقتی که هر ناوبری از 'merge' استفاده کند.

سوالات متداول

۱. چطور پارامترهای Query را در Routing مربوط به Angular پاس بدهیم؟

می‌توانید پارامترهای Query را با تأمین شیء queryParams به‌عنوان بخشی از NavigationExtras هنگام فراخوانی Router.navigate پاس بدهید. مثلاً برای افزودن پارامتر order هنگام ناوبری برنامه‌ای:

this.router.navigate(['/products'], { queryParams: { order: 'popular' } });

این URLای مثل /products?order=popular تولید می‌کند.

در قالب‌ها، از اتصال [queryParams] با RouterLink برای رسیدن به همان اثر استفاده می‌کنید:

<a [routerLink]="['/products']" [queryParams]="{ order: 'popular' }">
  Products
</a>

هر دو رویکرد پارامترهای Query را بعد از Route الصاق می‌کنند؛ که به شما اجازه می‌دهد وضعیت اختیاری را از طریق URL در اپلیکیشن به اشتراک بگذارید.

۲. چطور پارامتر Query را به RouterLink در Angular اضافه کنم؟

برای افزودن پارامترهای Query در قالب، Input مربوط به [queryParams] لینک (یا هر عنصری که از RouterLink استفاده می‌کند) را به شیء‌ای متصل کنید که کلیدهایش پارامترهای موردنظرتان هستند:

<a [routerLink]="['/products']" [queryParams]="{ order: 'popular' }">
  Products
</a>

اگر می‌خواهید پارامترهای Query را داینامیک تولید کنید، [queryParams] را به ویژگی کامپوننت (مثلاً filterOptions) متصل کنید؛ که به مقادیر اجازه می‌دهد در پاسخ به اقدامات کاربر یا وضعیت اپلیکیشن به‌روز شوند.

مثلاً:

// در کلاس کامپوننت شما
filterOptions = { order: 'popular', 'price-range': 'not-cheap' };
<a [routerLink]="['/products']" [queryParams]="filterOptions">
  Filtered Products
</a>

۳. تفاوت پارامترهای Query و پارامترهای Route در Angular چیست؟

پارامترهای Route مستقیماً درون بخش مسیر URL گنجانده می‌شوند. مثلاً، /products/:id پارامتر Route مربوط به id را تعریف می‌کند. این پارامترها برای تطبیق درست Route الزامی‌اند و باید در URL موجود باشند. معمولاً، پارامترهای Route برای تعیین و شناسایی منبع خاصی—مانند ID یکتای محصول—استفاده می‌شوند.

پارامترهای Query از طرف دیگر، بعد از ? در URL ظاهر و به‌صورت جفت‌های کلید-مقدار بیان می‌شوند. مثلاً، /products?order=popular از پارامتر Query برای نشان دادن ترتیب مرتب‌سازی استفاده می‌کند. پارامترهای Query همیشه اختیاری‌اند و بر اینکه کدام Route انتخاب یا تطبیق می‌یابد اثر نمی‌گذارند. معمولاً برای کنترل نمایش، فیلتر یا مرتب‌سازی منبع استفاده می‌شوند—مثلاً با تعیین ترتیب مرتب‌سازی یا اعمال فیلترها. آزادید پارامترهای Query را در صورت نیاز شامل یا حذف کنید بدون تأثیر بر توانایی Route در تطبیق.

۴. چطور چند پارامتر Query را در Angular پاس بدهم؟

می‌توانید هر تعداد پارامتر Query لازم را با گنجاندن جفت‌های کلید-مقدار اضافی در شیء اضافه کنید. مثلاً، افزودن هم order و هم price-range:

ناوبری برنامه‌ای:

this.router.navigate(['/products'], {
  queryParams: { order: 'popular', 'price-range': 'not-cheap' }
});

ناوبری قالب:

<a
  [routerLink]="['/products']"
  [queryParams]="{ order: 'popular', 'price-range': 'not-cheap' }"
>
  Products
</a>

هر دو روش URLای مثل این تولید می‌کنند:

/products?order=popular&price-range=not-cheap

این الگو از پارامترهای اختیاری نامحدود پشتیبانی می‌کند.

۵. تفاوت snapshot.queryParams و اشتراک در queryParams به‌عنوان Observable چیست؟

وقتی از snapshot.queryParams استفاده می‌کنید، Angular پارامترهای Query را یک‌بار—مشخصاً وقتی کامپوننت اولین‌بار ساخته می‌شود—می‌خواند. این روش برای سناریوهایی مناسب‌ترین است که کامپوننت همیشه با هر ناوبری destroy و بازسازی می‌شود؛ مانند وقتی که Angular کامپوننت را هر بار که Route یا URL تغییر می‌کند کاملاً پایین می‌کشد و دوباره Instantiate می‌کند. مثلاً:

const order = this.route.snapshot.queryParams['order'];

از طرف دیگر، اشتراک در queryParams به‌عنوان Observable به کامپوننت‌تان اجازه می‌دهد به تغییرات پارامترهای Query حین فعال ماندنش واکنش نشان دهد. در این حالت، Angular کامپوننت را destroy و بازسازی نمی‌کند اگر فقط مقادیر پارامتر Query تغییر کنند. این رویکرد برای رابط‌های داینامیک—مانند فراهم کردن فیلترهای قابل ویرایش توسط کاربر یا محتوای صفحه‌بندی‌شده—ضروری است؛ جایی که می‌خواهید به تغییرات پارامتر همان‌طور که اتفاق می‌افتند پاسخ بدهید. مثلاً:

this.route.queryParams.subscribe(params => {
  this.order = params['order'];
});

خلاصه اینکه، از Snapshot وقتی استفاده کنید که Route همیشه کامپوننت را بازسازی می‌کند (رویکرد ایستا)؛ و از اشتراک Observable اگر کامپوننت ممکن است بین تغییرات URL باقی بماند—تا مطمئن شوید مقادیر پارامترِ به‌روز دارید.

۶. queryParamsHandling: ‘preserve’ در مقابل queryParamsHandling: ‘merge’ چه می‌کند؟

وقتی از queryParamsHandling: 'preserve' استفاده می‌کنید، Angular کل رشته Query فعلی را بدون تغییر حین ناوبری به Route جدید نگه می‌دارد. مثلاً، اگر از /products?order=popular به Route دیگری با گزینه 'preserve' ناوبری کنید، URL برای Route جدید هم پارامتر Query اصلیِ order=popular را شامل می‌شود؛ که به /users?order=popular منجر می‌شود.

از طرف دیگر، queryParamsHandling: 'merge' به Angular دستور می‌دهد پارامترهای Query فعلی را با جدیدهایی که تعیین می‌کنید ترکیب کند. اگر پارامتر جدیدی با کلیدی مشترک با موجودی تأمین کنید، مقدار جدید جایگزین قدیمی می‌شود. مثلاً، ناوبری از /products?order=popular به /users با queryParams: { filter: 'new' } و queryParamsHandling: 'merge' URL برابر /users?order=popular&filter=new تولید می‌کند.

خلاصه تفاوت:

گزینههمه پارامترهای موجود را نگه می‌دارد؟می‌تواند پارامترها را اضافه یا به‌روزرسانی کند؟مورد استفاده معمول
preserveبلهخیرنگه داشتن کل زمینه هنگام جابه‌جایی بین صفحات
mergeبله (فقط اگر کلیدها همپوشان باشند جایگزین می‌شوند)بله، کلیدهای جدید یا موجود قابل تنظیم‌اندافزودن پارامترهای جدید یا به‌روزرسانی فقط کلیدهای خاصی هنگام ناوبری کاربر

۷. چطور مقدار پارامتر Query خاصی را در کامپوننت Angular بخوانم؟

برای خواندن مقدار پارامتر Query خاصی در کامپوننت Angular، بسته به الزامات و نسخه Angularتان چند گزینه دارید:

اگر می‌خواهید کامپوننت‌تان به تغییرات پارامترهای Query همان‌طور که اتفاق می‌افتند واکنش نشان دهد، می‌توانید در Observable مربوط به ActivatedRoute.queryParamMap مشترک شوید. این رویکرد مقاوم‌ترین است و تضمین می‌کند هر وقت پارامترهای Query تغییر کنند به‌روزرسانی دریافت کنید. مثلاً:

this.route.queryParamMap.subscribe(params => {
  const value = params.get('order'); // مقدار رشته‌ای یا null اگر پارامتر مفقود باشد
});

اگر فقط لازم است یک‌بار حین مقداردهی اولیه کامپوننت به مقدار پارامتر Query دسترسی پیدا کنید، می‌توانید از ActivatedRoute.snapshot.queryParamMap بخوانید. این روش مقدار را در لحظه ساخته شدن کامپوننت ثبت می‌کند:

const value = this.route.snapshot.queryParamMap.get('order');

برای اپلیکیشن‌هایی که از Angular 16 یا جدیدتر استفاده می‌کنند و با کامپوننت‌های Standaloneِ فعال‌شده با withComponentInputBinding()، Angular می‌تواند مقادیر پارامترهای Query را خودکار به ویژگی‌های Input کامپوننت اختصاص دهد. مثلاً:

@Input() order: string | undefined;

در این حالت، Angular Input مربوط به order را هر وقت پارامتر Query متناظر در URL تغییر کند به‌روز می‌کند.

دقت کنید که شیء خام queryParams برای کلیدهای مفقود undefined برمی‌گرداند؛ در حالی که queryParamMap.get() برمی‌گرداند. همیشه برای هر دو چک بگذارید یا از عملگر ترکیب nullish یعنی ?? استفاده کنید.

۸. آیا پارامترهای Query می‌توانند در Angular باعث عدم تطبیق Route یا شکست ناوبری شوند؟

نه، پارامترهای Query بر اینکه Angular کدام Route را تطبیق می‌دهد اثر نمی‌گذارند. Angular صرفاً به بخش مسیر URL برای تعیین و فعال کردن Route متکی است؛ در حالی که هر پارامتر Query موجود در URL (مثلاً ?key=value) حین فرایند تطبیق Route نادیده گرفته می‌شود.

در نتیجه، Angular همان Route را برای URLهایی مثل /products، /products?order=popular یا /products?foo=bar&baz=qux تطبیق می‌دهد. حضور یا غیاب پارامترهای Query هیچ تفاوتی در نحوه انتخاب و فعال کردن Route توسط فریم‌ورک ایجاد نمی‌کند.

اما مسئولیت توسعه‌دهنده است که مواردی را که پارامترهای Query ممکن است مفقود یا روی مقادیر غیرمنتظره تنظیم شده باشند درون منطق کامپوننت مدیریت کند. همیشه باید چک کنید که پارامتر Query موجود است (یعنی null یا undefined نیست) قبل از استفاده از مقدارش؛ تا از خطاهای احتمالی زمان اجرا یا رفتار نادرست اپلیکیشن اجتناب شود.

مثلاً، می‌توانید پارامتر را به این شکل امن چک کنید:

const value = this.route.snapshot.queryParamMap.get('order');
if (value !== null) {
  // از مقدار استفاده کن
}

پیروی از این الگو تضمین می‌کند کدتان مواردی را که پارامتر Query اختیاری یا غایب است با ظرافت مدیریت کند.

نتیجه‌گیری

در این آموزش، از queryParams و queryParamsHandling با هر دوی Router.navigate و RouterLink برای تنظیم و کنترل پارامترهای Query استفاده کردید؛ و مقادیر پارامتر را با ActivatedRoute.snapshot، Observable مربوط به queryParams و queryParamMap خواندید. هم‌چنین دیدید چطور withComponentInputBinding() مربوط به Angular 16+ مسیر خواندن را برای کامپوننت‌های Standalone ساده می‌کند؛ و toSignal() پارامترهای Query را با سیستم Signal مربوط به Angular در 16+ یکپارچه می‌کند.

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا