بُني هذا المقال على الخطوة الأولى من سلسلة المقالات التعليمية لتعلم استعمال Angular عبر بناء تطبيق تجارة إلكترونية، حيث يحتوي تطبيق المتجر عبر الانترنت في هذه المرحلة من التطوير على قائمة المنتجات الأساسية، كما ستضيف في الأقسام التالية الميزات التالية إلى التطبيق:
- اكتب عنوان URL في شريط العنوان للانتقال إلى صفحة المنتج المقابلة له.
- انقر فوق الروابط الموجودة في الصفحة للتنقل داخل تطبيق الصفحة الواحدة الخاص بك.
- انقر على زرَّي الانتقال للخلف والأمام للمتصفح للتنقل في سجل المتصفح تلقائيًا.
- تحديث قسم العرض الخاص بتفاصيل المنتج ليتضمن زر الشراء الذي يضيف المنتج الحالي إلى قائمة منتجات تديرها خدمة سلة التسوق.
- إضافة مكوِّن السلة الذي يعرض العناصر الموجودة في السلة.
-
إضافة مكوِّن الشحن الذي يعيد أسعار الشحن للعناصر الموجودة في السلة باستخدام
HttpClient
الخاص بـ Angular لاستعادة بيانات الشحن من ملفjson.
.
هذه المقال جزءٌ من سلسلة مقالات حول بناء تطبيق تجارة إلكترونية عبر Angular:
- ما هي Angular؟
- كيفية استعمال Angular في بناء تطبيقات الويب
- إضافة التنقل وإدارة البيانات في تطبيق Angular
- تهيئة بيئة تطبيقات Angular ونشرها على الويب
ربط مسار URL مع مكون
يستخدم التطبيق الموجِّه Router من Angular للانتقال إلى المكوِّن ProductListComponent
افتراضيًا، حيث يوضِّح هذا القسم كيفية تعريف الوجهة لعرض تفاصيل المنتجات بصورة فردية.
نبدأ أولًا بتوليد مكون جديد باسم product-details
لعرض تفاصيل المنتج وذلك بتنفيذ الأمر التالي:
ng generate component product-details
بعد ذلك أضف وجهة لتفاصيل المنتج في app.module.ts
من خلال استخدام path
مع القيمة products/:productId
وضبط component
إلى المكون ProductDetailsComponent
.
- الملف src/app/app.module.ts:
@NgModule({ imports: [ BrowserModule, ReactiveFormsModule, RouterModule.forRoot([ { path: '', component: ProductListComponent }, { path: 'products/:productId', component: ProductDetailsComponent }, ]) ],
افتح product-list.component.html
، وعدِّل المِربط الخاص باسم المنتج ليتضمن routerLink
مع استخدام product.id
على أساس معامِل.
- الملف src/app/product-list/product-list.component.html:
<div *ngFor="let product of products"> <h3> <a [title]="product.name + ' details'" [routerLink]="['/products', product.id]"> {{ product.name }} </a> </h3> <!-- . . . --> </div>
يساعدك الموجِّه RouterLink
على تخصيص الرابط، حيث يحتوي الموجه أو العنوان في هذه الحالة على جزء واحد ثابت هو /products
، ويكون الجزء الأخير متغيرًا يتمثَّل في إدراج الخاصية id
للمنتج الحالي، حيث سيكون العنوان URL مثلًا لمنتج يملك المُعرِّف 1 مشابهًا للعنوان https://getting-started-myfork.stackblitz.io/products/1
أخيرًا، تحقّق من عمل الموجِّه على النحو المطلوب من خلال النقر على اسم المنتج، حيث يجب أن يعرض التطبيق المكوِّن ProductDetailsComponent
والذي سيعرض رسالة "product-details works" أي صفحة تفاصيل المنتج تعمل!، ولاحظ أنَّ العنوان في نافذة المعاينة يتغير، كما يكون الجزء الأخير هو products/#
حيث تمثّل #
رقم المسار الذي نقرت عليه.
عرض تفاصيل المنتج
يعالِج ProductDetailsComponent
طريقة عرض كل منتج، يعرض موجِّه Angular المكوِّنات اعتمادًا على عنوان المتصفح والمسارات التي حددتها، كما ستستخدِم في هذا القسم موجِّه Angular لدمج بيانات المنتجات products
ومعلومات المسار لعرض التفاصيل الخاصة لكل منتج.
بدايةً، استورد ActivatedRoute
من @angular/router
ومصفوفة المنتجات products
من ../products
في ملف product-details.component.ts
.
- الملف src/app/product-details/product-details.component.ts:
import { Component, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { Product, products } from '../products';
حدِّد خاصية product
.
- الملف src/app/product-details/product-details.component.ts:
export class ProductDetailsComponent implements OnInit { product: Product|undefined; /* ... */ }
احقن ActivatedRoute
في الباني constructor()
عن طريق إضافة private route: ActivatedRoute
على أساس وسيط ضمن أقواس الباني.
- الملف src/app/product-details/product-details.component.ts:
export class ProductDetailsComponent implements OnInit { product: Product|undefined; constructor(private route: ActivatedRoute) { } }
يوجد صنف يدعى ActivatedRoute
لكل مكوِّن يحمِّله موجّه Angular بحيث يحتوي على معلومات حول الموجه route ومعامِلاته، كما تُهيّئ المكوِّن ليستخدِم خدمة عن طريق حقن ActivatedRoute
، وسنغطي ذلك في خطوة إدارة البيانات بتفصيل أكثر.
استخرج productId
من معامِلات المسار في دالة ngOnInit()
واعثر على المنتج المقابل له ضمن مصفوفة products
.
- الملف src/app/product-details/product-details.component.ts:
ngOnInit() { // First get the product id from the current route. const routeParams = this.route.snapshot.paramMap; const productIdFromRoute = Number(routeParams.get('productId')); // Find the product that correspond with the id provided in route. this.product = products.find(product => product.id === productIdFromRoute); }
تقابل معامِلات المسار متغيرات المسار التي حدَّدتها في المسار، حيث نستخدِم route.snapshot
للوصول إلى معاملات الموجه والذي يُعَدّ ActivatedRouteSnapshot
ويحوي معلومات حول الموجه النشط في لحظة معينة من الزمن، كما يوفِّر العنوان الذي يطابق موجه productId
، حيث يستخدِم Angular معرف المنتج productId
لعرض تفاصيل كل منتج فريد.
حدِّث قالب ProductDetailsComponent
لعرض تفاصيل المنتج باستخدام *ngIf، فإذا كان المنتج منتج موجودًا، فسيعرض محتوى <div>
مع اسم وسعر وتوصيف المنتج.
- الملف src/app/product-details/product-details.component.html
<h2>Product Details</h2> <div *ngIf="product"> <h3>{{ product.name }}</h3> <h4>{{ product.price | currency }}</h4> <p>{{ product.description }}</p> </div>
يستخدِم السطر <h4>{{ product.price | currency }}</h4>
الأنابيب العملة currency
لتحويل قيمة product.price
من عدد إلى سلسلة نصية بصيغة عملة، حيث يُعَدّ الأنبوب طريقةً يمكنك من خلالها تحويل البيانات الموجودة في قالب HTML الخاص بك.
عندما ينقر المستخدمون على اسم في قائمة المنتجات، ينقلهم الموجِّه إلى العنوان المميز للمنتج ويعرِض ProductDetailsComponent
ويعرض تفاصيل المنتج.
يحتوي تطبيق المتجر في هذه المرحلة من التطوير على فئات المنتجات مع قسمي عرض هما قائمة المنتجات وتفاصيل المنتج، حيث يمكن للمستخدِمين النقر على اسم المنتج من قائمة المنتجات لمشاهدة تفاصيله في قسم عرض جديد مع رابط مميز أو مسار، وسنكمل إضافة ميزة سلة التسوق وإدارة بياناتها للتطبيق.
إنشاء خدمة سلة التسوق
تُعَدّ الخدمة service في Angular نسخةً من صنف تجعله متاحًا لأي جزء من أجزاء التطبيق الخاص بك باستخدام نظام حقن التبعية في Angular، كما يمكن للمستخدمين حاليًا عرض معلومات المنتج، ويمكن للتطبيق أن يحاكي المشاركة والإشعارات في حال حدوث تغييرات في المنتج، وتكون الخطوة التالية هي بناء طريقة تمكِّن المستخدِمين من إضافة منتجات إلى السلة، حيث يرشدك هذا المقال من خلال عملية إضافة زر الشراء وإعداد خدمة السلة لتخزين المعلومات حول المنتجات ضمن السلة.
تعريف خدمة السلة
لإنشاء خدمة السلة، استعمل الطرفية ونفذ الأمر التالي لتوليد خدمة باسم cart
:
ng generate service cart
- الملف src/app/cart.service.ts:
import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root' }) export class CartService { constructor() {} }
استورد واجهة Product
من ./products.ts
ضمن cart.service.ts
، وعرّف خاصيةً باسم items
في صنف CartService
لتخزين مصفوفة المنتجات الحالية الموجودة في سلة التسوق.
- الملف src/app/cart.service.ts:
import { Product } from './products'; /* . . . */ export class CartService { items: Product[] = []; /* . . . */ }
عرِّف التوابع المسؤولة عن إضافة عناصر إلى سلة التسوق وإعادة عناصر سلة التسوق ومسح عناصر سلة التسوق.
- الملف src/app/cart.service.ts:
export class CartService { items: Product[] = []; /* . . . */ addToCart(product: Product) { this.items.push(product); } getItems() { return this.items; } clearCart() { this.items = []; return this.items; } /* . . . */ }
شرح التوابع السابقة المعرفة:
-
addToCart()
: يضيف منتجًا إلى مصفوفةitems
. -
getItems()
: يجمِّع العناصر التي يضيفها المستخدمون إلى سلة التسوق ويُعيد كل عنصر مع الكمية المرتبطة به. -
clearCart()
: يعيد مصفوفةً فارغةً من العناصر، أي أنه يُفرِّغ السلة من العناصر الموجودة فيها.
استخدم خدمة السلة
سنبرمج الآن عملية إضافة منتج إلى السلة عن طريق استخدام الخدمة CartService
.
أولًا، استورد خدمة السلة في ملف product-details.component.ts
.
- الملف src/app/product-details/product-details.component.ts:
import { Component, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { Product, products } from '../products'; import { CartService } from '../cart.service';
ثانيًا، احقن خدمة السلة عن طريق إضافتها إلى الباني constructor()
.
- الملف src/app/product-details/product-details.component.ts:
export class ProductDetailsComponent implements OnInit { constructor( private route: ActivatedRoute, private cartService: CartService ) { } }
ثالثًا، عرِّف التابع addToCart()
الذي تضيف المنتج الحالي إلى سلة التسوق.
- الملف src/app/product-details/product-details.component.ts:
export class ProductDetailsComponent implements OnInit { addToCart(product: Product) { this.cartService.addToCart(product); window.alert('Your product has been added to the cart!'); } }
يفعل التابع addToCart()
ما يلي:
-
يأخذ المنتج الحالي
product
على أساس وسيط. -
يستخدِم التابع
addToCart()
الموجود ضمنCartService
لإضافة المنتج إلى السلة. - يعرض رسالةً تخبرنا بأنه قد أُضيف منتج إلى السلة.
رابعًا، أضف زر الشراء في ملف product-details.component.html
واربط الحدث click()
إلى التابع addToCart()
، إذ تحدِّث هذه الشيفرة قالب تفاصيل المنتج بإضافة زر الشراء المسؤول عن إضافة المنتج الحالي إلى سلة التسوق.
- الملف src/app/product-details/product-details.component.html:
<h2>Product Details</h2> <div *ngIf="product"> <h3>{{ product.name }}</h3> <h4>{{ product.price | currency }}</h4> <p>{{ product.description }}</p> <button (click)="addToCart(product)">Buy</button> </div>
خامسًا، تحقّق من ظهور زر الشراء الجديد كما هو متوقَّع من خلال تحديث التطبيق والنقر على اسم المنتج لعرض تفاصيله.
أخيرًا، انقر على زر الشراء لإضافة المنتج إلى قائمة العناصر المخزنة في سلة التسوق وعرض رسالة تأكيد.
إنشاء قسم العرض الخاص بالسلة
يمكنك إنشاء قسم العرض الخاص بسلة التسوق لكي يتمكن العملاء من رؤية سلة التسوق الخاصة بهم وذلك بخطوتين:
- أنشئ مكوِّن السلة وهيّئ التوجيه إلى هذا المكوِّن الجديد.
- اعرض العناصر الموجودة في السلة.
إعداد مكون السلة
اتبع الخطوات نفسها التي استخدمتها في إنشاء ProductDetailsComponent
من أجل إنشاء قسم العرض الخاص بالسلة وهيِّئ التوجيه لهذا المكون الجديد.
بدايةً، أنشئ مكونًا جديدًا باسم cart
يمثل السلة بتنفيذ الأمر التالي في الطرفية:
ng generate component cart
سيولد هذا الأمر الملف cart.component.ts الخاص بالمكون وقالبه وملفات تنسيقاته.
- الملف src/app/cart/cart.component.ts:
import { Component } from '@angular/core'; @Component({ selector: 'app-cart', templateUrl: './cart.component.html', styleUrls: ['./cart.component.css'] }) export class CartComponent { constructor() { } }
ينشئ StackBlitz -الذي ضبطناه في المقال الأول ببداية المشروع- أيضًا تابع ngOnInit()
في المكونات افتراضيًا، ويمكنك تجاهل ngOnInit()
الخاصة بالمكون CartComponent
في هذا المقال.
لاحظ أن المكون CartComponent
المولد حديثًا يضاف إلى قسم التصريحات declarations
في الملف app.module.ts.
- الملف src/app/app.module.ts:
import { CartComponent } from './cart/cart.component'; @NgModule({ declarations: [ AppComponent, TopBarComponent, ProductListComponent, ProductAlertsComponent, ProductDetailsComponent, CartComponent, ],
أبقَ في الملف app.module.ts
وأضف فيه وجهة لمكون CartComponent
، مع تعيين قيمة path
إلى القيمة cart
.
- الملف src/app/app.module.ts:
@NgModule({ imports: [ BrowserModule, ReactiveFormsModule, RouterModule.forRoot([ { path: '', component: ProductListComponent }, { path: 'products/:productId', component: ProductDetailsComponent }, { path: 'cart', component: CartComponent }, ]) ],
حدِّث زر الدفع بحيث يوجِّه إلى الرابط /cart
، وأضف موجِّه routerLink يشير إلى /cart
في ملف top-bar.component.html
.
- الملف src/app/top-bar/top-bar.component.html:
<a routerLink="/cart" class="button fancy-button"> <i class="material-icons">shopping_cart</i>Checkout </a>
تحقّق من عمل CartComponent
كما هو متوقَّع من خلال النقر على زر الدفع، حيث يمكنك رؤية النص الافتراضي الذي وضعناه "السلة تعمل!"، ويملك الرابط النمط https://getting-started.stackblitz.io/cart
، حيث أنَّ getting-started.stackblitz.io
قد تكون مختلفةً في مشروع StackBlitz الخاص بك.
عرض عناصر السلة
سنعمل في هذا القسم على عرض المنتجات في السلة عن طريق استخدام خدمة السلة.
بدايةً، استورد CartService
في ملف cart.component.ts
من ملف cart.service.ts
.
- الملف src/app/cart/cart.component.ts:
import { Component } from '@angular/core'; import { CartService } from '../cart.service';
احقن الخدمة CartService
بحيث يتمكن المكون CartComponent
من استخدامه عن طريق إضافته إلى الباني constructor()
.
- الملف src/app/cart/cart.component.ts:
export class CartComponent { constructor( private cartService: CartService ) { } }
عرِّف الخاصية items
لتخزين المنتجات في السلة.
- الملف src/app/cart/cart.component.ts:
export class CartComponent { items = this.cartService.getItems(); constructor( private cartService: CartService ) { } }
تحدد هذه الشيفرة العناصر عن طريق تابع getItems()
الموجودة ضمن CartService
، ولقد عرَّفت هذا التابع عندما أنشأت cart.service.ts
.
حدِّث قالب السلة مع إضافة ترويسة، واستخدم <div>
مع *ngFor
لعرض كل عنصر من عناصر السلة مع اسمه وسعره، وستكون شيفرة قالب المكون CartComponent
كما يلي:
- الملف src/app/cart/cart.component.html:
<h3>Cart</h3> <div class="cart-item" *ngFor="let item of items"> <span>{{ item.name }}</span> <span>{{ item.price | currency }}</span> </div>
تحقّق من عمل السلة كما يجب:
- انقر على My Store.
- انقر على اسم المنتج لعرض تفاصيله.
- انقر زر الشراء لإضافة المنتج إلى السلة.
- انقر فوق زر الدفع لرؤية السلة.
جلب أسعار الشحن
تُعيد الخوادم البيانات على هيئة مجرى stream غالبًا والتي تُعَدّ مفيدةً لتسهيلها من عملية نقل البيانات المعادة وإجراء تعديلات على الطريقة التي تُطلَب فيها تلك البيانات، كما تعد الوحدة HttpClient
في Angular طريقة أساسية لجلب البيانات من واجهات برمجة تطبيقات خارجية وتوفيرها للتطبيق الخاص بك على أساس مجرى، حيث يُوضِّح هذا القسم لك كيفية استخدام الوحدة HttpClient
لاسترجاع أسعار الشحن من ملف خارجي.
يأتي التطبيق الذي ولَّده StackBlitz مع بيانات الشحن بشكل مسبق ضمن ملف assets/shipping.json
، كما يمكنك استخدام هذه البيانات لإضافة أسعار الشحن للعناصر الموجودة في السلة.
- الملف src/assets/shipping.json:
[ { "type": "Overnight", "price": 25.99 }, { "type": "2-Day", "price": 9.99 }, { "type": "Postal", "price": 2.99 } ]
تهيئة AppModule لاستخدام HttpClient
يجب عليك ضبط التطبيق الخاص بك لاستخدام الوحدة HttpClientModule
من أجل استخدام خدمة HttpClient
من Angular، حيث يُسجِّل HttpClientModule
المزوِّدين الذين يحتاجهم التطبيق الخاص بك لكي يستخدم خدمة HttpClient
في جميع ملفات التطبيق.
لنبدأ، أولًا استورد الوحدة HttpClientModule
في ملف app.module.ts
عن طريق حزمة @angular/common/http
في الجزء العلوي من الملف مع باقي الاستيرادات، ونظرًا لوجود عدد من الاستيرادات الأخرى، فإن هذه الشيفرة تحذفها للإيجاز، ولذلك تأكد من وضع الاستيرادات الموجودة في مكانها الصحيح.
- الملف src/app/app.module.ts:
import { HttpClientModule } from '@angular/common/http';
ثانيًا، لتسجيل مزوِّد HttpClient
ليكون متاحًا في جميع ملفات التطبيق، أضف HttpClientModule
إلى ملف AppModule
ضمن مصفوفة الاستيرادات imports
في @NgModule
.
- الملف src/app/app.module.ts:
@NgModule({ imports: [ BrowserModule, HttpClientModule, ReactiveFormsModule, RouterModule.forRoot([ { path: '', component: ProductListComponent }, { path: 'products/:productId', component: ProductDetailsComponent }, { path: 'cart', component: CartComponent }, ]) ], declarations: [ AppComponent, TopBarComponent, ProductListComponent, ProductAlertsComponent, ProductDetailsComponent, CartComponent, ], bootstrap: [ AppComponent ] }) export class AppModule { }
تهيئة الخدمة CartService لاستخدام HttpClient
تتمثَّل الخطوة التالية في حقن خدمة HttpClient
ضمن خدمتك حتى يتمكن تطبيقك من جلب البيانات والتفاعل مع الموارد وواجهات برمجة التطبيقات الخارجية.
استورد خدمة HttpClient
من حزمة @angular/common/http
ضمن ملف cart.service.ts
.
- الملف src/app/cart.service.ts:
import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Product } from './products';
احقن HttpClient
في الباني constructor()
الخاص بالخدمة CartService
.
- الملف src/app/cart.service.ts:
export class CartService { items: Product[] = []; constructor( private http: HttpClient ) {} /* . . . */ }
تهيئة الخدمة CartService لجلب أسعار الشحن
يمكنك استخدام تابع get()
من HttpClient
للحصول على بيانات الشحن من ملف shipping.json
.
عرِّف تابعًا جديدًا getShippingPrices()
يستخدِم تابع get()
من HttpClient
ضمن ملف cart.service.ts
أسفل تابع clearCart()
.
- الملف src/app/cart.service.ts:
export class CartService { /* . . . */ getShippingPrices() { return this.http.get<{type: string, price: number}[]>('/assets/shipping.json'); } }
انتهينا من عملية الضبط والتهيئة لجلب أسعار الشحن.
إنشاء مكون الشحن
الآن بعدما هيّئت تطبيقك لاسترجاع بيانات الشحن، يمكنك إنشاء مكان لعرض تلك البيانات.
بدايةً، ولِّد مكوِّنًا باسم shipping
يمثل عملية الشحن بتنفيذ الأمر التالي في الطرفية:
ng generate component shipping
سيولد هذا الأمر الملف shipping.component.ts الخاص بالمكون وقالبه وملفات تنسيقاته.
- الملف src/app/shipping/shipping.component.ts:
import { Component } from '@angular/core'; @Component({ selector: 'app-shipping', templateUrl: './shipping.component.html', styleUrls: ['./shipping.component.css'] }) export class ShippingComponent { constructor() { } }
أضف مسار للشحن في ملف app.module.ts
، واضبط الحقل pah
إلى القيمة shipping
والحقل component
إلى المكون ShippingComponent
.
- الملف src/app/app.module.ts:
@NgModule({ imports: [ BrowserModule, HttpClientModule, ReactiveFormsModule, RouterModule.forRoot([ { path: '', component: ProductListComponent }, { path: 'products/:productId', component: ProductDetailsComponent }, { path: 'cart', component: CartComponent }, { path: 'shipping', component: ShippingComponent }, ]) ], declarations: [ AppComponent, TopBarComponent, ProductListComponent, ProductAlertsComponent, ProductDetailsComponent, CartComponent, ShippingComponent ], bootstrap: [ AppComponent ] }) export class AppModule { }
لا يوجد رابط لمكون الشحن الجديد حتى الآن، ولكن يمكنك رؤية قالبه في جزء المعاينة عن طريق إدخال عنوان URL الذي يحدده مساره، حيث يحتوي عنوان URL على النمط الآتي:
https://angular-ynqttp--4200.local.webcontainer.io/shipping
حيث أنَّ جزء angular-ynqttp--4200.local.webcontainer.io
قد يكون مختلفًا في مشروع StackBlitz الخاص بك.
تهيئة المكون ShippingComponent لاستخدام الخدمة CartService
ينضبط المكون ShippingComponent
لجلب بيانات الشحن عبر استخدام طلب HTTP من ملف shipping.json
.
أولًا، استورد CartService
في ملف shipping.component.ts
.
- الملف src/app/shipping/shipping.component.ts:
import { Component } from '@angular/core'; import { CartService } from '../cart.service';
ثانيًا، احقن خدمة السلة في الباني constructor()
الخاص بالمكون ShippingComponent
.
- الملف src/app/shipping/shipping.component.ts:
constructor(private cartService: CartService) { }
ثالثًا، عرِّف الخاصية shippingCosts
التي تُضبط باستخدام التابع getShippingPrices()
من الخدمة CartService
.
- الملف src/app/shipping/shipping.component.ts:
export class ShippingComponent { shippingCosts = this.cartService.getShippingPrices(); }
رابعًا، حدِّث قالب المكون ShippingComponent
لكي يعرض أنواع وأسعار الشحن باستخدام أنبوب async
.
- الملف src/app/shipping/shipping.component.html:
<h3>Shipping Prices</h3> <div class="shipping-item" *ngFor="let shipping of shippingCosts | async"> <span>{{ shipping.type }}</span> <span>{{ shipping.price | currency }}</span> </div>
يُعيد أنبوب async
أحدث قيمة من مجرى البيانات ويتابع تحميل مكوِّن معيَّن، حيث يتوقف أنبوب async
تلقائيًا عندما تدمر Angular هذا المكوِّن.
خامسًا، أضف رابطًا من قسم العرض الخاص بالمكون CartComponent
إلى قسم العرض الخاص بالمكون ShippingComponent
.
- الملف src/app/cart/cart.component.html:
<h3>Cart</h3> <p> <a routerLink="/shipping">Shipping Prices</a> </p> <div class="cart-item" *ngFor="let item of items"> <span>{{ item.name }}</span> <span>{{ item.price | currency }}</span> </div>
سادسًا، انقر على زر الدفع Checkout لرؤية السلة المحدَّثة، وتذكَّر أنَّ أي تعديلات على التطبيق ستؤدي إلى تحديث المعاينة، وبالتالي إفراغ السلة.
انقر على الرابط للانتقال إلى أسعار الشحن.
أصبح تطبيقنا الآن يعرض قائمة بالمنتجات وفيه سلة تسوق مع توفير إمكانية عرض الأسعار، وسنعمل في الخطوة التالية على إضافة ميزة الدفع عن طريق تعبئة استمارة تجمع المعلومات المتعلقة بالمستخدم والتي تعد جزءًا من عملية التسوق من المتجر.
تعريف نموذج استمارة الدفع
توضِّح لك هذه الخطوة كيفية إعداد نموذج استمارة الدفع في صنف المكون حيث يحدّد هذا النموذج حالة الاستمارة.
افتح الملف cart.component.ts
واستورد خدمة FormBuilder
من حزمة @angular/forms
، حيث توفِّر هذه الخدمة توابعًا ملائمةً لتوليد عناصر التحكم.
- الملف src/app/cart/cart.component.ts:
import { Component } from '@angular/core'; import { FormBuilder } from '@angular/forms'; import { CartService } from '../cart.service';
احقن خدمة FormBuilder
في الباني constructor()
الخاص بالمكون CartComponent
، حيث أنَّ هذه الخدمة هي جزء من وحدة ReactiveFormsModule
التي استوردتها للتو.
- الملف src/app/cart/cart.component.ts:
export class CartComponent { constructor( private cartService: CartService, private formBuilder: FormBuilder, ) {} }
استخدم تابع group()
من FormBuilder
من أجل الحصول على اسم المستخدِم وعنوانه وذلك من أجل ضبط خاصية checkoutForm
إلى نموذج استمارة يحوي حقلَي name
وaddress
.
- الملف src/app/cart/cart.component.ts:
export class CartComponent { items = this.cartService.getItems(); checkoutForm = this.formBuilder.group({ name: '', address: '' }); constructor( private cartService: CartService, private formBuilder: FormBuilder, ) {} }
عرِّف التابع onSubmit()
المسؤول عن معالجة الاستمارة، حيث يسمح هذا التابع للمستخدمين بإرسال أسمائهم وعناوينهم، كما أنَّ هذا التابع يستخدِم تابع clearCart()
الخاص بخدمة CartService
لإعادة ضبط الاستمارة وتفريغ السلة، ويكون صنف المكوِّن الخاص بالسلة كاملًا كما يلي:
- الملف src/app/cart/cart.component.ts:
import { Component } from '@angular/core'; import { FormBuilder } from '@angular/forms'; import { CartService } from '../cart.service'; @Component({ selector: 'app-cart', templateUrl: './cart.component.html', styleUrls: ['./cart.component.css'] }) export class CartComponent { items = this.cartService.getItems(); checkoutForm = this.formBuilder.group({ name: '', address: '' }); constructor( private cartService: CartService, private formBuilder: FormBuilder, ) {} onSubmit(): void { // Process checkout data here this.items = this.cartService.clearCart(); console.warn('Your order has been submitted', this.checkoutForm.value); this.checkoutForm.reset(); } }
إنشاء استمارة الدفع
اتبع الخطوات التالية لإضافة استمارة الدفع في أسفل قسم العرض الخاص بسلة التسوق.
-
أولًا، أضف وسم
<form>
وزر الشراء Purchase في نهاية ملفcart.component.html.
-
ثانيًا، استخدِم تربيط الخاصيات لإضافة الخاصية
formGroup
إلى وسم<form>
وربطcheckoutForm
بها. - الملف src/app/cart/cart.component.html:
<form [formGroup]="checkoutForm"> <button class="button" type="submit">Purchase</button> </form>
-
ثالثًا، استخدم التربيط عن طريق الحدث
ngSubmit
ضمن وسمform
للاستماع إلى عملية إرسال النموذج واستدعاء تابعonSubmit()
مع قيمةcheckoutForm
. -
الملف src/app/cart/cart.component.html (تفاصيل قالب مكون السلة):
<form [formGroup]="checkoutForm" (ngSubmit)="onSubmit()"> </form>
رابعًا، أضف حقول <input>
لكل من الاسم name
والعنوان address
، وأضف لكل منها سمة formControlName
التي تربط عناصر تحكم name
وaddress
الموجودة في استمارة checkoutForm
بحقول <input>
الخاصة بهم، ويكون المكوِّن كاملًا كما يلي:
- الملف src/app/cart/cart.component.html:
<h3>Cart</h3> <p> <a routerLink="/shipping">Shipping Prices</a> </p> <div class="cart-item" *ngFor="let item of items"> <span>{{ item.name }} </span> <span>{{ item.price | currency }}</span> </div> <form [formGroup]="checkoutForm" (ngSubmit)="onSubmit()"> <div> <label for="name"> Name </label> <input id="name" type="text" formControlName="name"> </div> <div> <label for="address"> Address </label> <input id="address" type="text" formControlName="address"> </div> <button class="button" type="submit">Purchase</button> </form>
يستطيع المستخدِمين بعد وضع عناصر قليلة في السلة معاينة تلك العناصر ومن ثم إدخال أسمائهم وعناوينهم وتأكيد عملية الشراء.
افتح الطرفية لتأكيد عملية الإرسال، حيث ستجد كائنًا يحتوي على الاسم والعنوان اللذَين أرسلتهما.
الخطوة التالية
ضبطت في هذا المثال التطبيق الخاص بك حتى تتمكن من عرض تفاصيل كل منتج في عنوان متميز، ولديك الآن تطبيق متجر يحتوي على قائمة بالمنتجات وسلة تسوق ونموذج دفع، وبإمكانك إلقاء نظرة على أسعار الشحن أيضًا.
أكمل إلى قسم النشر لتنتقل إلى التطوير المحلي أو تنشر التطبيق الخاص بك إلى Firebase أو الخادم الخاص بك وذلك لمتابعة استكشاف Angular.
ترجمة -وبتصرف- للمقال Adding navigation والمقال Managing data والمقال Using forms for user input من موقع angular.io الرسمي.
أفضل التعليقات
لا توجد أية تعليقات بعد
انضم إلى النقاش
يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.