آموزش جامع Angular Templates

به نام خدا. در این آموزش قصد دارم آموزش جامعی از Angular Templates که شامل مباحثی در مورد ng-template، ng-container و ngTemplateOutlet هست ارائه دهم.

قالببندی در Angular یا همان Angular Templates یکی از مباحث پیشرفته در انگولار است. احتمالا شما تا کنون از directiveهای مربوط به ng-template نظیر ngIf و ngSwitch استفاده کرده اید. ng-template و دایرکتیو ngTemplateOutlet یکی از قدرتمندترین ویژگی های انگولار در است که کاربردهای بسیاری نیز دارد.

برای شروع باید ابتدا یک پروژه ی جدید با Angular 8 ایجاد کنید. بدین منظور می توانید از آموزش زیر استفاده کنید:

معرفی ng-template

همانطور که از نام آن مشخص است ng-template برای قالبندی را در انگولار استفاده می شود یعنی محتوای تگ ng-template بخشی از قالب سایت یا بهتر است بگویم بخشی از HTML یک کامپوننت است. انگولار در پسزمینه از این تگ برای بسیاری از دایرکتیوهای خود نظیر ngIf ، ngFor و ngSwitch استفاده می کند.

بیایید با یک مثال شروع کنیم. در کد زیر از ng-template و دو دکمه برای قالبندی صفحه استفاده کرده ایم:

@Component({
  selector: 'app-root',
  template: `      
      <ng-template>
          <button class="tab-button" 
                  (click)="login()">{{loginText}}</button>
          <button class="tab-button" 
                  (click)="signUp()">{{signUpText}}</button>
      </ng-template>
  `})
export class AppComponent {
    loginText = 'Login';
    signUpText = 'Sign Up'; 
    lessons = ['Lesson 1', 'Lessons 2'];

    login() {
        console.log('Login');
    }

    signUp() {
        console.log('Sign Up');
    }
}

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

این خروجی کاملا طبیعی است و همان چیزی است که انتظارش را داشتیم! دلیل آن هم این است که ما تگ ng-template را در کدهای خود تعریف کرده ایم ولی از آن استفاده نکرده ایم!! بیایید این مطلب را با یک مثال بررسی کنیم.

استفاده از ng-template و ngIf else

احتمالا مثال زیر یکی از پایه ای ترین کاربردهای ng-template باشد. بیایید اول کد را مشاهد کنیم سپس در مورد آن توضیح می دهم:

<div class="lessons-list" *ngIf="lessons else loading">
  ... 
</div>

<ng-template #loading>
    <div>Loading...</div>
</ng-template>

در این مثال در صورتی که مقدار متغیر lessons برابر true باشد تگ div مربوطه رندر می شود و در غیر این صورت تگ ng-template که با ارجاع loading مشخص شده است رندر می شود و خروجی آن در صفحه نشان داده می شود. چون ما در اینجا با استفاده از یک ارجاع با نام loading از تگ ng-template علاوه بر تعریف کردن استفاده هم کرده ایم، خروجی آن در صفحه نشان داده می شود.

استفاده ی پویا از قالبندی ها با کمک ngTemplateOutlet

ما می توانیم با استفاده از دایرکتیو ngTemplateOutlet از یک قالبندی در جاهای مختلف کد خود و به دفعات استفاده کنیم. برای این کار همان template با ارجاع loading که در کد فوق تعریف شده است را مورد استفاده قرار می دهیم. برای استفاده از این template در بخش های مختلف کد خود می توانیم از ngTemplateOutlet همانند مثال زیر کمک بگیریم:

<ng-container *ngTemplateOutlet="loading"></ng-container>

داده های اختصاصی مربوط به یک template

هر template می تواند از تمام متغییرهای مربوط به class یک کامپوننت همانند سایر تگ های html با کمک روش های bindig مختلف استفاده کند ولی ویژگی جالب دیگری که ng-template دارد این است که می تواند داده های مربوط به خود را داشته باشد که فقط در محدوده ی آن قابل دسترس است. به مثال زیر دقت کنید:

@Component({
  selector: 'app-root',
  template: `      
<ng-template #estimateTemplate let-lessonsCounter="estimate">
    <div> Approximately {{lessonsCounter}} lessons ...</div>
</ng-template>
<ng-container 
   *ngTemplateOutlet="estimateTemplate;context:ctx">
</ng-container>
`})
export class AppComponent {

    totalEstimate = 10;
    ctx = {estimate: this.totalEstimate};
  
}

در این مثال یک context یا بهتر است بگویم object با نام ctx تعریف شده است و در هنگام استفاده از ng-template با کمک ngTemplateOutlet این context به template داده شده است. در تمپلیت مورد نظر با کمک دستور let-lessonsCounter یک متغییر محلی با عنوان let-lessonsCounter تعریف شده و مقدار آن را برابر estimate که در ctx وجود دارد قرار دادیم و از آن درون template استفاده کردیم.

جابه جایی templateها بین کامپوننت های مختلف

ویژگی جالب دیگری که ng-template دارد این است که می توان آن را به از یک کامپوننت به کامپوننت دیگری ارسال کرد و همانند یک متغیر inject شده توسط @input آن را در component مقصد دریافت کرد. همچنین می توانیم آن را توسط ViewChild به صورت پویا در کد خود دریافت و از آن همانند یک متغییر استفاده کنیم. ابتدا بیایید این مسئله را به صورت یک مثال بررسی کنیم:

@Component({
  selector: 'app-root',
  template: `      
      <ng-template #defaultTabButtons>
          <button class="tab-button" (click)="login()">
            {{loginText}}
          </button>
          <button class="tab-button" (click)="signUp()">
            {{signUpText}}
          </button>
      </ng-template>
`})
export class AppComponent implements OnInit {

  @ViewChild('defaultTabButtons', { static: true })
  private defaultTabButtonsTpl: TemplateRef<any>;

    ngOnInit() {
        console.log(this.defaultTabButtonsTpl);
    }

}

حال به سراغ مثالی برای ارسال یک template از یک component به دیگری برویم. کد زیر کامپوننت مبدا را نشان می دهد:

@Component({
  selector: 'app-root',
  template: `      
<ng-template #customTabButtons>
    <div class="custom-class">
        <button class="tab-button" (click)="login()">
          {{loginText}}
        </button>
        <button class="tab-button" (click)="signUp()">
          {{signUpText}}
        </button>
    </div>
</ng-template>
<tab-container [headerTemplate]="customTabButtons"></tab-container>      
`})
export class AppComponent implements OnInit {

}

همانطور که در این کد مشاهده می فرمایید، تگ ng-template که با ارجاع customTabButtons مشخص شده است به ورودی headerTemplate مربوط به کامپوننت tab-container داده شده است. حال به سراغ کد مربوط به کامپوننت tab-container برویم:

@Component({
    selector: 'tab-container',
    template: `
    
<ng-template #defaultTabButtons>
    
    <div class="default-tab-buttons">
        ...
    </div>
    
</ng-template>
<ng-container 
  *ngTemplateOutlet="headerTemplate ? headerTemplate: defaultTabButtons">
    
</ng-container>
... rest of tab container component ...
`})
export class TabContainerComponent {
    @Input()
    headerTemplate: TemplateRef<any>;
}

در این کامپوننت که مقصد template ما می باشد ابتدا با استفاده از @Input تمپلیت را از ورودی گرفته ایم و سپس در کد خود با کمک ngTemplateOutlet استفاده کرده ایم. با استفاده از این قابلیت می توانید ظاهرهای مختلفی را متناسب با نظر کاربر ایجاد کنید و ظاهر پیش فرضی را نیز برای کامپوننت خود در نظر بگیرید…

بسیار عالی. امیدوارم این آموزش برای شما مفید باشد. با پیوستن به کانال تلگرامی ما به آدرس https://t.me/angular_netcore از آخرین آموزش ها و اخبار مطلع شوید.

اگر سوالی داشتید لطفا آن را در بخش دیدگاه های همین پست مطرح بفرمایید.

موفق باشید. التماس دعا

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

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