انقیاد خصوصیت ها در angular 2
Template Syntax در AngularJs 2.0
Contents
- Get to know our basic Angular TabsComponent (in master branch here)
- Declare a template within a template using
ng-template
in Angular - Pass a reference of an ng-template to a component and render it in Angular
- Pass data to be rendered in a dynamic ng-template using ngTemplateOutletContext in Angular
- Define an anchor point where to render dynamic components in Angular
- Dynamically instantiate an Angular component
- Destroy a dynamically instantiated Angular component
نگاهی به نحوهی عملکرد سرویسها و تزریق وابستگیها در AngularJS 2.0
فرض کنید کلاس سرویسی، به نحو ذیل تعریف شدهاست:
export class MyService {}
let svc = new MyService();
همچنین در این حالت، mocking این سرویس برای نوشتن unit tests نیز مشکل میباشد.
راه بهتر و توصیه شدهی در اینجا، ثبت و معرفی این سرویسها به AngularJS 2.0 است. سپس AngularJS 2.0 به ازای هر کلاس سرویس معرفی شدهی به آن، یک وهله/نمونه را ایجاد میکند. بنابراین طول عمر سرویسهای ایجاد شدهی در این حالت، singleton است (یکبار ایجاد شده و تا پایان طول عمر برنامه زنده نگه داشته میشوند).
پس از آن میتوان از تزریق کنندههای توکار AngularJS 2.0، جهت تزریق وهلههای این سرویسها استفاده کرد.
اکنون اگر کلاسی، نیاز به این سرویس داشته باشد، نیاز خود را به صورت یک وابستگی تعریف شدهی در سازندهی کلاس اعلام میکند:
constructor(private _myService: MyService){}
به این فرآیند اصطلاحا dependency injection و یا تزریق وابستگیها میگویند. در فرآیند تزریق وابستگیها، یک کلاس، وهلههای کلاسهای دیگر مورد نیاز خودش را بجای وهله سازی مستقیم، از یک تزریق کننده دریافت میکند. بنابراین بجای نوشتن newها در کلاس جاری، آنها را به صورت وابستگیهایی در سازندهی کلاس تعریف میکنیم تا توسط AngularJS 2.0 تامین شوند.
با توجه به اینکه طول عمر این وابستگیها singleton است و این طول عمر توسط AngularJS 2.0 مدیریت میشود، اطلاعات وهلههای سرویسهای مختلف و تغییرات صورت گرفتهی در آنها، بین تمام کامپوننتها به صورت یکسانی به اشتراک گذاشته میشوند.
به علاوه اکنون امکان mocking سرویسها با توجه به عدم وهله سازی آنها در داخل کلاسها به صورت مستقیم، سادهتر از قبل میسر است.
مراحل ساخت یک سرویس در AngularJS 2.0
ساخت یک سرویس در AngularJS 2.0، با ایجاد یک کلاس جدید شروع میشود. سپس متادیتای آن افزوده شده و در آخر موارد مورد نیاز آن import خواهند شد. با این موارد پیشتر در حین ساختن یک کامپوننت جدید و یا یک Pipe جدید آشنا شدهاید و این طراحی یک دست را در سراسر AngularJS 2.0 میتوان مشاهده کرد.
اولین سرویس خود را با افزودن فایل جدید product.service.ts به پوشهی app\products آغاز میکنیم؛ با این محتوا:
import { Injectable } from 'angular2/core'; import { IProduct } from './product'; @Injectable() export class ProductService { getProducts(): IProduct[] { return [ { "productId": 2, "productName": "Garden Cart", "productCode": "GDN-0023", "releaseDate": "March 18, 2016", "description": "15 gallon capacity rolling garden cart", "price": 32.99, "starRating": 4.2, "imageUrl": "app/assets/images/garden_cart.png" }, { "productId": 5, "productName": "Hammer", "productCode": "TBX-0048", "releaseDate": "May 21, 2016", "description": "Curved claw steel hammer", "price": 8.9, "starRating": 4.8, "imageUrl": "app/assets/images/rejon_Hammer.png" } ]; } }
همانند سایر ماژولهای تعریف شده، در اینجا نیز باید کلاس تعریف شده export شود تا در قسمتهای دیگر قابل استفاده و دسترسی گردد.
سپس در این سرویس، یک متد برای بازگشت لیست محصولات ایجاد شدهاست.
در ادامه یک decorator جدید به نام ()Injectable@ به بالای این کلاس اضافه شدهاست. این متادیتا است که مشخص میکند کلاس جاری، یک سرویس AngularJS 2.0 است.
البته باید دقت داشت که این مزین کننده تنها زمانی نیاز است حتما قید شود که کلاس تعریف شده، دارای وابستگیهای تزریق شدهای باشد. اما توصیه شدهاست که بهتر است هر کلاس سرویسی (حتی اگر دارای وابستگیهای تزریق شدهای هم نبود) به این decorator ویژه، مزین شود تا بتوان طراحی یک دستی را در سراسر برنامه شاهد بود.
در آخر هم موارد مورد نیاز، import میشوند. برای مثال Injectable در ماژول angular2/core تعریف شدهاست.
هدف از تعریف این سرویس، دور کردن وظیفهی تامین داده، از کلاس کامپوننت لیست محصولات است؛ جهت رسیدن به یک طراحی SOLID.
در قسمت بعدی این سری، این لیست را بجای یک آرایهی از پیش تعریف شده، از یک سرور HTTP دریافت خواهیم کرد.
ثبت و معرفی سرویس جدید ProductService به AngularJS 2.0 Injector
مرحلهی اول استفاده از سرویسهای تعریف شده، ثبت و معرفی آنها به AngularJS 2.0 Injector است. سپس این Injector است که تک وهلهی سرویس ثبت شدهی در آنرا در اختیار هر کامپوننتی که آنرا درخواست کند، قرار میدهد.
مرحلهی ثبت این سرویس، معرفی نام این کلاس، به خاصیتی آرایهای، به نام providers است که یکی از خواص decorator ویژهی Component است. بدیهی است هر کامپوننتی که در برنامه وجود داشته باشد، توانایی ثبت این سرویس را نیز دارد؛ اما باید از کدامیک استفاده کرد؟
اگر سرویس خود را در کامپوننت لیست محصولات رجیستر کنیم، تک وهلهی این سرویس تنها در این کامپوننت و زیر کامپوننتهای آن در دسترس خواهند بود و اگر این سرویس را در بیش از یک کامپوننت ثبت کنیم، آنگاه دیگر هدف اصلی طول عمر singleton یک سرویس مفهومی نداشته و برنامه هم اکنون دارای چندین وهله از سرویس تعریف شدهی ما میگردد و دیگر نمیتوان اطلاعات یکسانی را بین کامپوننتها به اشتراک گذاشت.
بنابراین توصیه شدهاست که از خاصیت providers کامپوننتهای غیر ریشهای، صرفنظر کرده و سرویسهای خود را تنها در بالاترین سطح کامپوننتهای تعریف شده، یعنی در فایل app.component.ts ثبت و معرفی کنید. به این ترتیب تک وهلهی ایجاد شدهی در اینجا، در این کامپوننت ریشهای و تمام زیر کامپوننتهای آن (یعنی تمام کامپوننتهای دیگر برنامه) به صورت یکسانی در دسترس قرار میگیرد.
به همین جهت فایل app.component.ts را گشوده و تغییرات ذیل را به آن اعمال کنید:
import { Component } from 'angular2/core'; import { ProductListComponent } from './products/product-list.component'; import { ProductService } from './products/product.service'; @Component({ selector: 'pm-app', template:` <div><h1>{{pageTitle}}</h1> <pm-products></pm-products> </div> `, directives: [ProductListComponent], providers: [ProductService] }) export class AppComponent { pageTitle: string = "DNT AngularJS 2.0 APP"; }
الف) خاصیت providers که آرایهای از سرویسها را قبول میکند، با ProductService مقدار دهی شدهاست.
ب) در ابتدای فایل، ProductService، از ماژول آن import گردیدهاست.
تزریق سرویسها به کامپوننتها
تا اینجا یک سرویس جدید را ایجاد کردیم و سپس آنرا به AngularJS 2.0 Injector معرفی نمودیم. اکنون نوبت به استفاده و تزریق آن، به کلاسی است که به این وابستگی نیاز دارد. در TypeScript، تزریق وابستگیها در سازندهی یک کلاس صورت میگیرند. هر کلاس، دارای متد سازندهای است که در زمان وهله سازی آن، اجرا میشود. اگر نیاز به تزریق وابستگیها باشد، تعریف این سازنده به صورت صریح، ضروری است. باید دقت داشت که هدف اصلی از متد سازنده، آغاز و مقدار دهی متغیرها و وابستگیهای مورد نیاز یک کلاس است و باید تا حد امکان از منطقهای طولانی عاری باشد.
در ادامه فایل product-list.component.ts را گشوده و سپس سازندهی ذیل را به آن اضافه کنید:
import { ProductService } from './product.service'; export class ProductListComponent implements OnInit { pageTitle: string = 'Product List'; imageWidth: number = 50; imageMargin: number = 2; showImage: boolean = false; listFilter: string = 'cart'; constructor(private _productService: ProductService) { }
روش خلاصه شدهای که در اینجا جهت تعریف سازندهی کلاس و متغیر تعریف شدهی در آن بکار گرفته شده، معادل قطعه کد متداول ذیل است و هر دو حالت ذکر شده، در TypeScript یکی میباشند:
private _productService: ProductService; constructor(productService: ProductService) { _productService = productService; }
این وابستگی در اولین باری که کلاس کامپوننت، توسط AngularJS 2.0 وهله سازی میشود، از لیست providers ثبت شدهی در کامپوننت ریشهی سایت، تامین خواهد شد.
اکنون نوبت به استفادهی از این سرویس تزریق شدهاست. به همین جهت ابتدا لیست عناصر آرایهی خاصیت products را حذف میکنیم (برای اینکه قرار است این سرویس، کار تامین اطلاعات را انجام دهد و نه کلاس کامپوننت).
products: IProduct[];
this.products = _productService.getProducts();
به همین جهت روش صحیح انجام این مقدار دهی، با پیاده سازی life cycle hook ویژهای به نام OnInit است که در قسمت پنجم آنرا معرفی کردیم:
export class ProductListComponent implements OnInit { products: IProduct[]; constructor(private _productService: ProductService) { } ngOnInit(): void { //console.log('In OnInit'); this.products = this._productService.getProducts(); }
در اینجا اکنون خاصیت products عاری است از ذکر صریح عناصر تشکیل دهندهی آن. سپس وابستگی مورد نیاز، در سازندهی کلاس تزریق شدهاست و در آخر، در رویداد چرخهی حیات ngOnInit، با استفاده از این وابستگی تزریقی، لیست محصولات دریافت و به خاصیت عمومی products نسبت داده شدهاست.
در ادامه برنامه را اجرا کنید. باید هنوز هم مطابق قبل، لیست محصولات قابل مشاهده باشد.
کدهای کامل این قسمت را از اینجا میتوانید دریافت کنید: MVC5Angular2.part7.zip
خلاصهی بحث
فرآیند کلی تعریف یک سرویس AngularJS 2.0، تفاوتی با ساخت یک کامپوننت یا Pipe سفارشی ندارد. پس از تعریف کلاسی که نام آن ختم شدهی به Service است، آنرا مزین به ()Injectable@ میکنیم. سپس این سرویس را در بالاترین سطح کامپوننتهای موجود یا همان کامپوننت ریشهی سایت، ثبت و معرفی میکنیم؛ تا تنها یک وهله از آن توسط AngularJS 2.0 Injector ایجاد شده و در اختیار تمام کامپوننتهای برنامه قرار گیرد. البته اگر این سرویس تنها در یک کامپوننت استفاده میشود و قصد به اشتراک گذاری اطلاعات آنرا نداریم، میتوان سطح سلسله مراتب دسترسی به آنرا نیز کاهش داد. برای مثال این سرویس را در لیست providers همان کامپوننت ویژه، ثبت و معرفی کرد. به این ترتیب تنها این کامپوننت خاص و فرزندان آن دسترسی به امکانات سرویس مدنظر را مییابند و نه تمام کامپوننتهای دیگر تعریف شدهی در برنامه.
در ادامه هر کلاسی که به این سرویس نیاز دارد (با توجه به سلسه مراتب دسترسی ذکر شده)، تنها کافی است در سازندهی خود، این وابستگی را اعلام کند تا توسط AngularJS 2.0 Injector تامین گردد.
Angular CLI 1.1 منتشر شد
Angular CLI 1.1 is out and here are some notable new features:
- outputs smaller and faster bundles by default,
- now comes with a new welcome screen when creating a new application,
- has better support for serving with a different public URL, and
- now supports fixing generated code according to your linting preferences, e.g. use double-quotes instead of single quotes for strings.
Along with over 50 fixes!
بنابراین برای ایجاد یک کامپوننت میتوانیم به اینصورت عمل کنیم:
var app = angular.module("dntModule", []); app.component("pmApp", { template: `Hello this is a simple component` });
همانطور که مشاهده میکنید تابع component دو پارامتر را از ورودی دریافت خواهد کرد؛ نام کامپوننت و یک شیء برای تعیین تنظیمات کامپوننت. نام کامپوننت در اینجا به صورت camel case تعریف شده است؛ که در واقع یک convention برای Angular است. در اینحالت برای استفادهی از کامپوننت باید به اینصورت عمل کنیم:
<pm-app></pm-app>
در قسمت تنظیمات کامپوننت، در سادهترین حالت یک template تعیین شدهاست که بیانگر نحوهی رندر شدن یک کامپوننت میباشد. در اینحالت وقتی انگیولار به تگ فوق برسد، یک کامپوننت با نام pmApp را بارگذاری خواهد کرد.
ایجاد یک کامپوننت ساده
در ادامه میخواهیم یک کامپوننت ساده را جهت نمایش یکسری URL درون صفحه طراحی کنیم. ساختار صفحه index.html به صورت زیر خواهد بود:
<html ng-app="DNT"> <head> <meta charset="UTF-8"> <title>Using Angular Component</title> <link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap.css"> <link rel="stylesheet" href="bower_components/font-awesome/css/font-awesome.min.css"> </head> <body> <div class="container"> <div class="row"> <div class="col-md-3"> <dnt-widget></dnt-widget> </div> </div> </div> <script src="bower_components/angular/angular.js"></script> <script src="scripts/app.js"></script> <script src="scripts/components/dnt-widget.component.js"></script> </body> </html>
در اینجا ابتدا توسط دایرکتیو ng-app، به Angular، ماژولمان را معرفی کردهایم. سپس مداخل بوتاسترپ و کتابخانهی font-awesome را مشاهده میکنید. در ادامه، کتابخانهی Angular و همچنین فایل app.js جهت معرفی ماژول برنامه معرفی شدهاست. در نهایت نیز یک فایل در مسیر ذکر شده برای قرار دادن کدهای کامپوننت در مسیر scripts/components اضافه شدهاست.
همانطور که ملاحظه میکنید، کامپوننتمان به صورت یک تگ سفارشی، درون صفحه قرار گرفته است:
<dnt-archive></dnt-archive>
در ادامه باید به Angular، نحوهی تعریف این کامپوننت را اعلام کنیم. بنابراین یک فایل جاوا اسکریپتی را با نام dnt-widget.component، با محتویات زیر ایجاد کنید:
(function () { "use strict"; var app = angular.module("DNT"); function DntArchiveController() { var model = this; model.panel = { title: "Panel Title", items: [ { title: "Dotnettips", url: "https://www.dntips.ir" }, { title: "Google", url: "http://www.google.con" }, { title: "Yahoo", url: "http://www.yahoo.con" } ] }; }; app.component("dntWidget", { templateUrl: '/scripts/components/dnt-widget.component.html', controllerAs: "model", controller: DntArchiveController }); } ());
توضیح کدهای فوق:
همانطور که مشاهده میکنید، برای پارمتر دوم کامپوننت، سه پراپرتی را تعیین کردهایم:
templateUrl: به کمک این پراپرتی به Angular گفتهایم که محتوای قالب این کامپوننت، درون یک فایل HTML مجزا قرار دارد و به صورت linked template میباشد.
controllerAs: یکی از مزایای استفاده از کامپوننتها، استفاده از controller as syntax میباشد. لازم به ذکر است اگر این پراپرتی را مقداردهی نکنیم، به صورت پیشفرض مقدار ctrl$ در نظر گرفته خواهد شد.
controller: مزیت دیگر کامپوننتها، استفاده از کنترلرها است. با استفاده از این پراپرتی، یک کنترلر را برای کامپوننتمان رجیستر کردهایم. در نتیجه زمانیکهی Angular میخواهد کامپوننتمان را نمایش دهد، تابع تعریف شده برای این پراپرتی، جهت ایجاد یک controller instance فراخوانی خواهد شد. بنابراین هر پراپرتی یا تابعی که برای این controller instance تعریف کنیم، به راحتی درون ویوی آن جهت اعمال بایندینگ در دسترس خواهد بود (در نتیجه نیازی به scope$ نخواهد بود).
درون کنترلر نیز برای راحتی کار و همچنین به عنوان یک best practice، مقدار this را توسط یک متغیر با نام model، کپچر کردهایم. در اینجا یک شیء را با نام panel نیز به مدل اضافه کردهایم.
محتویات تمپلیت:
<div class="panel panel-default"> <div class="panel-heading"> <h3 class="panel-title"> <span class="fa fa-archive"></span> {{ model.panel.title}} </h3> </div> <ul class="list-group"> <li class="list-group-item" ng-repeat="item in model.panel.items"> <span class="fa fa-industry"></span> <a href="{{ item.url }}">{{ item.title }}</a> </li> </ul> </div>
ویوی کامپوننت پیچیدگی خاصی ندارد. همانطور که مشاهده میکنید یک پنل بوتاسترپی را ایجاد کردهایم که مقدار عنوان آن و همچنین آیتمهای آن، از شیء اتچ شده به مدل دریافت خواهند شد. بنابراین اکنون اگر برنامه را اجرا کنید، خروجی کامپوننت را به اینصورت مشاهده خواهید کرد:
همانطور که مشاهده میکنید استفاده از کامپوننتها در Angular 1.5 در مقایسه با ایجاد دایرکتیوها و کنترلرها خیلی سادهتر است. در واقع امکانات این API جدید تنها به مثال فوق ختم نمیشود؛ بلکه این API یک سیستم مسیریابی جدید را نیز معرفی کرده است که در قسمتهای بعدی به آن نیز خواهیم پرداخت.
جهت تکمیل بحث نیز یک تقویم شمسی ساده را در اینجا قرار دادهام. میتوانید جهت مرور بحث جاری به کدهای آن مراجعه کنید. البته هدف از تعریف این پروژه تنها یک مثال ساده برای معرفی کامپوننتها بود و طبیعتاً باگهای زیادی دارد. اگر مایل بودید میتوانید در توسعهی آن مشارکت نمائید.
کدهای این قسمت را نیز از اینجا میتوانید دریافت کنید.
منابع و مآخذ مرتبط با کتابخانهی Angular Material
در اینجا مآخذ اصلی کار با این کتابخانه را ملاحظه میکنید که شامل اصول طراحی متریال و مخازن اصلی توسعهی آن میباشند:
Material Design Specification
- https://material.io/design
Angular Material
- https://material.angular.io
- https://github.com/angular/material2
مفاهیم پایهی طراحی متریال
چرا «زیبایی» رابط کاربری مهم است؟
در ابتدای معرفی کتابخانهی Angular Material عنوان شد که این مجموعه به همراه تعدادی کامپوننت «زیبا» است. بنابراین این سؤال مطرح میشود که چرا و یا تا چه اندازه «زیبایی» رابط کاربری اهمیت دارد؟ مهمترین دلیل آن بهبود تجربهی کاربری است. بر اساس تحقیقاتی که بر روی کاربران بسیاری صورت گرفتهاست، مشخص شدهاست کاربران، با رابطهای کاربری زیبا نتایج بهتری را از لحاظ کاهش زمان اتمام کار و تعداد خطاهای مرتبط دریافت میکنند.
اما ... طراحی برنامههای زیبا مشکل است. به همین جهت استفاده از کتابخانههای غنی مانند طراحی متریال که این امر را سهولت میبخشند، ضروری است. طراحی متریال یک زبان کامل طراحی برنامههای زیبا است. توسط گوگل طراحی شدهاست و دو هدف اصلی را دنبال میکند:
- وفاداری به اصول کلاسیک طراحی رابط کاربری
- ارائهی تجربهی کاربری یکدست و هماهنگ، در بین وسایل و اندازههای صفحات نمایشی مختلف
اصول پایهی طراحی متریال نیز شامل موارد زیر است:
- «متریال» یک متافور است و بر اساس مطالعهی نحوهی کار با کاغذ، مرکب و ارتباط بین اشیاء در دنیای واقعی پدید آمدهاست.
- اشیاء در دنیای واقعی دارای ارتباطهای ابعادی و حجمی هستند. برای مثال دو برگهی کاغذ یک فضا را اشغال نمیکنند. طراحی متریال برای نمایش این ارتباط سه بعدی بین اشیاء، از نور و سایه استفاده میکند.
- در دنیای واقعی، اشیاء از درون یکدیگر رد نمیشوند. این مورد در طراحی متریال نیز صادق است.
- طراحی متریال به همراه جعبهی رنگ مخصوص و بکارگیری فضاهای خالی و عناوین درشت بسیار مشخص، واضح و عمدی است.
- طراحی متریال به همراه حرکت و پویانمایی، جهت ارائهی مفاهیم مختلف به کاربر، جهت درک بهتر او از برنامه است.
برپایی پیشنیازهای ابتدایی کار با Angular Material
پیش از ادامهی بحث فرض بر این است که آخرین نگارش Angular CLI را نصب کردهاید و اگر پیشتر آنرا نصب کردهاید، یکبار دستور ذیل را اجرا کنید تا تمام وابستگیهای سراسری نصب شدهی در سیستم به صورت خودکار به روز رسانی شوند:
npm update -g
ng new MaterialAngularClient --routing
cd MaterialAngularClient ng serve -o
افزودن کتابخانهی Angular Material به برنامه
در طول این سری از سایت https://material.angular.io زیاد استفاده خواهیم کرد. همواره به روزترین روش افزودن کتابخانهی Angular Material به یک برنامهی موجود را در آدرس https://material.angular.io/guide/getting-started میتوانید مشاهده کنید که خلاصهی آن به صورت زیر است:
البته در Angular 6 روش تفصیلی نصب فوق که شامل 6 مرحلهاست، به صورت زیر هم خلاصه شدهاست:
ng add @angular/material
npm install --save @angular/material @angular/cdk npm install --save @angular/animations npm install --save hammerjs
- همانطور که عنوان شد، طراحی متریال مبتنی بر حرکت و پویانمایی است. به همین جهت تعدادی از کامپوننتهای آن نیاز به بستهی angular/animations را دارند که توسط دستور دوم نصب میشود.
- دستور سوم نیز کامپوننتهای slide و slider را پشتیبانی میکند (Gesture Support). البته پس نصب این وابستگی، نیاز است به فایل src/main.ts مراجعه کرده و یک سطر زیر را نیز افزود:
import "hammerjs";
import { BrowserAnimationsModule } from "@angular/platform-browser/animations"; @NgModule({ imports: [ BrowserModule, BrowserAnimationsModule, AppRoutingModule ] }) export class AppModule { }
مدیریت بهتر import کامپوننتهای Angular Material
در ادامه به ازای هر کامپوننت Angular Material باید ماژول آنرا به لیست imports افزود که پس از مدتی به یک فایل app.module.ts بسیار شلوغ خواهیم رسید. برای مدیریت بهتر این فایل، از روش مطرح شدهی در مطلب «سازماندهی برنامههای Angular» استفاده خواهیم کرد.
به همین جهت دو پوشهی core و shared را درون پوشهی src/app ایجاد میکنیم:
محتویات فایل src\app\core\core.module.ts به صورت زیر است:
import { CommonModule } from "@angular/common"; import { NgModule, Optional, SkipSelf } from "@angular/core"; import { RouterModule } from "@angular/router"; @NgModule({ imports: [CommonModule, RouterModule], exports: [ // components that are used in app.component.ts will be listed here. ], declarations: [ // components that are used in app.component.ts will be listed here. ], providers: [ /* ``No`` global singleton services of the whole app should be listed here anymore! Since they'll be already provided in AppModule using the `tree-shakable providers` of Angular 6.x+ (providedIn: 'root'). This new feature allows cleaning up the providers section from the CoreModule. But if you want to provide something with an InjectionToken other that its class, you still have to use this section. */ ] }) export class CoreModule { constructor(@Optional() @SkipSelf() core: CoreModule) { if (core) { throw new Error("CoreModule should be imported ONLY in AppModule."); } } }
محتویات فایل src\app\shared\shared.module.ts نیز به صورت زیر است:
import { CommonModule } from "@angular/common"; import { HttpClientModule } from "@angular/common/http"; import { ModuleWithProviders, NgModule } from "@angular/core"; import { FormsModule } from "@angular/forms"; @NgModule({ imports: [ CommonModule, FormsModule, HttpClientModule ], entryComponents: [ // All components about to be loaded "dynamically" need to be declared in the entryComponents section. ], declarations: [ // common and shared components/directives/pipes between more than one module and components will be listed here. ], exports: [ // common and shared components/directives/pipes between more than one module and components will be listed here. CommonModule, FormsModule, HttpClientModule, ] /* No providers here! Since they’ll be already provided in AppModule. */ }) export class SharedModule { static forRoot(): ModuleWithProviders { // Forcing the whole app to use the returned providers from the AppModule only. return { ngModule: SharedModule, providers: [ /* All of your services here. It will hold the services needed by `itself`. */] }; } }
import { CoreModule } from "./core/core.module"; import { SharedModule } from "./shared/shared.module"; @NgModule({ imports: [ BrowserModule, BrowserAnimationsModule, CoreModule, SharedModule.forRoot(), AppRoutingModule ] }) export class AppModule { }
import { CdkTableModule } from "@angular/cdk/table"; import { NgModule } from "@angular/core"; import { MatAutocompleteModule, MatButtonModule, MatButtonToggleModule, MatCardModule, MatCheckboxModule, MatChipsModule, MatDatepickerModule, MatDialogModule, MatExpansionModule, MatFormFieldModule, MatGridListModule, MatIconModule, MatInputModule, MatListModule, MatMenuModule, MatNativeDateModule, MatPaginatorModule, MatProgressBarModule, MatProgressSpinnerModule, MatRadioModule, MatRippleModule, MatSelectModule, MatSidenavModule, MatSliderModule, MatSlideToggleModule, MatSnackBarModule, MatSortModule, MatStepperModule, MatTableModule, MatTabsModule, MatToolbarModule, MatTooltipModule, } from "@angular/material"; @NgModule({ imports: [ MatAutocompleteModule, MatButtonModule, MatButtonToggleModule, MatCardModule, MatCheckboxModule, MatChipsModule, MatDatepickerModule, MatDialogModule, MatExpansionModule, MatFormFieldModule, MatGridListModule, MatIconModule, MatInputModule, MatListModule, MatMenuModule, MatNativeDateModule, MatPaginatorModule, MatProgressBarModule, MatProgressSpinnerModule, MatRadioModule, MatRippleModule, MatSelectModule, MatSidenavModule, MatSliderModule, MatSlideToggleModule, MatSnackBarModule, MatStepperModule, MatSortModule, MatTableModule, MatTabsModule, MatToolbarModule, MatTooltipModule, CdkTableModule ], exports: [ MatAutocompleteModule, MatButtonModule, MatButtonToggleModule, MatCardModule, MatCheckboxModule, MatChipsModule, MatDatepickerModule, MatDialogModule, MatExpansionModule, MatGridListModule, MatIconModule, MatInputModule, MatListModule, MatMenuModule, MatNativeDateModule, MatPaginatorModule, MatProgressBarModule, MatProgressSpinnerModule, MatRadioModule, MatRippleModule, MatSelectModule, MatSidenavModule, MatSliderModule, MatSlideToggleModule, MatSnackBarModule, MatStepperModule, MatSortModule, MatTableModule, MatTabsModule, MatToolbarModule, MatTooltipModule, CdkTableModule ] }) export class MaterialModule { }
سپس MaterialModule را نیز به قسمتهای imports و exports فایل src\app\shared\shared.module.ts اضافه خواهیم کرد:
import { MaterialModule } from "./material.module"; @NgModule({ imports: [ CommonModule, FormsModule, HttpClientModule, MaterialModule ], exports: [ // common and shared components/directives/pipes between more than one module and components will be listed here. CommonModule, FormsModule, HttpClientModule, MaterialModule ] }) export class SharedModule { }
تا اینجا جهت اطمینان از اجرای برنامه، دستور ng serve -o را از ابتدا اجرا کنید.
افزودن چند کامپوننت مقدماتی متریال به برنامه
بهترین روش کار با این مجموعه، بررسی مستندات آن در سایت https://material.angular.io/components است. برای مثال برای افزودن دکمه، به مستندات آن مراجعه کرده و بر روی دکمهی view source کلیک میکنیم:
سپس کدهای قسمت HTML آنرا به برنامه و فایل app.component.html اضافه خواهیم کرد:
<button mat-button>Click me!</button>
<mat-checkbox>Check me!</mat-checkbox>
البته شکل ظاهری آنها تا اینجا آنچنان مطلوب نیست. برای رفع این مشکل، نیاز است یک قالب را به این کنترلها و کامپوننتها اعمال کرد. به همین جهت فایل styles.css واقع در ریشهی برنامه را گشوده و قالب پیشفرض متریال را به آن اضافه میکنیم:
@import "~@angular/material/prebuilt-themes/indigo-pink.css";
پس از اعمال قالب، اکنون است که شکل ظاهری کنترلهای آن بسیار بهتر شدهاند و همچنین کار با آنها به همراه پویانمایی نیز شدهاست:
افزودن آیکنهای متریال به برنامه
مرحلهی آخر این تنظیمات، افزودن آیکنهای متریال به برنامهاست. برای این منظور فایل src\index.html را گشوده و یک سطر ذیل را به head اضافه کنید:
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<button mat-button> <mat-icon>face</mat-icon> Click me! </button> <mat-checkbox>Check me!</mat-checkbox>
لیست کامل این آیکنها را به همراه توضیحات تکمیلی آنها، در آدرس ذیل میتوانید ملاحظه کنید:
http://google.github.io/material-design-icons
البته چون ما نمیخواهیم این آیکنها را از وب بارگذاری کنیم، برای نصب محلی آنها ابتدا دستور زیر را در ریشهی پروژه صادر کنید:
npm install material-design-icons --save
همانطور که مشاهده میکنید، برای استفادهی از این فایلهای آیکن فونت محلی، تنها کافی است فایل material-icons.css را به برنامه معرفی کنیم. برای این منظور فایل angular.json را گشوده و قسمت styles آنرا به صورت زیر تکمیل میکنیم:
"styles": [ "node_modules/material-design-icons/iconfont/material-icons.css", "src/styles.css" ],
کدهای کامل این قسمت را از اینجا میتوانید دریافت کنید: MaterialAngularClient-01.zip
برای اجرای آن نیز ابتدا فایل restore.bat و سپس فایل ng-serve.bat را اجرا کنید.