اذهب إلى المحتوى

إنشاء تطبيق قائمة مهام وتنسيقه باستخدام Angular


Ola Abbas

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

  • المتطلبات الأساسية: يوصَى على الأقل بأن تكون على دراية بأساسيات لغات HTML وCSS وجافاسكربت JavaScript، ومعرفة باستخدام سطر الأوامر أو الطرفية.
  • الهدف: إنشاء بنية تطبيقك الأساسية، وعرض قائمة بعناصر المهام، وفهم مفاهيم Angular الأساسية مثل بنية المكونات ومشاركة البيانات بين المكونات وإنشاء حلقات المحتوى ومعرفة كيفية تنسيق تطبيق Angular.

بنية تطبيق قائمة المهام

يحتوي تطبيق Angular على الملف index.html مثل أيّ تطبيق أساسي لا يستخدِم إطار عمل، ويستخدِم عنصرًا خاصًا هو <app-root> ضمن الوسم <body>. في الملف index.html لإدراج مكوِّنك الرئيسي الذي يتضمن بدوره المكونات الأخرى التي تنشئها، كما لا تحتاج إلى تعديل الملف index.html بصورة عامة، وإنما يجب أن تركّز اهتمامك على مناطق متخصصة من تطبيقك هي المكونات Components.

تنظيم تطبيقك ضمن المكونات

تُعَدّ المكونات لبنة البناء المركزية لتطبيقات Angular، إذ يحتوي تطبيق قائمة المهام على مكونين هما مكوِّن يمثّل أساس تطبيقك ومكوِّن للتعامل مع عناصر المهام.

يتكون كل مكوِّن من صنف TypeScript وشيفرة HTML وCSS، إذ تُترجَم أو تُحوَّل شيفرة Typescript إلى شيفرة جافاسكربت، مما يعني أنّ تطبيقك يتحوّل في النهاية إلى شيفرة جافاسكربت عادية مع القدرة على استخدام ميزات لغة Typescript الموسَّعة وصيغتها المبسَّطة.

تعديل واجهة المستخدم ديناميكيا باستخدام الموجهين ‎ngIf* و‎*ngFor

سنغطي في هذا المقال أيضًا موجّهَين Directives مهمين في Angular لتعديل بنية نموذج DOM ديناميكيًا، إذ يشبه الموجّه الأمر الذي يمكنك استخدامه في لغة HTML لإحداث تغيير في تطبيقك.

الموجّه الأول هو المكرِّر ‎*ngFor الذي يمكنه إنشاء عناصر DOM ديناميكيًا بناءً على عناصر في مصفوفة؛ أما الموجّه الثاني فهو ‎*ngIf الذي يمكنك استخدامه لإضافة عناصر أو إزالتها من نموذج DOM بناءً على شرط معيّن، فإذا أراد المستخدِمون مثلًا تعديل عنصر في قائمة المهام، فيمكنك تزويدهم بالوسائل اللازمة لتعديل هذا العنصر؛ وإذا لم يرغبوا في تعديل عنصر، فيمكنك إزالة واجهة التعديل.

مشاركة البيانات بين المكونات

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

يمكن تحقيق مشاركة البيانات بين مكونات Angular باستخدام عناصر تصميم خاصة هي ‎@Input()‎ و ‎@Output()‎ التي يمكنك استخدامها لتحديد أنّ بعض الخاصيات تسمح للبيانات بالدخول إلى مكون أو الخروج منه، كما يجب رفع حدث في أحد المكونات لاستخدام عنصر التصميم ‎@Output()‎ حتى يعرف المكوِّن الآخر أنّ هناك بيانات متاحة.

تعريف عنصر

أنشئ ملفًا جديدًا بالاسم item.ts بالمحتويات التالية في المجلد app:

export interface Item {
  description: string;
  done: boolean;
}

لن تستخدِم هذا الملف حتى وقت لاحق، ولكن هذا هو الوقت المناسب لمعرفة ما هو العنصر item. تنشئ واجهة العنصر Item نموذج كائن عنصر بحيث يفهم تطبيقك ما هو العنصر، في حين يُعَدّ العنصر في تطبيق قائمة المهام كائنًا له وصف ويمكن إكماله.

إضافة شيفرة إلى القالب AppComponent

يمكنك الآن -بعد أن عرفت ما هو العنصر item- وضع بعض العناصر في تطبيقك عبر إضافتها إلى ملف TypeScript وهو app.component.ts واستبدال محتوياته بما يلي:

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})

export class AppComponent {
  title = 'todo';

  filter: 'all' | 'active' | 'done' = 'all';

  allItems = [
    { description: 'eat', done: true },
    { description: 'sleep', done: false },
    { description: 'play', done: false },
    { description: 'laugh', done: false },
  ];

  get items() {
    if (this.filter === 'all') {
      return this.allItems;
    }
    return this.allItems.filter((item) => this.filter === 'done' ? item.done : !item.done);
  }

}

السطر الأول هو تعليمة استيراد بلغة جافاسكربت تستورد إطار عمل Angular، إذ يحدد عنصر التصميم ‎@Component()‎ بيانات AppComponent الوصفية، وتكون خاصيات البيانات الوصفية الافتراضية كما يلي:

  • selector: يخبرك باسم محدّد CSS الذي تستخدِمه في قالب لإنشاء نسخة من هذا المكوِّن وهو هنا 'app-root'، وقد أضافت واجهة Angular CLI الوسم <app-root></app-root> في الملف index.html ضمن الوسم body عند إنشاء تطبيقك، كما يمكنك استخدام جميع محددات المكونات بالطريقة نفسها من خلال إضافتها إلى قوالب HTML الخاصة بالمكونات الأخرى.
  • templateUrl: يحدّد ملف HTML لربطه بهذا المكوِّن، وهو هنا '‎./app.component.html'.
  • styleUrls: يوفّر موقع واسم ملف التنسيق الذي ينطبق تحديدًا على هذا المكوِّن، وهو هنا '‎./app.component.css'.

تكون خاصية الترشيح filter من النوع union، وبالتالي يمكن أن يكون للخاصية filter القيمة all أو active أو done، فإذا ارتكبت خطأً مطبعيًا أثناء كتابة القيمة التي تسندها إلى الخاصية filter مع النوع union، فستتيح لغة TypeScript معرفة ذلك لتتمكن من اكتشاف الخطأ مبكرًا، كما يوضح لك هذا المقال كيفية إضافة الترشيح في خطوة لاحقة، ولكن يمكنك استخدام خاصية الترشيح لإظهار القائمة الافتراضية لجميع العناصر.

تحتوي المصفوفة allItems على عناصر المهام وما إذا كانت مكتملةً done أم لا، وتكون قيمة الخاصية done للعنصر الأولeat هي true.

يعمل التابع الجالب get items()‎ على استرداد العناصر من المصفوفة allItems إذا كانت الخاصية filter مساويةً للقيمة all، وإلّا فسيعيد الجالب get items()‎ العناصر المكتملة done أو العناصر المعلَّقة اعتمادًا على كيفية ترشيح المستخدِم للعرض، إذ ينشئ الجالب Getter مصفوفةً بالاسم items التي سنستخدِمها لاحقًا.

إضافة شيفرة HTML إلى القالب AppComponent

استبدل محتويات الملف app.component.html بتوصيف HTML التالي للاطلاع على قائمة العناصر في المتصفح:

<div class="main">
  <h1>My To Do List</h1>
  <h2>What would you like to do today?</h2>

  <ul>
    <li *ngFor="let item of items">{{item.description}}</li>
  </ul>
</div>

يحتوي العنصر <li> على الموجّه ‎*ngFor، وهو موجّه Angular مضمَّن يُكرَّر على العناصر في المصفوفة items، إذ ينشئ الموجّه ‎*ngFor عنصر <li> جديد لكل عنصر، كما توجّه الأقواس المزدوجة المعقوصة التي تحتوي على item.description إطار عمل Angular لملء كل عنصر <li> بنص يصِف كل عنصر.

سترى قائمة العناصر في المتصفح كما يلي:

My To Do List
What would you like to do today?

* eat
* sleep
* play
* laugh

إضافة عناصر إلى القائمة

تحتاج قائمة المهام لطريقة ما لإضافة عناصر، لذا أضِف التابع التالي إلى الصنف في الملف app.component.ts:

addItem(description: string) {
  this.allItems.unshift({
    description,
    done: false
  });
}

يأخذ التابع addItem()‎ عنصرًا يوفّره المستخدِم ويضيفه إلى المصفوفة عندما ينقر المستخدِم على زر "الإضافة Add"، ويستخدِم هذا التابع تابع المصفوفة unshift()‎ لإضافة عنصر جديد إلى بداية المصفوفة وأعلى القائمة، أو يمكنك بدلًا من ذلك استخدام التابع push()‎ الذي سيضيف العنصر الجديد إلى نهاية المصفوفة وأسفل القائمة، كما يمكنك استخدام التابع addItem()‎ من خلال تعديل قسم HTML في القالب AppComponent.

استبدل العنصر <h2> بما يلي في الملف app.component.html:

<label for="addItemInput">What would you like to do today?</label>

<input
  #newItem
  placeholder="add an item"
  (keyup.enter)="addItem(newItem.value); newItem.value = ''"
  class="lg-text-input"
  id="addItemInput"
/>

<button class="btn-primary" (click)="addItem(newItem.value)">Add</button>

إذا كتب المستخدِم عنصرًا جديدًا في عنصر الإدخال <input> وضغط على مفتاح Enter، فسيضيف التابع addItem()‎ هذه القيمة إلى المصفوفة items، كما يؤدي الضغط على مفتاح Enter إلى إعادة ضبط قيمة حقل الإدخال <input> إلى سلسلة نصية فارغة، أو يمكن للمستخدِم النقر على زر "الإضافة Add" الذي يستدعي التابع addItem()‎ نفسه.

تنسيق تطبيق Angular

أصبحت بنية التطبيق الأساسية جاهزةً، إذًا لنطّلع على كيفية تعامل إطار عمل Angular مع تنسيق التطبيقات.

إضافة التنسيق إلى تطبيق Angular

تنشئ واجهة Angular CLI نوعين من ملفات التنسيق هما:

  • تنسيق المكونات: توفِّر واجهة Angular CLI لكل مكوِّن ملفه الخاص بالتنسيق الذي يُطبَّق على هذا المكوِّن فقط.
  • styles.css: يوجد هذا الملف في المجلد src، ويُطبَّق التنسيق الموجود في هذا الملف على التطبيق بأكمله ما لم تحدّد تنسيقًا على مستوى المكوِّن.

يمكن أن يختلف الامتداد الموجود في ملفات CSS اعتمادًا على ما إذا أردت معالج CSS المُسبَق، كما يدعم Angular لغات CSS و SCSS وSass و Less و Stylus.

الصق ما يلي في الملف src/styles.css:

body {
  font-family: Helvetica, Arial, sans-serif;
}

.btn-wrapper {
  /* flexbox */
  display: flex;
  flex-wrap: nowrap;
  justify-content: space-between;
}

.btn {
  color: #000;
  background-color: #fff;
  border: 2px solid #cecece;
  padding: 0.35rem 1rem 0.25rem 1rem;
  font-size: 1rem;
}

.btn:hover {
  background-color: #ecf2fd;
}

.btn:active {
  background-color: #d1e0fe;
}

.btn:focus {
  outline: none;
  border: black solid 2px;
}

.btn-primary {
  color: #fff;
  background-color: #000;
  width: 100%;
  padding: 0.75rem;
  font-size: 1.3rem;
  border: black solid 2px;
  margin: 1rem 0;
}

.btn-primary:hover {
  background-color: #444242;
}

.btn-primary:focus {
  color: #000;
  outline: none;
  border: #000 solid 2px;
  background-color: #d7ecff;
}

.btn-primary:active {
  background-color: #212020;
}

يُطبَّق قسم CSS في الملف src/styles.css على التطبيق بأكمله، ولكن لا يؤثر هذا التنسيق على كل شيء في الصفحة، فالخطوة التالية هي إضافة التنسيق الذي يُطبَّق على الملف AppComponent على وجه التحديد.

أضِف التنسيق التالي في الملف app.component.css:

.main {
  max-width: 500px;
  width: 85%;
  margin: 2rem auto;
  padding: 1rem;
  text-align: center;
  box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), 0 2.5rem 5rem 0 rgba(0, 0, 0, 0.1);
}

@media screen and (min-width: 600px) {
  .main {
    width: 70%;
  }
}

label {
  font-size: 1.5rem;
  font-weight: bold;
  display: block;
  padding-bottom: 1rem;
}

.lg-text-input {
  width: 100%;
  padding: 1rem;
  border: 2px solid #000;
  display: block;
  box-sizing: border-box;
  font-size: 1rem;
}

.btn-wrapper {
  margin-bottom: 2rem;
}

.btn-menu {
  flex-basis: 32%;
}

.active {
  color: green;
}

ul {
  padding-inline-start: 0;
}

ul li {
  list-style: none;
}

الخطوة الأخيرة هي زيارة المتصفح مرةً أخرى وإلقاء نظرة على كيفية تحديث تنسيق التطبيق

الخلاصة

يجب الآن أن يكون لديك قائمة المهام الأساسية معروضةً في متصفحك مع تنسيق جيد لتطبيق Angular، وسننشئ في المقال التالي مكونًا مناسبًا لعناصر المهام بحيث يمكنك تحديد عناصر المهام وتعديلها وحذفها.

ترجمة -وبتصرُّف- للمقالين Beginning our Angular todo list app وStyling our Angular app.

اقرأ أيضًا


تفاعل الأعضاء

أفضل التعليقات

لا توجد أية تعليقات بعد



انضم إلى النقاش

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

زائر
أضف تعليق

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   جرى استعادة المحتوى السابق..   امسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • أضف...