پروژه Drag & Drop: نمایش لیست پروژه‌ها

Drag & Drop Project: Showing List of Projects

16 مرداد 1399
پروژه ی Drag & Drop: نمایش لیست پروژه ها

در قسمت قبل متدی برای اعتبارسنجی فرم خود ایجاد کردیم اما نهایت کاری که با داده ها می کنیم دریافت log کردن آن ها در کنسول مرورگر است:

  @autobind
  private submitHandler(event: Event) {
    event.preventDefault();
    const userInput = this.gatherUserInput();
    if (Array.isArray(userInput)) {
      const [title, desc, people] = userInput;
      console.log(title, desc, people);
      this.clearInputs();
    }
  }

در حالی که هدف نهایی پروژه این است که لیستی از پروژه ها را در مرورگر نمایش بدهیم (درون template ای که در فایل index.html تعریف کرده بودیم). در ابتدا و برای شروع کار باید کلاس دیگر به نام project list را تعریف کنیم که template ما را گرفته و لیستی از پروژه ها را در آن render می کند:

// ProjectList Class
class ProjectList {
  templateElement: HTMLTemplateElement;
  hostElement: HTMLDivElement;
  element: HTMLElement;

  constructor() {

  }
}

ما به سه فیلد/تگ template و hostElement و element نیاز داریم بنابراین تایپ آن ها را تعریف کرده ایم و حالا باید آن ها را در constructor دریافت کنیم. شما می توانید این فیلدها یا تگ ها را در فایل index.html پیدا کنید:

    <template id="project-list">
      <section class="projects">
        <header>
          <h2></h2>
        </header>
        <ul></ul>
      </section>
    </template>

در قدم اول باید template را بگیریم بنابراین دقیقا شبیه به کدهای جلسه قبل عمل می کنیم:

    constructor() {
        this.templateElement = document.getElementById(
            'project-list'
        )! as HTMLTemplateElement;
        this.hostElement = document.getElementById('app')! as HTMLDivElement;
    }

در مرحله بعد باید از محتوای درون تگ template یک کپی بگیریم بنابراین از دستور importNode استفاده می کنیم:

    constructor() {
        this.templateElement = document.getElementById(
            'project-list'
        )! as HTMLTemplateElement;
        this.hostElement = document.getElementById('app')! as HTMLDivElement;

        const importedNode = document.importNode(
            this.templateElement.content,
            true
        );
        this.element = importedNode.firstElementChild as HTMLElement;
    }

تا این قسمت که دقیقا مانند جلسات قبلی عمل کرده ایم و اولین فرزند درون تگ template را (که یک تگ section است) درون element ذخیره کرده ایم اما اینجا دیگر نمی توانیم مانند جلسه قبل id را به صورت دستی بنویسیم. چرا؟ به دلیل اینکه دیگر فقط یک id نداریم بلکه لیستی از پروژه ها را داریم که هر کدام id جداگانه ای دارد. در واقع در برنامه نهایی ما دو لیست جداگانه خواهیم داشت که یکی برای پروژه های فعال و دیگری برای پروژه های غیرفعال خواهد بود. به همین دلیل باید اطلاعاتی را به constructor پاس بدهیم:

    constructor(private type: 'active' | 'finished') {
        this.templateElement = document.getElementById(
            'project-list'
        )! as HTMLTemplateElement;
// بقیه کدها //

در اینجا پارامتری ورودی به نام type را ایجاد کرده ام که تایپ آن از نوع union type ها می باشد، یا active (فعال و در حال انجام) است یا finished (تمام شده) و غیر از این دو مقدار دیگری را قبول نمی کند. همانطور که توضیح دادم پروژه های ما حتما در یکی از این دو حالت خواهند بود و حالت دیگری برایشان تعریف نشده است. همچنین من از روش خلاصه تایپ اسکریپت برای ایجاد property ها استفاده کرده ام. آیا هنوز یادتان است؟ شما می توانید با اضافه کردن یک accessor مانند private یا public قبل از پارامترهای ورودی constructor، یک خصوصیت (property) به همان نام در آن کلاس تعریف کنید بدون اینکه نیاز باشد کدی برایش بنویسید. این یک روش خلاصه بود که در فصل های گذشته آن را توضیح داده بودیم.

حالا برای تعیین id می توان گفت:

    constructor(private type: 'active' | 'finished') {
        this.templateElement = document.getElementById(
            'project-list'
        )! as HTMLTemplateElement;
        this.hostElement = document.getElementById('app')! as HTMLDivElement;

        const importedNode = document.importNode(
            this.templateElement.content,
            true
        );
        this.element = importedNode.firstElementChild as HTMLElement;
        this.element.id = `${this.type}-projects`;
    }

من می خواهم هر لیست یک id خاص داشته باشد که تایپ آن در همان id مشخص شده باشد (یعنی یا active-projects یا finished-projects).  تا اینجای کار به تمام عناصر اصلی دسترسی پیدا کرده و id آن section را نیز تعیین کرده ایم بنابراین حالا وقت render کردن آن ها در مرورگر است. برای این کار متدی به نام attach را در این کلاس تعریف می کنم:

// ProjectList Class
class ProjectList {
  templateElement: HTMLTemplateElement;
  hostElement: HTMLDivElement;
  element: HTMLElement;

  constructor(private type: 'active' | 'finished') {
    this.templateElement = document.getElementById(
      'project-list'
    )! as HTMLTemplateElement;
    this.hostElement = document.getElementById('app')! as HTMLDivElement;

    const importedNode = document.importNode(
      this.templateElement.content,
      true
    );
    this.element = importedNode.firstElementChild as HTMLElement;
    this.element.id = `${this.type}-projects`;
    this.attach();
  }

  private attach() {
    this.hostElement.insertAdjacentElement('beforeend', this.element);
  }
}

حالا دوباره از متد insertAdjacentElement استفاده می کنم تا div با id برابر App (همان hostElement) را قبل از تگ پایانی section قرار دهم ('beforeend' یعنی قبل از تگ پایانی). همچنین attach را داخل constructor نیز صدا زده ام. زمانی که این کدها را برای فرم خود می نوشتیم، کافی بود که یک event-listener تعریف کنیم تا داده ها را از کاربر بگیرد اما حالا با خروجی آن کار می کنیم و در قسمت HTML تگ های h2 را داریم که عنوان را نشان می دهند و باید اضافه کاری هایی انجام بدهیم. برای این کار یک متد جدید ایجاد می کنم:

  private renderContent() {
    const listId = `${this.type}-projects-list`;
    this.element.querySelector('ul')!.id = listId;
    this.element.querySelector('h2')!.textContent =
      this.type.toUpperCase() + ' PROJECTS';
    
  }

  private attach() {
    this.hostElement.insertAdjacentElement('beforeend', this.element);
  }

همانطور که می بینید در کد بالا ابتدا id را برای ul تعریف کرده و ثبت می کنیم. سپس محتوای تگ h2 یا عنوان آن لیست از پروژه ها را نیز بر اساس type دریافتی تعریف خواهیم کرد (مثلا FINISHED PROJECTS). در نهایت آن را نیز درون constructor صدا بزنیم:

// بقیه کدها //
    this.attach();
    this.renderContent();
  }

فعلا آیتمی برای نمایش در لیست ها نداریم اما کلیت برنامه را می توانیم مشاهده کنیم. برای این کار به انتهای فایل app.ts رفته و یک نمونه از این کلاس را بسازید:

const prjInput = new ProjectInput();
const activePrjList = new ProjectList('active');
const finishedPrjList = new ProjectList('finished');

با ذخیره فایل و مراجعه به مرورگر باید دو مجموعه لیست را مشاهده کنید:

نمایش دو لیست متفاوت در مرورگر
نمایش دو لیست متفاوت در مرورگر

در جلسه بعد باید کاری کنیم که با کلیک روی Add Project در کدهایمان یک پروژه بسازیم (ساختار داده های یک پروژه را بسازیم) و سپس این کدها را به قسمت ACTIVE PROJECTS ارسال کنیم (تمام پروژه هایی که تازه ساخته می شوند قطعا فعال هستند).

تمام فصل‌های سری ترتیبی که روکسو برای مطالعه‌ی دروس سری آموزش جامع تایپ اسکریپت توصیه می‌کند:
نویسنده شوید
دیدگاه‌های شما

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.

مقالات مرتبط
ما را دنبال کنید
اینستاگرام روکسو تلگرام روکسو ایمیل و خبرنامه روکسو