تایپاسکریپت - چگونه دادهها را به کامپوننتهای مسیریابی شدهی Angular منتقل کنم؟


در یکی از قالبهای مسیرهای Angular 2 من (FirstComponent) یک دکمه دارم

first.component.html

<div class="button" click="routeWithData()">Pass data and route</div>

هدف من این است که به دست آورم:

کلیک روی دکمه -> هدایت به یک کامپوننت دیگر در حالی که دادهها حفظ میشوند و بدون استفاده از آن کامپوننت به عنوان یک دایرکتیو.

این چیزی است که من امتحان کردم...

اولین رویکرد

در همان دیدگاه، من دادههای مشابه را بر اساس تعامل کاربر ذخیره و جمعآوری میکنم.

first.component.ts

export class FirstComponent {
     constructor(private _router: Router) { }

     property1: number;
     property2: string;
     property3: TypeXY; // this a class, not a primitive type

    // here some class methods set the properties above

    // DOM events
    routeWithData(){
         // here route
    }
}

به طور معمول من به SecondComponent هدایت میشوم با

 this._router.navigate(['SecondComponent']);

در نهایت دادهها را منتقل کردن

 this._router.navigate(['SecondComponent', {p1: this.property1, p2: property2 }]);

در حالی که تعریف لینک با پارامترها اینگونه خواهد بود

@RouteConfig([
      // ...
      { path: '/SecondComponent/:p1:p2', name: 'SecondComponent', component: SecondComponent} 
)]

مشکل این روش این است که حدس میزنم نمیتوانم دادههای پیچیده (مثلاً یک شیء مانند property3) را در URL منتقل کنم؛

روش دوم

یک گزینه جایگزین میتواند شامل کردن SecondComponent به عنوان دایرکتیو در FirstComponent باشد.

  <SecondComponent [p3]="property3"></SecondComponent>

با این حال من میخواهم به آن کامپوننت مسیر یابی کنم، نه اینکه آن را شامل کنم!

روش سوم

قابل اجراترین راهحلی که در اینجا میبینم استفاده از یک سرویس (برای مثال FirstComponentService) برای

  • ذخیره کنید دادهها (_firstComponentService.storeData()) در routeWithData() در FirstComponent
  • دادهها را (_firstComponentService.retrieveData()) در ngOnInit() در SecondComponent بازیابی کنید

در حالی که این رویکرد به نظر کاملاً قابل استفاده میرسد، من تعجب میکنم که آیا این آسانترین یا زیباترین روش برای رسیدن به هدف است یا خیر.

به طور کلی میخواهم بدانم آیا روشهای پتانسیل دیگری برای انتقال داده بین کامپوننتها وجود دارد که من از آنها غافل شدهام، بهویژه با کمترین میزان کد ممکن

پاسخ شماره ۱

بهروزرسانی ۴.۰.۰

برای جزئیات بیشتر به Angular Angular Router - واکشی دادهها قبل از ناوبری مراجعه کنید.

اصلی

استفاده از یک سرویس راهی است که باید پیش بروید. در پارامترهای مسیر شما تنها باید دادههایی را ارسال کنید که میخواهید در نوار URL مرورگر نمایش داده شوند.

کتاب آشپزی Angular بخش ارتباطات کامپوننت - سرویس دوطرفه.

روتری که با RC.4 ارسال شد، data را دوباره معرفی میکند

constructor(private route: ActivatedRoute) {}
const routes: RouterConfig = [
  {path: '', redirectTo: '/heroes', pathMatch: 'full'},
  {path: 'heroes', component: HeroDetailComponent, data: {some_data: 'some value'}}
];
class HeroDetailComponent {
  ngOnInit() {
    this.sub = this.route
      .data
      .subscribe(v => console.log(v));
  }

  ngOnDestroy() {
    this.sub.unsubscribe();
  }
}

همچنین به Plunker مراجعه کنید.

پاسخ شماره ۲

Angular 7.2.0 روش جدیدی برای ارسال دادهها هنگام حرکت بین کامپوننتهای مسیریابی شده معرفی کرد:

@Component({
  template: `<a (click)="navigateWithState()">Go</a>`,
})
export class AppComponent  {
  constructor(public router: Router) {}
  navigateWithState() {
    this.router.navigateByUrl('/123', { state: { hello: 'world' } });
  }
}

یا :

@Component({
  selector: 'my-app',
  template: `
  <a routerLink="/details" [state]="{ hello: 'world' }">Go</a>`,
})
export class AppComponent  {}

برای خواندن وضعیت، میتوانید پس از اتمام ناوبری به ویژگی window.history.state دسترسی پیدا کنید:

export class PageComponent implements OnInit {
  state$: Observable<object>;

  constructor(public activatedRoute: ActivatedRoute) {}

  ngOnInit() {
    this.state$ = this.activatedRoute.paramMap
      .pipe(map(() => window.history.state))
  }
}

پاسخ شماره ۳

من فکر میکنم که از آنجا که ما چیزی مثل $rootScope در Angular 2 نداریم همانطور که در Angular 1.x داشتیم، میتوانیم از یک سرویس/کلاس مشترک Angular 2 استفاده کنیم، در حالی که دادهها را در ngOnDestroy به سرویس منتقل میکنیم و سپس دادهها را از سرویس در تابع ngOnInit پس از مسیریابی دریافت میکنیم:

اینجا من از DataService برای به اشتراک گذاری شیء قهرمان استفاده میکنم:

import { Hero } from './hero';
export class DataService {
  public hero: Hero;
}

ارسال شیء از کامپوننت صفحه اول:

 ngOnDestroy() {
    this.dataService.hero = this.hero; 
 }

گرفتن شیء از مؤلفه صفحه دوم:

 ngOnInit() {
    this.hero = this.dataService.hero; 
 }

در اینجا یک مثال است: plunker

پاسخ شماره ۴

<div class="button" click="routeWithData()">Pass data and route</div>

خب، سادهترین راه برای انجام این کار در Angular 6 یا نسخههای دیگر، امیدوارم، به سادگی تعریف مسیر خود با مقدار دادهای باشد که میخواهید منتقل کنید.

{path: 'detailView/:id', component: DetailedViewComponent}

همانطور که از تعریف مسیرهای من میبینید، من /:id را اضافه کردهام تا دادهای که میخواهم از طریق مسیریابی روتر به کامپوننت منتقل کنم، منتقل شود. بنابراین کد شما به شکل زیر خواهد بود

<a class="btn btn-white-view" [routerLink]="[ '/detailView',list.id]">view</a>

برای خواندن id روی کامپوننت، کافی است ActivatedRoute را مانند زیر وارد کنید

import { ActivatedRoute } from '@angular/router'

و در ngOnInit جایی است که دادهها را بازیابی میکنید

ngOnInit() {
       this.sub = this.route.params.subscribe(params => {
        this.id = params['id'];
        });
        console.log(this.id);
      }

شما میتوانید بیشتر در این مقاله بخوانید https://www.tektutorialshub.com/angular-passing-parameters-to-route/

پاسخ شماره ۵

من به هر راهحلی که در این صفحه بود نگاهی انداختم (و چند مورد را هم امتحان کردم) اما قانع نشدم که ما باید به نوعی یک روش هکمانند را برای انتقال داده بین مسیرها پیادهسازی کنیم.

یک مشکل دیگر با history.state ساده این است که اگر شما یک نمونه از یک کلاس خاص را در شیء state ارسال کنید، هنگام دریافت آن، آن نمونه نخواهد بود. بلکه یک شیء ساده و معمولی جاوااسکریپت خواهد بود.

بنابراین در برنامه Angular v10 (Ionic v5) خود، این کار را انجام دادم-

this.router.navigateByUrl('/authenticate/username', {
    state: {user: new User(), foo: 'bar'}
});

و در کامپوننت مسیریابی ('/authenticate/username')، در متد ngOnInit()، دادهها را با this.router.getCurrentNavigation().extras.state چاپ کردم-

ngOnInit() {
    console.log('>>authenticate-username:41:',
        this.router.getCurrentNavigation().extras.state);
}

و من دادهٔ موردنظر که منتقل شده بود را گرفتم

پاسخ شماره ۶

سال ۲۰۱۹ است و بسیاری از پاسخهای اینجا کار خواهند کرد، بسته به اینکه چه میخواهید انجام دهید. اگر میخواهید مقداری وضعیت داخلی که در URL (پارامترها، کوئری) قابل مشاهده نیست را ارسال کنید، میتوانید از state استفاده کنید از نسخه ۷.۲ (همانطور که من همین امروز یاد گرفتم :) ).

از وبلاگ (با تشکر از توماش كولا) - شما به مسیر ... هدایت میشوید

...از ts: this.router.navigateByUrl('/details', { state: { hello: 'world' } });

...از قالب HTML: <a routerLink="/details" [state]="{ hello: 'world' }">برو</a>

و برای برداشتن آن در مؤلفه مقصد:

constructor(public activatedRoute: ActivatedRoute) {}

  ngOnInit() {
    this.state$ = this.activatedRoute.paramMap
      .pipe(map(() => window.history.state))
  }

دیر ولی امیدوارم این به کسی که تازه با انگولار کار میکند کمک کند.

پاسخ شماره ۷

من فکر میکنم رویکرد دیگر برای این مسئله مناسب نیست. به نظر من بهترین رویکرد پارامتر پرسوجو توسط Router انگولار است که دو روش دارد:

ارسال مستقیم پارامتر پرسوجو

با این کد میتوانید با استفاده از params به url در کد HTML خود بروید:

<a [routerLink]="['customer-service']" [queryParams]="{ serviceId: 99 }"></a>

ارسال پارامتر پرس و جو با Router

شما باید روتر را در داخل constructor خود مانند این تزریق کنید:

constructor(private router:Router){

}

حالا استفاده از آن مثل:

goToPage(pageNum) {
    this.router.navigate(['/product-list'], { queryParams: { serviceId: serviceId} });
}

حال اگر میخواهید از Router در یک Component دیگر بخوانید، باید از ActivatedRoute استفاده کنید مانند:

constructor(private activateRouter:ActivatedRouter){

}

و subscribe که:

  ngOnInit() {
    this.sub = this.route
      .queryParams
      .subscribe(params => {
        // Defaults to 0 if no query param provided.
        this.page = +params['serviceId'] || 0;
      });
  }

پاسخ شماره ۸

یک نفر فوقالعاده باهوش (tmburnell) که من نیستم پیشنهاد میکند دادههای مسیر را بازنویسی کنیم:

let route = this.router.config.find(r => r.path === '/path');
route.data = { entity: 'entity' };
this.router.navigateByUrl('/path');

همانطور که اینجا در نظرات دیده میشود.

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

پاسخ شماره ۹

راهحل با ActiveRoute (اگر میخواهید شیء را از طریق مسیر منتقل کنید - از JSON.stringify/JSON.parse استفاده کنید):

آمادهسازی شی قبل از ارسال:

export class AdminUserListComponent {

  users : User[];

  constructor( private router : Router) { }

  modifyUser(i) {

    let navigationExtras: NavigationExtras = {
      queryParams: {
          "user": JSON.stringify(this.users[i])
      }
    };

    this.router.navigate(["admin/user/edit"],  navigationExtras);
  }

}

دریافت شیء خود در مؤلفه مقصد:

export class AdminUserEditComponent  {

  userWithRole: UserWithRole;      

  constructor( private route: ActivatedRoute) {}

  ngOnInit(): void {
    super.ngOnInit();

      this.route.queryParams.subscribe(params => {
        this.userWithRole.user = JSON.parse(params["user"]);
      });
  }

}

پاسخ شماره ۱۰

مسیرها :

{ path: 'foo-route', component: FooComponent, data: { myData: false } },

در کامپوننت یک بار به شیء دادهها دسترسی پیدا کنید:

pipe(take(1)) بلافاصله لغو اشتراک میکند بنابراین هیچ نشت حافظهای وجود ندارد و نیازی به لغو اشتراک دستی نیست

constructor(private activatedRoute: ActivatedRoute) { ... }

ngOnInit(): void {
  this.activatedRoute.data.pipe(take(1)).subscribe((data) => {
    console.log(data); // do something with the data
  });
}
  • به یاد داشته باش موارد لازم را وارد کنی

ویرایش: firstValueFrom() جدید میتواند بهتر باشد