مسیریابی (Routing) در انگولار

24 تیر 1396
angular-routing

با مطالعه‌ی فصل‌های گذشته تا سطح نیمه‌حرفه‌ای با فریم‌ورک قدرتمند انگولار آشنا شدید و تا به اینجای کار نیمه بیشتر مسیر را طی نموده‌اید. اما هنوز تا تکمیل سایر مباحث انگولار مسیرهای دیگری باقی‌ ست که باید طی کنیم. یکی از این مباحث که بسیار ارزشمند و قابل تامل است، مبحث مسیردهی یا Routing می‌باشد. در ادامه به توضیح این موضوع خواهیم پرداخت با ما همراه باشید.

مسیردهی (Routing) در انگولار چیست؟

هنگامیکه شما در حال تولید یک نرم‌افزار تک صفحه‌ای (Single Page App) هستید همواره نرم‌افزار خود را به سمتی سوق می‌دهید که کاربر با کلیک کردن روی لینک‌های مختلف بدون لود کردن و بارگذاری مجدد صفحه، بتواند به لینک موردنظر انتقال پیدا کند.

حال فرض کنید وب سایت یا نرم‌افزار شما دارای منوهایی است که کاربر با کلیک روی آنها به هر صفحه منتقل می‌شود و این انتقال در حالی انجام خواهد شد که رفرش یا بارگذاری مجددی صورت نمی‌گیرد. مثلا الان کاربر در آدرس http://www.roxo.ir قرار دارد و با کلیک روی لینک تماس با ما به صفحه http://www.roxo.ir/contact-us می‌رود. این مسیردهی به آدرس وب سایت را Routing می‌گویند.

حال انگولار امکانات و ابزاری را برای شما فراهم می‌کند که به سادگی بتوانید بدون بارگذاری مجدد صفحه، مسیردهی را انجام داده و کاربر را به هدف موردنظر خود منتقل کنید.

برای شروع آموزش این فصل ابتدا فایل پیوست شده در انتهای این فصل را دریافت کرده که توسط مجموعه روکسو ایجاد شده است و شامل یک صفحه مبتنی بر مدیریت سرور می‌باشد.

هدف از ارائه‌ی این مثال و کدها جلوگیری از کدنویسی اضافی و کوتاه کردن آموزش و در نهایت پرداختن به اصل موضوع مسیردهی (Routing) است. بنابراین اگر فایل پیوست شده را به درستی دانلود و روی سیستم خود اجرا کرده باشید با صفحه زیر روبه‌رو خواهید شد:

پروژه مدیریت سرور و مسیریابی در انگولار

حال مسیردهی (Routing) نرم‌افزار خود را انجام خواهیم داد.

تعریف مسیردهی (Routing) در انگولار

برای تعریف مسیردهی در نرم‌افزار خود ابتدا وارد فایل app.module.ts‌ شده و در ابتدای این صفحه یک ثابت به نام appRoutes ایجاد می‌کنیم تا تمام مسیردهی‌های نرم‌افزار خود را درون آن انجام دهیم. بنابراین داریم:

const appRoutes: Routes = [
  {path: '', component: HomeComponent},
  {path: 'users', component: UsersComponent},
  {path: 'servers', component: ServersComponent}
];

همانطور که مشخص است در ثابت appRoutes که از نوع کلاس Route‌ می‌باشد یک آرایه ایجاد (علت ایجاد آرایه برای دارا بودن چندین مسیر برای یک نرم‌افزار است) و سپس درون آن اشیاء جاوا اسکریپت را با علامت { } تولید کرده‌ایم.

اگر توجه داشته باشید درون این دو کروشه یک کلمه تحت عنوان path و دیگری با نام component وجود دارد:

کلمه‌کلیدی path: این کلمه برای نشان دادن مسیر صفحه می‌باشد. به عنوان مثال users به مسیر http://localhost:4200/users اشاره می‌کند.

کلمه‌کلیدی component: از این کلمه برای تعریف کامپوننت مرتبط با مسیر استفاده می‌شود به عنوان مثال کامپوننت مرتبط با مسیر http://localhost:4200/users معادل UsersComponent‌ است که لیست کاربران را نمایش می‌دهد.

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

برای معرفی کردن باید از کلاس RouterModule استفاده کرده و با متد forRoot مسیر موردنظر را مشابه ذیل به نرم‌افزار معرفی کنیم:

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';

import { AppComponent } from './app.component';
import { HomeComponent } from './home/home.component';
import { UsersComponent } from './users/users.component';
import { ServersComponent } from './servers/servers.component';
import { UserComponent } from './users/user/user.component';
import { EditServerComponent } from './servers/edit-server/edit-server.component';
import { ServerComponent } from './servers/server/server.component';
import { ServersService } from './servers/servers.service';
import {RouterModule, Routes} from "@angular/router";

const appRoutes: Routes = [
  {path: '', component: HomeComponent},
  {path: 'users', component: UsersComponent},
  {path: 'servers', component: ServersComponent}
];

@NgModule({
  declarations: [
    AppComponent,
    HomeComponent,
    UsersComponent,
    ServersComponent,
    UserComponent,
    EditServerComponent,
    ServerComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    HttpModule,
    RouterModule.forRoot(appRoutes)
  ],
  providers: [ServersService],
  bootstrap: [AppComponent]
})
export class AppModule { }

همانطور که ملاحظه کردید تغییرات کلی در این فایل به صورت فوق اعمال شده است.

حال باید فایل app.component.html‌ را باز کنید و در نهایت به جای اسامی کامپوننت‌ها که به صورت تگ app-component‌ هستند یک ساختار جامع به نام router-outlet قرار دهیم تا به قالب HTML اطلاع دهیم که مسیرهای ما مشخص هستند و دیگر تمام کامپوننت‌ها را در یک صفحه لود نکن و متناسب با هر مسیری اطلاعات کامپوننت را نمایش بده! بنابراین در این فایل داریم:

<div class="container">
    <div class="row">
        <div class="col-xs-12 col-sm-10 col-md-8 col-sm-offset-1 col-md-offset-2">
            <ul class="nav nav-tabs">
                <li role="presentation" class="active"><a href="#">صفحه اصلی</a></li>
                <li role="presentation"><a href="#">سرورها</a></li>
                <li role="presentation"><a href="#">کابران</a></li>
            </ul>
        </div>
    </div>
    <div class="row">
        <div class="col-xs-12 col-sm-10 col-md-8 col-sm-offset-1 col-md-offset-2">
            <router-outlet></router-outlet>
        </div>
    </div>
</div>

با انجام این تغییر ملاحظه خواهید کرد که در صفحه نخست یعنی http://localhost:4200 تنها کامپوننت home فراخوانی می‌شود.

حال اگر در مرورگر خود آدرس http://localhost:4200/users را بزنید اطلاعات کامپوننت users و در نهایت با وارد کردن آدرس http://localhost:4200/servers اطلاعات کامپوننت servers را دریافت خواهید کرد.

بسیار عالی بنابراین خروجی تصویر ما به صورت زیر است:

اعمال router-outlet به قالب HTML

مسیریابی بین مسیرها (Navigation)

اگر مثال قبلی را بررسی کرده باشید وقتی روی زبانه‌های کاربران و سرور کلیک می‌کنیم اتفاقی نمی‌افتد. بنابراین باید به آنها مسیر مورد نظر را معرفی کنیم.

برای اینکار به جای استفاده از عبارت href از یک دستور به نام routerLink استفاده خواهیم کرد که عبارت روبه‌روی آن برابر مسیری‌ست که دوست داریم کاربر به آن بدون بارگذاری مجدد صفحه انتقال پیدا کند.

بنابراین فایل app.component.html را به صورت زیر ویرایش خواهیم کرد:

<div class="container">
    <div class="row">
        <div class="col-xs-12 col-sm-10 col-md-8 col-sm-offset-1 col-md-offset-2">
            <ul class="nav nav-tabs">
                <li role="presentation" class="active"><a routerLink="/">صفحه اصلی</a></li>
                <li role="presentation"><a routerLink="/servers">سرورها</a></li>
                <li role="presentation"><a [routerLink]="'/users'">کابران</a></li>
            </ul>
        </div>
    </div>
    <div class="row">
        <div class="col-xs-12 col-sm-10 col-md-8 col-sm-offset-1 col-md-offset-2">
            <router-outlet></router-outlet>
        </div>
    </div>
</div>

این سوال در حال حاضر برای شما به وجود آمده است که چرا مسیر سوم (کاربران) از طریق یک ویژگی بایند (ارسال) شده است؟

در پاسخ به این سوال باید خدمت شما عزیزان مطرح کنیم که این یکی دیگر از روش‌های ارسال کاربران صفحات مختلف است که در آن می‌توان آرگومان‌های متغییر به یک مسیر لحاظ کرد که بعدا به توضیح آن می‌پردازیم.

معرفی مسیرها در انگولار

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

مسیر مطلق: به مسیری گفته می‌شود که از روی ریشه‌ی آدرس خوانده می‌شود. به عنوان مثال اگر ریشه‌ی آدرس ما به صورت http://localhost:4200 باشد آنگاه مسیر زیر:

routerLink = "users"

یک مسیر مطلق نسبت به ریشه سایت (http://localhost:4200) است و با کلیک روی لینکی که این مسیردهی را انجام داده است، مسیر زیر را مشاهده خواهید کرد:

http://localhost:4200/users

مسیر نسبی: به مسیری گفته می‌شود که نسبت به مسیری که در آن قرار دارد آدرس دهی می‌شود. مثلا اگر مسیری که الان در آن قرار داریم به صورت http://localhost:4200/users باشد و بخواهیم صفت router-link را به صورت زیر تعریف کنیم:

router-link = "/profile"

یک مسیر نسبی تعریف کرده‌ایم و با کلیک روی این لینک کاربر به آدرس زیر منتقل می‌شود:

http://localhost:4200/users/profile

مسیر نسبی با بازگشت: این مورد دقیقا مشابه حالت قبل است اما یک مرحله مسیر را به عقب باز می‌گرداند. بنابراین اگر مسیری که در آن قرار داریم به صورت http://localhost:4200 باشد و صفت router-link را به صورت زیر تعریف کرده باشیم:

router-link = "../profile"

آنگاه کاربر به آدرس زیر منتقل می‌شود:

http://localhost:4200/profile

زیرا ابتدا یک مرحله به عقب باز می‌گردد و در نهایت عبارت profile‌ را در مسیر قرار می‌دهد.

دستور routerLinkActive و routerLinkActiveOption

اگر فایل app.component.html‌ را بررسی بفرمایید متوجه خواهید شد که وقتی زبانه‌ی «صفحه اصلی» فعال است و ما روی صفحه‌ی «سرورها» یا «کاربران» کلیک می‌کنیم همچنان استایل زبانه‌ی «صفحه اصلی» فعال باقی مانده‌ است. بنابراین برای انتقال دادن استایل active به سایر زبانه‌ها از دستور routerLinkActive استفاده می‌کنیم. اما با اعمال این دستور نیز به هنگام انتقال به صفحات دیگر اگرچه استایل active بین آنها تغییر می‌کند اما «صفحه اصلی» همیشه به صورت ثابت این استایل را دارد زیرا همواره مسیریاب انگولار آن را به عنوان root می‌شناسد.

برای جلوگیری این ابهام از دستور routerLinkActiveOption استفاده می‌کنیم. بدین صورت که درون آن یک شیء از جاوا اسکریپت قرار داده و مقدار exact را برابر true قرار خواهیم داد.

این امر بدین معنی‌ست که دقیقا آدرس‌ مورد نظر را که تنها شامل اسلش (/) است به هنگامیکه روی آن قرار نگرفته‌ایم خالی از استایل کن! بنابراین برای اعمال این تغییرات در فایل app.component.html‌ داریم:

<div class="container">
    <div class="row">
        <div class="col-xs-12 col-sm-10 col-md-8 col-sm-offset-1 col-md-offset-2">
            <ul class="nav nav-tabs">
                <li role="presentation" routerLinkActive="active" [routerLinkActiveOptions]="{exact: true}">
                    <a routerLink="/">صفحه اصلی</a>
                </li>
                <li role="presentation" routerLinkActive="active"><a routerLink="/servers">سرورها</a></li>
                <li role="presentation" routerLinkActive="active"><a [routerLink]="'/users'">کابران</a></li>
            </ul>
        </div>
    </div>
    <div class="row">
        <div class="col-xs-12 col-sm-10 col-md-8 col-sm-offset-1 col-md-offset-2">
            <router-outlet></router-outlet>
        </div>
    </div>
</div>

همینطور که ملاحظه می‌کنید با تغییر مسیر بین زبانه‌های مختلف استایل active مختص آن زبانه‌ فعال می‌شود.

گاهی نیاز داریم که در صفحه اصلی دکمه‌ یا لینکی قرار دهیم که با کلیک روی آن از طریق یک متد رویداد یا event به مسیر موردنظر انتقال پیدا کنیم. در این حالت باید از متد navigate و کلاس Router‌ استفاده کنیم.

بنابراین فایل home.component.html را باز کرده و درون آن یک دکمه به نام بارگذاری سرور قرار می‌دهیم:

<h4>به نرم افزار مدیریت سرور خوش آمدید</h4>
<p>در این بخش کاربران و سرورها را کنترل می کنید</p>
<button class="btn btn-primary" (click)="onLoadServer()">بارگذاری سرور</button>

حال برای تعریف متد onLoadServer فایل home.component.ts را باز کرده و سپس متد navigate از کلاس Router را مورد استفاده قرار می‌دهیم:

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

@Component({
  selector: 'app-home',
  templateUrl: './home.component.html',
  styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {

  constructor(private router: Router) { }

  ngOnInit() {
  }
  onLoadServer(){
    this.router.navigate(['/servers']);
  }
}

حال خروجی صفحه نمایش شما به صورت زیر خواهد بود و در صورت کلیک روی دکمه‌ی «بارگذاری سرور» وارد صفحه سرور می‌شوید.

اضافه کردن دکمه برای انتقال بین صفحات

حال فرض کنید می‌خواهیم یک دکمه در یکی از صفحات (مثلا صفحه «سرورها») قرار دهیم که با کلیک کردن روی آن صفحه مجددا بارگذاری شود. در این حالت می‌توانیم از یکی از قابلیت‌های دیگر فریم ورک انگولار به نام Route‌ استفاده کنیم.

فایل server.component.html‌ را باز کرده و تغییرات زیر را در آن لحاظ می‌کنیم:

<div class="row">
  <button class="btn btn-primary" (click)="onReloadServer()">بارگذاری مجدد سرور</button>
  <div class="col-xs-12 col-sm-4">
    <div class="list-group">
      <a
        href="#"
        class="list-group-item"
        *ngFor="let server of servers">
        {{ server.name }}
      </a>
    </div>
  </div>
  <div class="col-xs-12 col-sm-4">
    <app-edit-server></app-edit-server>
    <hr>
    <app-server></app-server>
  </div>
</div>

سپس درون فایل server.component.ts‌ جهت معرفی متد onReloadServer اقدام کرده و در نهایت با استفاده از کلاس Router و ActivedRouter مسیر دهی روی این لینک را مشخص خواهیم کرد:

import {Component, OnInit} from '@angular/core';
import {ServersService} from './servers.service';
import {ActivatedRoute, Router} from "@angular/router";

@Component({
    selector: 'app-servers',
    templateUrl: './servers.component.html',
    styleUrls: ['./servers.component.css']
})
export class ServersComponent implements OnInit {
    private servers: { id: number, name: string, status: string }[] = [];

    constructor(private serversService: ServersService,
                private router: Router,
                private route: ActivatedRoute) {
    }

    ngOnInit() {
        this.servers = this.serversService.getServers();
    }

    onReloadServer() {
        this.router.navigate(['servers'], {relativeTo: this.route})
    }
}

بسیار عالی! با استفاده از دستور relativeTo می‌توان به متد navigate اطلاع داد که مسیردهی به صورت نسبی از مسیر http://localhost:4200/servers انجام بگیرد.

جهت دانلود فایل ها روی دکمه زیر کلیک کنید.

دانلود

به شما عزیزان تبریک می‌گوییم تا به اینجای توانستید مسیرهای موردنیاز خود را ایجاد کرده و مورد بررسی قرار دهید. در جلسه‌ی آینده مبحث مربوط به مسیردهی را در سطح متوسط بررسی خواهیم کرد. با ما همراه باشید.

توجه: دوستان عزیز آموزش ویدیویی انگولار 6 از مقدماتی تا پیشرفته به زبان فارسی را می‌توانید با کلیک روی اینجا یاد بگیرید.

دوره آموزش انگولار به زبان فارسی + پروژه ساخت فروشگاه اینترنتی

تمام فصل‌های سری ترتیبی که روکسو برای مطالعه‌ی دروس سری آموزش رایگان انگولار توصیه می‌کند:
نویسنده شوید

دیدگاه‌های شما (6 دیدگاه)

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.

سامان
23 مرداد 1399
سلام خسته نباشید. ممنون از اموزش خوبتون. لینک دانلود کدهای این قسمت یه چیز دیگه است و یه برنامه دیگه بجاش دانلود میشه. لطفا اگر امکان داره اصلاح کنید. بازم ممنونم بابت اموزش خوبتون من که خوشم امد

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.

رضا
27 تیر 1399
لینک دانلود از کار افتاده. میشه اصلاح بفرمایید؟

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.

روکسو
29 تیر 1399
سلام وقت شما بخیر لینک های دانلود اصلاح شدند.

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.

علی ظریف
23 بهمن 1398
سلام. توضیحات برای ران کردن فایل ضمیمه خیلی گنگ و مختصر هست.منم در اجراش مشکل داشتم.چرا کسی جواب سوالات رو نمیده؟

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.

angluar
02 شهریور 1398
سلام یه سوال داشتم من میخوام کلا با کلیک کردن روی یک لینک مثلا از homepage کلا صفحه عوض شه بره یه پیچ دیگرو باز کنه؟ این اموزش رو کار کردم ولی اون چیزی که میخواستم نیست میشه راهنمایی کنید؟

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.

zahra
25 اسفند 1398
رویداد ها رو بخونید )Click)

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.

سید قاسم
23 اردیبهشت 1398
سلام من پروژه رو دانلود کردم اما فقط محتویات پوشه src هستن پوشه های دیگه مثل e2e و غیره رو نداره فایل های angular.json package.json و... هم نداره چجور باید درست کنم؟

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.

فرزاد
22 اسفند 1396
سلام وقت بخیر من این فایل رو دانلود کردم ولی نمیتونم ران کنم ممکنه راهنمایی بفرمایید؟ میگه که فایل package.json رو نداری

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.

فرشاد
28 فروردین 1397
سلام لطفاً package.json را ارسال نماییید.

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.

mr.Farzad
04 مهر 1398
سلام وقت بخیر من پروژه رو دانلود کردم ولی نمیتونم ران کنم میشه کمکم کنین؟

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.