Angular 6 Tutorial: ميزات جديدة بقوة جديدة

نشرت: 2022-03-11

خرج Angular 6! تتمثل أبرز التغييرات في CLI وكيفية إدخال الخدمات. إذا كنت تتطلع إلى كتابة أول تطبيق Angular 6 - أو تطبيق Angular / Firebase - في هذا البرنامج التعليمي ، فسننتقل إلى الخطوات الأساسية للإعداد الأولي وإنشاء تطبيق مذكرات صغير.

الزاوية 6: الأساسيات

إذا لم تستخدم Angular من قبل ، دعني أقدم لك وصفًا موجزًا ​​لها وكيف تعمل.

Angular هو إطار عمل JavaScript مصمم لدعم إنشاء تطبيقات ذات صفحة واحدة (SPA) لكل من سطح المكتب والجوال.

يتضمن إطار العمل مجموعة كاملة من التوجيهات والوحدات النمطية التي تسمح لك بتنفيذ بعض السيناريوهات الأكثر شيوعًا لتطبيق ويب بسهولة ، مثل التنقل والتفويض والنماذج وإعداد التقارير. يأتي أيضًا مع جميع الحزم اللازمة لإضافة الاختبارات باستخدام إطار Jasmine وتشغيلها باستخدام عداء اختبار Karma أو منقلة.

تعتمد الهندسة المعمارية الزاويّة على المكونات والقوالب والتوجيهات والخدمات. يوفر آلية حقن تبعية مضمنة لخدماتك ، بالإضافة إلى ربط بيانات ثنائي الاتجاه لربط طرق العرض الخاصة بك بكود المكون الخاص بك.

تستخدم Angular TypeScript ، وهي مجموعة شاملة مكتوبة من JS ، وستجعل بعض الأشياء أسهل ، خاصةً إذا كنت تأتي من خلفية لغة مكتوبة.

الزاوية 6: الميزات الجديدة

ملخص موجز للميزات الجديدة في Angular 6:

  • سياسة لمزامنة أرقام الإصدارات الرئيسية لحزم إطار العمل ( @angular/core ، @angular/common ، @angular/compiler ، إلخ) ، CLI ، Material ، و CDK. سيساعد هذا في جعل التوافق المتبادل أكثر وضوحًا من الآن فصاعدًا: يمكنك أن تعرف من لمحة سريعة على رقم الإصدار ما إذا كانت حزم المفاتيح متوافقة مع بعضها البعض.
  • أوامر ng CLI الجديدة:
    • ng update إصدارات الحزم بذكاء وتحديث إصدارات التبعيات وإبقائها متزامنة. (على سبيل المثال ، عند تشغيل ng update @angular/core ، سيتم تحديث جميع أطر العمل بالإضافة إلى RxJS.) كما سيتم تشغيل المخططات إذا كانت الحزمة تتضمنها. (إذا تضمن الإصدار الأحدث تغييرات فاصلة تتطلب تغييرات في التعليمات البرمجية ، فسيقوم المخطط بتحديث التعليمات البرمجية نيابة عنك.)
    • ng add لإضافة حزم جديدة (وتشغيل البرامج النصية ، إن أمكن)
  • تشير الخدمات الآن إلى الوحدات النمطية التي ستوفرها ، بدلاً من الوحدات النمطية التي تشير إلى الخدمات ، كما اعتادوا الحصول عليها.

كمثال على ما يعنيه هذا التغيير الأخير ، حيث كانت الكود الخاص بك يبدو مثل:

 @NgModule({ // ... providers: [MyService] })

... مع هذا التغيير المحدد في Angular 6 ، سيبدو كما يلي:

 @Injectabe({ providedIn: 'root', })

يُطلق عليها اسم موفري اهتزاز الشجرة وتسمح للمترجم بإزالة الخدمات غير المشار إليها مما يؤدي إلى حزم أصغر حجمًا.

زاوية 6 CLI

تعد واجهة سطر الأوامر ng جزءًا مهمًا جدًا من Angular وتسمح لك بالتحرك بشكل أسرع عند ترميز تطبيقك.

باستخدام CLI ، يمكنك دعم الإعداد الأولي لتطبيقك بسهولة بالغة ، وإنشاء مكونات وتوجيهات جديدة ، وما إلى ذلك ، وإنشاء تطبيقك وتشغيله في بيئتك المحلية.

إنشاء مشروع Angular 6

حسنًا ، كفى الحديث. دعنا نتسخ أيدينا ونبدأ في البرمجة.

للبدء ، ستحتاج إلى تثبيت Node.js و npm على جهازك.

الآن ، دعنا نمضي قدمًا ونثبت CLI:

 npm install -g @angular/cli

سيؤدي هذا إلى تثبيت الأمر ng CLI بشكل عام ، بسبب المحول -g .

بمجرد حصولنا على ذلك ، يمكننا الحصول على السقالة الأولية لتطبيقنا باستخدام ng new :

 ng new my-memories --style=scss

سيؤدي هذا إلى إنشاء مجلد my-memories ، وإنشاء جميع الملفات الضرورية حتى يصبح الإعداد الأولي جاهزًا للبدء ، وتثبيت جميع الحزم الضرورية. يعد التبديل --style=scss اختياريًا وسيعمل على إعداد المحول البرمجي لترجمة ملفات SCSS إلى CSS ، وهو ما سنحتاجه لاحقًا.

بمجرد اكتمال التثبيت ، يمكنك cd my-memories وتشغيل ng serve . سيبدأ هذا عملية الإنشاء وخادم ويب محلي يخدم تطبيقك على http://localhost:4200 .

تطبيق Angular 6 بعد السقالات مباشرة

ما يحدث خلف الكواليس هو أن CLI تنقل جميع ملفات .ts (ملفات TypeScript) إلى Vanilla JS ، وتجمع جميع التبعيات المطلوبة من مجلد الحزم node_modules ، وتخرج النتيجة في مجموعة من الملفات التي يتم تقديمها عبر خادم ويب محلي الذي يعمل على المنفذ 4200.

ملفات المشروع

إذا لم تكن معتادًا على بنية مجلد المشروع في Angular ، فإن أهم شيء تحتاج إلى معرفته هو أن كل الأكواد المتعلقة بالتطبيق تدخل داخل مجلد src . ستقوم عادةً بإنشاء جميع الوحدات النمطية والتوجيهات الخاصة بك في هذا المجلد باتباع بنية التطبيق الخاص بك (على سبيل المثال ، المستخدم ، عربة التسوق ، المنتج.)

هيكل مجلد مشروع Angular 6

الإعداد الأولي

حسنًا ، لدينا حتى الآن الإعداد الأولي لتطبيقنا. لنبدأ في إجراء بعض التغييرات.

قبل أن نبدأ ، دعنا نتعمق في مجلد src قليلاً. الصفحة الأولى هي index.html :

 <!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <title>MyMemories</title> <base href="/"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="icon" type="image/x-icon" href="favicon.ico"> </head> <body> <app-root></app-root> </body> </html>

هنا نرى بعض HTML الأساسي وعلامة <app-root> . هذا مكون Angular ، حيث يُدرج Angular 6 كود المكون الخاص بنا.

سنجد ملف app/app.component.ts ، الذي يحتوي على محدد app-root لمطابقة ما هو موجود في ملف index.html .

المكون هو فئة TypeScript مزخرفة ، وفي هذه الحالة ، يحتوي على خاصية title . يقوم مصمم @Component بإخبار Angular بتضمين سلوك المكون في الفصل. بالإضافة إلى المحدد ، فإنه يحدد ملف HTML الذي سيتم عرضه وأوراق الأنماط التي يجب استخدامها.

 import { Component } from '@angular/core'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.scss'] }) export class AppComponent { title = 'app'; }

إذا نظرنا إلى app.component.html ، فسنرى {{title}} ربط الاستيفاء. هذا هو المكان الذي تحدث فيه جميع عمليات الربط السحرية ، وسيقوم Angular بعرض قيمة خاصية عنوان الفئة وتحديثها في أي وقت تتغير فيه.

 <!--The content below is only a placeholder and can be replaced.--> <div> <h1> Welcome to {{ title }}! </h1> <img width="300" alt="Angular Logo" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNTAgMjUwIj4KICAgIDxwYXRoIGZpbGw9IiNERDAwMzEiIGQ9Ik0xMjUgMzBMMzEuOSA2My4ybDE0LjIgMTIzLjFMMTI1IDIzMGw3OC45LTQzLjcgMTQuMi0xMjMuMXoiIC8+CiAgICA8cGF0aCBmaWxsPSIjQzMwMDJGIiBkPSJNMTI1IDMwdjIyLjItLjFWMjMwbDc4LjktNDMuNyAxNC4yLTEyMy4xTDEyNSAzMHoiIC8+CiAgICA8cGF0aCAgZmlsbD0iI0ZGRkZGRiIgZD0iTTEyNSA1Mi4xTDY2LjggMTgyLjZoMjEuN2wxMS43LTI5LjJoNDkuNGwxMS43IDI5LjJIMTgzTDEyNSA1Mi4xem0xNyA4My4zaC0zNGwxNy00MC45IDE3IDQwLjl6IiAvPgogIDwvc3ZnPg=="> </div> <h2>Here are some links to help you start: </h2> <ul> <li> <h2><a target="_blank" rel="noopener" href="https://angular.io/tutorial">Tour of Heroes</a></h2> </li> <li> <h2><a target="_blank" rel="noopener" href="https://github.com/angular/angular-cli/wiki">CLI Documentation</a></h2> </li> <li> <h2><a target="_blank" rel="noopener" href="https://blog.angular.io/">Angular blog</a></h2> </li> </ul>

دعنا نمضي قدمًا ونقوم بتحديث title من الفصل إلى 'My Memories!' .

 ... export class AppComponent { title = 'My Memories!'; } ...

سنرى المترجم يقوم بمعالجة التغيير وتحديث المتصفح لإظهار العنوان المحدث.

هذا يعني أن Angular 6's ng serve ساعات لتغييرات الملفات الخاصة بنا وعرضها في كل مرة يتم فيها إدخال تغيير في أي ملف.

من أجل جعل الترميز أكثر ملاءمة وتجنب تحديث الصفحة بالكامل في كل مرة نقوم فيها بإجراء تغييرات ، يمكننا الاستفادة من webpack Hot Module Replacement (HMR) ، الذي يقوم فقط بتحديث جزء JS / CSS الذي تم تغييره بدلاً من إنتاج تحديث كامل لـ تظهر التغييرات الخاصة بك.

تكوين HMR

أولاً ، نحن بحاجة إلى تهيئة البيئة.

قم بإنشاء ملف src/environments/environment.hmr.ts بالمحتويات التالية:

 export const environment = { production: false, hmr: true };

قم بتحديث src/environments/environment.prod.ts وأضف hmr: false flag إلى البيئة:

 export const environment = { production: true, hmr: false };

ثم حدِّث src/environments/environment.ts وأضف hmr: false flag إلى البيئة هناك أيضًا:

 export const environment = { production: false, hmr: false };

بعد ذلك في ملف angular.json ، قم بتحديث هذا الجزء:

 "projects": { "my-memories": { // ... "architect": { "build": { // ... "configurations": { "hmr":{ "fileReplacements":[ { "replace": "src/environments/environment.ts", "with": "src/environments/environment.hmr.ts" } ] }, // ...

وفي إطار projectsmy-memoriesarchitectserveconfigurations :

 "projects": { "my-memories": { "architect": { // ... "serve": { // ... "configurations": { "hmr": { "browserTarget": "my-memories:build:hmr" }, // ...

الآن قم بتحديث tsconfig.app.json لتضمين types الضرورية (حسنًا ، اكتب) عن طريق إضافة هذا ضمن خيارات compilerOptions :

 "compilerOptions": { // ... "types": [ "node" ]

بعد ذلك ، سنقوم بتثبيت الوحدة @angularclass/hmr للتطوير:

 npm install --save-dev @angularclass/hmr

ثم قم بتكوينه عن طريق إنشاء ملف src/hmr.ts :

 import { NgModuleRef, ApplicationRef } from '@angular/core'; import { createNewHosts } from '@angularclass/hmr'; export const hmrBootstrap = (module: any, bootstrap: () => Promise<NgModuleRef<any>>) => { let ngModule: NgModuleRef<any>; module.hot.accept(); bootstrap().then(mod => ngModule = mod); module.hot.dispose(() => { const appRef: ApplicationRef = ngModule.injector.get(ApplicationRef); const elements = appRef.components.map(c => c.location.nativeElement); const makeVisible = createNewHosts(elements); ngModule.destroy(); makeVisible(); }); };

بعد ذلك ، قم بتحديث src/main.ts لاستخدام الوظيفة المذكورة أعلاه:

 import { enableProdMode } from '@angular/core'; import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { AppModule } from './app/app.module'; import { environment } from './environments/environment'; import { hmrBootstrap } from './hmr'; if (environment.production) { enableProdMode(); } const bootstrap = () => platformBrowserDynamic().bootstrapModule(AppModule); if (environment.hmr) { if (module[ 'hot' ]) { hmrBootstrap(module, bootstrap); } else { console.error('HMR is not enabled for webpack-dev-server!'); console.log('Are you using the --hmr flag for ng serve?'); } } else { bootstrap().catch(err => console.log(err)); }

ما نقوم به هنا هو جعل استدعاء bootstrap وظيفة مجهولة ، ثم نسأل بعد ذلك ما إذا كانت علامة environment.hmr صحيحة. إذا كان الأمر كذلك ، فإننا نسمي الوظيفة المحددة مسبقًا من hmr.ts والتي مكنت من استبدال الوحدة الساخنة ؛ خلاف ذلك ، نقوم بتمهيده كما اعتدنا.

الآن ، عند تشغيل ng serve --hmr --configuration=hmr ، سنستدعي تكوين hmr ، وعندما نجري تغييرات على الملفات ، سنحصل على تحديثات بدون تحديث كامل. أول --hmr لـ webpack ، و--configuration --configuration=hmr مخصص لـ Angular لاستخدام بيئة hmr .

تطبيق الويب التقدمي (PWA)

لإضافة دعم Angular 6 PWA وتمكين التحميل دون اتصال للتطبيق ، يمكننا الاستفادة من أحد أوامر CLI الجديدة ، ng add :

 ng add @angular/[email protected]

لاحظ أنني أقوم بإضافة الإصدار ، نظرًا لأن أحدث إصدار عندما كنت أكتب هذا البرنامج التعليمي كان يتسبب في حدوث خطأ. (يمكنك المحاولة بدونها ومعرفة ما إذا كانت تعمل من أجلك باستخدام ng add @angular/pwa .)

حسنًا ، بعد تشغيل الأمر ، سنرى الكثير من التغييرات في مشروعنا. أهم التغييرات أنها أضافت:

  • مرجع لـ manifest.json في ملف أصول angular.json ، بحيث يتم تضمينه في مخرجات الإنشاء ، بالإضافة إلى "serviceWorker": true في إصدارات الإنتاج
  • ملف ngsw-config.json مع الإعداد الأولي لتخزين جميع الملفات اللازمة لتشغيل التطبيق مؤقتًا
  • العلامة الوصفية manifest.json في ملف index.html
  • ملف manifest.json نفسه ، مع تكوين أساسي للتطبيق
  • تحميل عامل الخدمة في وحدة التطبيق ServiceWorkerModule.register('/ngsw-worker.js', { enabled: environment.production }) (لاحظ أنه سيتم تمكين عامل الخدمة فقط في بيئات الإنتاج)

لذلك ، هذا يعني الآن أنه عندما يصل المستخدم لأول مرة إلى عنوان URL ، سيتم تنزيل الملفات. بعد ذلك ، إذا حاول المستخدم الوصول إلى عنوان URL بدون خدمة الشبكة ، فسيظل التطبيق يعمل عن طريق سحب تلك الملفات المخزنة مؤقتًا.

إضافة مكتبة Material Angular 6 UI

حتى الآن لدينا الإعداد الأولي ، ونحن جاهزون لبدء إنشاء تطبيقنا. للاستفادة من المكونات التي تم إنشاؤها بالفعل ، يمكننا استخدام إصدار Angular 6 من المواد.

لتثبيت الحزمة material على تطبيقنا ، سنستخدم ng add مرة أخرى:

 ng add @angular/material

بعد تشغيل ذلك ، سنرى بعض الحزم الجديدة المضافة وبعض تكوين النمط الأساسي:

  • يتضمن index.html خط Roboto ورموز المواد
  • تمت إضافة BrowserAnimationsModule إلى AppModule بنا
  • يحتوي angular.json على المظهر النيلي الوردي المتضمن بالفعل بالنسبة لنا

للإشارة إلى اختيارك لمظهر Angular 6 الذي تم إنشاؤه مسبقًا

ستحتاج إلى إعادة تشغيل ng serve لالتقاط المظهر ، أو يمكنك اختيار سمة أخرى تم إنشاؤها مسبقًا.

الموضوعات ذات الصلة: أنشئ تطبيقات ويب فائقة الحداثة باستخدام مادة زاويّة

التخطيط الأساسي

للحصول على تخطيط sidenav الأولي ، سنستخدم المخططات التي تأتي مع Material. لكن لا بأس إذا كنت تريد استخدام تخطيط مختلف.

(باختصار ، تتيح لك المخططات تطبيق تحويلات على مشروع: يمكنك إنشاء ملفات أو تعديلها أو حذفها حسب الحاجة. في هذه الحالة ، فإنها تدعم تخطيط sidenav لتطبيقنا.)

 ng generate @angular/material:material-nav --name=my-nav

سيؤدي هذا إلى إنشاء مكون sidenav مع الحد الأدنى من الإعداد الجاهز للبدء. أليس هذا رائعًا؟

لقد تضمنت أيضًا جميع الوحدات الضرورية في app.module.ts بنا.

مكون Angular 6 الذي تم إنشاؤه حديثًا "my-nav"

نظرًا لأننا نستخدم SCSS ، فنحن بحاجة إلى إعادة تسمية ملف my-nav.component.css إلى my-nav.component.scss ، وفي my-nav.component.ts styleUrls أسلوب المرجع المقابل لاستخدام الاسم الجديد.

الآن للاستفادة من المكون الجديد ، دعنا نذهب إلى app.component.html كل الكود الأولي ، مع ترك:

 <app-my-nav></app-my-nav>

عندما نعود إلى المتصفح ، هذا ما سنراه:

تخطيط من أربعة أجزاء مع قائمة في الزاوية العلوية اليسرى ، وذكرياتي بجانبها ، وثلاثة روابط مرقمة ضمن القائمة ؛ الجزء الرابع فارغ

دعنا نقوم بتحديث الروابط للحصول على الخيارين اللذين نريدهما فقط.

أولاً ، لنقم بإنشاء مكونين جديدين:

 ng gc AddMemory ng generate @angular/material:material-table --name=view-memories

(الثاني هو مخطط مادي يستخدم لإنشاء جدول.)

بعد ذلك ، في my-nav سنقوم بالتحديث لإعداد الروابط وتضمين <router-outlet> لعرض مكونات المحتوى الخاصة بنا:

 <mat-sidenav-container class="sidenav-container"> <mat-sidenav #drawer class="sidenav" fixedInViewport="true" [attr.role]="(isHandset$ | async) ? 'dialog' : 'navigation'" [mode]="(isHandset$ | async) ? 'over' : 'side'" [opened]="!(isHandset$ | async)"> <mat-toolbar color="primary">Menu</mat-toolbar> <mat-nav-list> <a mat-list-item [routerLink]="['/add-memory']">Add Memory</a> <a mat-list-item [routerLink]="['/view-memories']">View My Memories</a> </mat-nav-list> </mat-sidenav> <mat-sidenav-content> <mat-toolbar color="primary"> <button type="button" aria-label="Toggle sidenav" mat-icon-button (click)="drawer.toggle()" *ngIf="isHandset$ | async"> <mat-icon aria-label="Side nav toggle icon">menu</mat-icon> </button> <span>my-memories</span> </mat-toolbar> <router-outlet></router-outlet> </mat-sidenav-content> </mat-sidenav-container>

أيضًا ، في app.component.html نحتاج إلى تحديثه لمجرد الحصول على <router-outlet> الرئيسي (على سبيل المثال ، إزالة <my-nav> ):

 <router-outlet></router-outlet>

بعد ذلك ، في AppModule سنقوم بتضمين المسارات:

 import { RouterModule, Routes } from '@angular/router'; // ... imports: [ // ... RouterModule.forRoot([ { path: '', component: MyNavComponent, children: [ { path: 'add-memory', component: AddMemoryComponent }, { path: 'view-memories', component: ViewMemoriesComponent } ] }, ]), ]

لاحظ أننا نقوم بتعيين MyNavComponent باعتباره الوالد والمكونين اللذين أنشأناهما كأطفال. هذا لأننا قمنا بتضمين <router-outlet> في MyNavComponent ، وكلما وصلنا إلى أحد هذين المسارين ، سنعرض المكون الفرعي حيث تم وضع <router-outlet> .

بعد ذلك ، عندما نخدم التطبيق ، يجب أن نرى:

تم استبدال الروابط الموجودة على اليسار بـ Add Memory و View My Memories ، مع تحديد الأخير. يحتوي الجزء الفارغ الآن على جدول بأرقام المعرفات والأسماء.

بناء التطبيق (مذكرات ذكريات)

حسنًا ، لنقم الآن بإنشاء النموذج لحفظ الذكريات الجديدة في يومياتنا.

سنحتاج إلى استيراد بعض وحدات المواد ووحدة النماذج إلى app.module.ts بنا:

 import { FormsModule } from '@angular/forms'; import { MatCardModule, MatFormFieldModule, MatInputModule, MatDatepickerModule, MatNativeDateModule } from '@angular/material'; // ... Imports:[ // ... MatCardModule, MatFormFieldModule, MatInputModule, MatDatepickerModule, FormsModule, MatNativeDateModule, // ... ]

ثم في add-memory.component.html ، سنضيف النموذج:

 <form #form="ngForm" (ngSubmit)="onSubmit()"> <mat-card class="memory-card"> <mat-card-title> Add a memory </mat-card-title> <mat-card-content> <mat-form-field> <input disabled matInput placeholder="Select the date..." [(ngModel)]="memory.date" name="date" [matDatepicker]="date"> <mat-datepicker-toggle matSuffix [for]="date"></mat-datepicker-toggle> <mat-datepicker disabled="false" #date></mat-datepicker> </mat-form-field> <mat-form-field> <textarea placeholder="Enter your memory..." rows="3" maxlength="300" matInput [(ngModel)]="memory.text" name="memory"></textarea> </mat-form-field> </mat-card-content> <mat-card-actions> <button mat-button type="submit">Save me!</button> </mat-card-actions> </mat-card> </form> <pre> {{ memory | json }} </pre>

نحن هنا نستخدم mat-card ونضيف حقلين ، date ومنطقة textarea .

لاحظ أننا نستخدم [(ngModel)] . هذا التوجيه الزاوي سوف يربط التعبير memory.date وخاصية memory في الفصل ببعضهما البعض ، كما سنرى لاحقًا. ( [(ngModel)] عبارة عن سكر نحوي - اختصار لتنفيذ ربط البيانات ثنائي الاتجاه من الفصل إلى العرض ومن العرض إلى الفصل الدراسي. وهذا يعني أنه عند إدخال نص في العرض ، فإن memory.date سيعكس هذه التغييرات في مثيل الفئة ، وإذا أجريت تغييرات على memory.date في مثيل الفئة ، فسوف يعكس العرض التغييرات.)

في add-memory.component.ts ، سيبدو الرمز كما يلي:

 import { Component, OnInit } from '@angular/core'; @Component({ selector: 'app-add-memory', templateUrl: './add-memory.component.html', styleUrls: ['./add-memory.component.scss'] }) export class AddMemoryComponent implements OnInit { memory: any = {}; constructor() { } ngOnInit() { } onSubmit() { console.log(this.memory); } }

هنا ، نقوم بتهيئة خاصية memory المرتبطة عبر ngModel . عند إنشاء مثيل لمكون AddMemoryComponent ، ستكون memory كائنًا فارغًا. ثم عند تشغيل التوجيه ngModel ، سيكون قادرًا على تعيين قيمة الإدخال إلى memory.date و memory.text . إذا لم نفعل ذلك ، فسنحصل على خطأ Cannot set property 'date/text' of undefined .

في غضون ذلك ، يجب أن يكون لدى add-memory.component.scss ما يلي:

 .memory-card { min-width: 150px; max-width: 400px; width: 100%; margin: auto; } .mat-form-field { width: 100%; }

بما أن لدينا <pre> {{ memory | json }} </pre> <pre> {{ memory | json }} </pre> يمكننا أن نرى الحالة الحالية memory في العرض. إذا انتقلنا إلى المتصفح ، فإليك النتيجة حتى الآن:

النموذج الأولي لتطبيق مذكرات "ذكرياتي" ، والذي يُظهر التمثيل الداخلي لإدخال المستخدم (التاريخ والنص.)

في طريقة العرض ، قمنا بربط النموذج عبر (ngSubmit)="onSubmit()" بوظيفة onSubmit في الفصل.

 onSubmit() { console.log(this.memory); }

لذلك عندما تنقر على زر "Save me!" الزر ، ستحصل على التمثيل الداخلي لإدخال المستخدم المرسل إلى سجل وحدة التحكم:

التمثيل الداخلي لإدخال المستخدم في سجل وحدة التحكم.

Angular 6 Tutorial: Connecting with Firebase

ما سنفعله بعد ذلك هو توصيل مشروعنا بـ Firebase من أجل حفظ ذاكرتنا.

أولاً ، سنذهب إلى وحدة تحكم Firebase وننشئ مشروعًا هناك.

إضافة مشروع Firebase.

ثانيًا ، سنقوم بتثبيت حزمتي firebase و angularfire2 :

 npm install firebase angularfire2 --save

ثم في كل ملف من هذه الملفات الثلاثة:

  1. /src/environments/environment.ts
  2. /src/environments/environment.hmr.ts
  3. /src/environments/environment.prod.ts

... سنضيف تهيئة Firebase الخاصة بنا:

 export const environment = { // ... firebase: { apiKey: '<your-key>', authDomain: '<your-project-authdomain>', databaseURL: '<your-database-URL>', projectId: '<your-project-id>', storageBucket: '<your-storage-bucket>', messagingSenderId: '<your-messaging-sender-id>' } };

يمكنك الحصول على تفاصيل التكوين المطلوبة للملفات أعلاه بالنقر فوق "إضافة Firebase إلى تطبيق الويب الخاص بك" في صفحة نظرة عامة على المشروع.

بعد ذلك ، سنقوم بتضمين وحدات Firebase في app.module.ts لدينا:

 import { AngularFireModule } from 'angularfire2'; import { AngularFireDatabaseModule } from 'angularfire2/database'; import { environment } from '../environments/environment'; // ... Imports:[ // ... AngularFireModule.initializeApp(environment.firebase), AngularFireDatabaseModule, // ... ]

وفي add-memory.component.ts ، نقوم بحقن قاعدة البيانات في المُنشئ وحفظ القيم من النموذج إلى قاعدة البيانات. عندما ينجح وعد الدفع من Firebase ، نسجل النجاح في وحدة التحكم ونعيد ضبط النموذج:

 import { AngularFireDatabase } from 'angularfire2/database'; // ... constructor(private db: AngularFireDatabase) { } // ... onSubmit() { this.memory.date = new Date(this.memory.date).valueOf(); this.db.list('memories').push(this.memory) .then(_ => { this.memory = {} console.log('success') }) } 

السماح بالوصول للقراءة والكتابة إلى قاعدة بيانات Firebase.

ستحتاج إلى السماح بالوصول العام إلى قواعد قاعدة البيانات ، حتى يتمكن المستخدمون المجهولون من القراءة والكتابة عليها. يرجى ملاحظة أنه مع هذا الإعداد ، سيتمكن أي مستخدم من قراءة / تغيير / حذف بيانات التطبيق الخاص بك. تأكد من إعداد القواعد الخاصة بك وفقًا لذلك قبل الانتقال إلى الإنتاج.

أيضًا ، لالتقاط تغييرات البيئة ، ستحتاج إلى إعادة تشغيل عملية ng serve .

الآن ، عندما نعود إلى المتصفح وننقر على زر الحفظ ، سنرى أن الذاكرة تمت إضافتها إلى قاعدة البيانات:

تمت إضافة ذاكرة الاختبار الخاصة بنا إلى قاعدة بيانات Firebase لتطبيق اليوميات.

دعنا نلقي نظرة على كيفية استرداد ذكرياتنا وعرضها في جدول المواد.

مرة أخرى عندما أنشأنا الجدول باستخدام ng generate @angular/material:material-table --name=view-memories', we automatically got a file view-memory / view-memory-datasource.ts`. يحتوي هذا الملف على بيانات مزيفة ، لذا سنحتاج إلى تغييره لبدء السحب من Firebase.

في view-memories-datasource.ts ، سنزيل EXAMPLE_DATA مصفوفة فارغة:

 export class ViewMemoriesDataSource extends DataSource<ViewMemoriesItem> { data: ViewMemoriesItem[] = []; // ...

وفي getSortedData سنقوم بتحديث أسماء الحقول:

 private getSortedData(data: ViewMemoriesItem[]) { if (!this.sort.active || this.sort.direction === '') { return data; } return data.sort((a, b) => { const isAsc = this.sort.direction === 'asc'; switch (this.sort.active) { case 'text': return compare(a.name, b.name, isAsc); case 'date': return compare(+a.id, +b.id, isAsc); default: return 0; } }); }

في view-memories.component.html سنقوم بتحديث أسماء الأعمدة حتى date text من نموذج ذاكرتنا. لاحظ أنه نظرًا لأننا حفظنا التاريخ بتنسيق ملي ثانية ، فإننا هنا نستخدم أنبوب التاريخ لتحويل القيمة للعرض بتنسيق تاريخ أكثر ملاءمةً للإنسان. أخيرًا ، [length]="dataSource.data.length" من الفاصل الزمني ، نظرًا لأننا سنحمل البيانات بشكل غير متزامن من Firebase:

 <div class="mat-elevation-z8"> <table mat-table #table [dataSource]="dataSource" matSort aria-label="Elements"> <!-- Id Column --> <ng-container matColumnDef="date"> <th mat-header-cell *matHeaderCellDef mat-sort-header>Date</th> <td mat-cell *matCellDef="let row">{{row.date | date:'short'}}</td> </ng-container> <!-- Name Column --> <ng-container matColumnDef="text"> <th mat-header-cell *matHeaderCellDef mat-sort-header>Text</th> <td mat-cell *matCellDef="let row">{{row.text}}</td> </ng-container> <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr> <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr> </table> <mat-paginator #paginator [pageIndex]="0" [pageSize]="50" [pageSizeOptions]="[25, 50, 100, 250]"> </mat-paginator> </div>

قم بتغيير view-memories.component.css إلى view-memories.component.scss وقم بتعيين نمط الجدول:

 table{ width: 100%; }

في view-memories.component.ts Memories.component.ts ، سنقوم بتغيير styleUrls لتعكس إعادة التسمية أعلاه إلى ./view-memories.component.scss . سنقوم أيضًا بتحديث مصفوفة الأعمدة displayedColumns لتكون ['date', 'text'] وإعداد مصدر بيانات الجدول للحصول على البيانات من Firebase.

ما يحدث هنا هو أننا مشتركون في قائمة الذكريات وعندما نتلقى البيانات ، نقوم بإنشاء مثيل ViewMemoriesDataSource بتعيين خاصية البيانات الخاصة به باستخدام البيانات من Firebase.

 this.subscription = this.db.list<ViewMemoriesItem>('memories').valueChanges().subscribe(d=>{ console.log('data streaming'); this.dataSource = new ViewMemoriesDataSource(this.paginator, this.sort); this.dataSource.data = d; });

يقوم Firebase بإرجاع مصفوفة يمكن ملاحظتها على نمط ReactiveX.

لاحظ أننا this.db.list<ViewMemoriesItem>('memories') - القيم المسحوبة من مسار 'memories' - إلى ViewMemoriesItem . يتم الاهتمام بهذا الأمر من خلال مكتبة angularfire2 .

قمنا أيضًا بتضمين استدعاء unsubscribe في خطاف onDestroy لدورة حياة المكون الزاوي.

 import { Component, OnInit, ViewChild, OnDestroy } from '@angular/core'; import { MatPaginator, MatSort } from '@angular/material'; import { ViewMemoriesDataSource, ViewMemoriesItem } from './view-memories-datasource'; import { AngularFireDatabase } from 'angularfire2/database'; import { Subscription } from 'rxjs'; import { map, first } from 'rxjs/operators'; @Component({ selector: 'app-view-memories', templateUrl: './view-memories.component.html', styleUrls: ['./view-memories.component.scss'] }) export class ViewMemoriesComponent implements OnInit, OnDestroy{ @ViewChild(MatPaginator) paginator: MatPaginator; @ViewChild(MatSort) sort: MatSort; dataSource: ViewMemoriesDataSource; /** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */ displayedColumns = ['date', 'text']; subscription: Subscription; constructor(private db: AngularFireDatabase) { } ngOnInit() { this.subscription = this.db.list<ViewMemoriesItem>('memories').valueChanges().subscribe(d=>{ console.log('data streaming'); this.dataSource = new ViewMemoriesDataSource(this.paginator, this.sort); this.dataSource.data = d; }); } ngOnDestroy(): void { this.subscription.unsubscribe(); } }
الموضوعات ذات الصلة: إنشاء تطبيقات جوال متعددة الأنظمة الأساسية في الوقت الفعلي: أمثلة باستخدام Ionic Framework و Firebase

النشر في Firebase Hosting

الآن ، لجعل تطبيقنا مباشرًا ، دعنا ننشره في Firebase Hosting. لذلك ، سنقوم بتثبيت Firebase CLI ، مما يجعل الأمر firebase متاحًا:

 npm install -g firebase-tools

يمكننا الآن استخدام Firebase CLI لتسجيل الدخول:

 firebase login

سيطالبك هذا بتحديد حساب Google الخاص بك.

بعد ذلك ، سنبدأ في تهيئة المشروع وتهيئة استضافة Firebase:

 firebase init

سنقوم فقط بتحديد خيار الاستضافة.

بعد ذلك ، عندما يُطلب منا المسار ، dist/my-memories . عندما يُطلب منا تهيئته كتطبيق من صفحة واحدة (أي إعادة كتابة جميع عناوين URL إلى /index.html ) ، سنرد بـ "نعم".

أخيرًا ، سنضغط ، "File dist / my-الذكريات / index.html موجود بالفعل. الكتابة فوق؟" هنا سنقول "لا".

سيؤدي ذلك إلى إنشاء ملفات تكوين .firebaserc و firebase.json بالتهيئة المتوفرة.

الخطوة الأخيرة هي تشغيل:

 ng build --prod firebase deploy

وبهذا نكون قد نشرنا التطبيق على Firebase ، والذي يوفر لنا عنوان URL للانتقال إليه ، مثل https://my-memories-b4c52.firebaseapp.com/view-memories ، حيث يمكنك عرض خاصتي المنشورة تجريبي.


رائع ، لقد مررت بهذا البرنامج التعليمي! اتمنى ان تكون قد استمتعت به. يمكنك أيضًا التحقق من الكود الكامل له على GitHub.

خطوة واحدة في وقت واحد

Angular هو إطار عمل قوي جدًا لبناء تطبيقات الويب. إنه موجود منذ فترة طويلة وقد أثبت جدارته في التطبيقات الصغيرة والبسيطة والتطبيقات الكبيرة والمعقدة على حدٍ سواء - Angular 6 ليست استثناءً هنا.

للمضي قدمًا ، تخطط Angular لمواصلة تحسين واتباع نماذج الويب الجديدة مثل مكونات الويب (Angular Elements). إذا كنت مهتمًا بإنشاء تطبيقات مختلطة ، فيمكنك التحقق من Ionic ، التي تستخدم Angular كإطار أساسي لها.

غطى هذا البرنامج التعليمي الخطوات الأساسية جدًا لبدء استخدام Angular و Material و Firebase. لكن يجب أن تأخذ في الاعتبار أنه بالنسبة للتطبيقات الواقعية ، ستحتاج إلى إضافة التحقق من الصحة ، ولتسهيل صيانة التطبيق وتوسيع نطاقه ، ربما ترغب في اتباع أفضل الممارسات مثل استخدام الخدمات والمكونات القابلة لإعادة الاستخدام وما إلى ذلك. . يجب أن يكون هذا موضوع مقال آخر - آمل أن يكون هذا المقال كافياً لإثارة شهيتك لتنمية Angular!

الموضوعات ذات الصلة: جميع الامتيازات ، بلا متاعب: دروس 9 Angular