در جلسه قبل ارث بری را پیاده سازی کرده و تمام برنامه را در حالت شیء گرایانه بازنویسی کردیم. در این جلسه می خواهیم به لیست پروژه ها نگاهی بیندازیم و اطلاعات بیشتری را در آن نشان بدهیم. در حال حاضر فقط عنوان نمایش داده می شود، بدون توضیحات و تعداد افراد. در حال حاضر برای نمایش لیست پروژه ها کلاس جداگانه ای داریم (ProjectList) و کلاس دیگری به نام ProjectInput داریم که مسئول نمایش فرم ما است اما این کار را برای تک تک آیتم های پروژه انجام نمی دهیم بلکه آن ها را درون renderProjects (در کلاس ProjectList) می سازیم.
برای شروع این کار، بالاتر از projectList کلاسی به نام ProjectItem تعریف می کنیم:
class ProjectItem extends Component { }
این کلاس مسئول نمایش یک آیتم از آیتم های پروژه ها است و از آنجایی که مسئول نمایش چیزی است باید کلاس component را extend کند. در مرحله بعد باید تایپ های این کلاس را مشخص کنیم:
class ProjectItem extends Component<HTMLUListElement, HTMLLIElement> { }
اگر به کلاس component نگاه کنید، می بینید که اولین تایپ پاس داده شده در آنجا hostElement است یعنی محلی که آیتم ها باید در آن به نمایش در بیایند. قطعا آیتم های ما درون یک <ul> به نمایش در می آیند بنابراین تایپ آن را HTMLUListElement انتخاب کرده ام. دومین تایپی که پاس داده می شود نیز element است که خود آیتم نمایش داده شده می باشد. تک تک آیتم های ما از نوع <li> هستند بر همین اساس آن را روی HTMLLIElement گذاشته ام.
در مرحله بعد باید super را درون constructor این کلاس صدا بزنیم و برای اولین پارامتر، id عنصری را می خواهیم که آیتم ها درون آن نمایش داده می شوند. مشکل اینجاست که id ثابت نیست چرا که دو لیست مختلف داریم و آیتم می تواند درون هر کدام نمایش داده شود بنابراین می توانیم آن را از constructor گرفته و به super پاس بدهیم:
class ProjectItem extends Component<HTMLUListElement, HTMLLIElement> { constructor(hostId: string, id: string) { super('single-project', hostId, false, id); } }
برای super ابتدا آیدی مربوط به Template را می خواهیم، سپس hostId را پاس می دهیم. همچنین من می خواهم هر آیتم جدیدی به انتهای لیست اضافه شود بنابراین پارامتر سوم را False گذاشته ام که شما می توانید بر اساس سلیقه خود تغییر دهید. در نهایت از آنجایی که id هر آیتم جدید متفاوت خواهد بود باید آن را از خارج بگیریم و به super پاس بدهیم که همین کار را نیز کرده ایم.
اگر یادتان باشد ما کلاسی به نام Project تعریف کردیم که مسئول تایپ های ما و ساختار کار بود (به جای interface از آن استفاده کردیم). کار عقلانی این است که پروژه مربوط به این کلاس را به صورت یک خصوصیت در این کلاس ذخیره کنیم و برای آن از همان کلاس Project برای تعیین تایپ آن استفاده می کنم:
class ProjectItem extends Component<HTMLUListElement, HTMLLIElement> { private project: Project; constructor(hostId: string, id: string) { super('single-project', hostId, false, id); } }
حالا می توانیم id را به شکل زیر دریافت کنیم:
class ProjectItem extends Component<HTMLUListElement, HTMLLIElement> { private project: Project; constructor(hostId: string, project: Project) { super('single-project', hostId, false, project.id); this.project = project; } }
یعنی خصوصیت project در این کلاس را برابر project پاس داده شده به constructor گذاشته ایم و از آنجایی که تایپ این project پاس داده شده از نوع Project است یعنی حتما دارای id خواهد بود بنابراین می توان گفت project.id آیدی را به ما می دهد. همچنین از آنجایی که از کلاس component ارث بری داریم باید متدهای configure و renderContent را تعریف کرده و درون constructor صدا بزنیم:
// ProjectItem Class class ProjectItem extends Component<HTMLUListElement, HTMLLIElement> { private project: Project; constructor(hostId: string, project: Project) { super('single-project', hostId, false, project.id); this.project = project; this.configure(); this.renderContent(); } configure () { } renderContent() { } }
به نظر شما درون این متدها چه چیزی باید نوشت؟ فعلا برای configure چیزی نداریم بنابراین آن را به همین صورت خالی رها کنید اما برای renderContent کار زیادی داریم. در حال حاضر آیتم هایی که در لیست ما نمایش داده می شوند فقط یک عنوان خالی دارند و نه توضیحات پروژه را نمایش می دهند نه می فهمیم تعداد افراد دخیل در این پروژه ها چند نفر است. به Template ما در فایل index.html نگاه کنید:
<template id="single-project"> <li></li> </template>
یعنی فقط تگ های li را داریم، همین! من می خواهم نحوه نمایش این آیتم ها را پیچیده تر و زیباتر کنم بنابراین برای هر پروژه یک تگ h2 در نظر می گیریم. سپس تگ h3 را برای تعداد افراد در نظر می گیریم و توضیحات پروژه را نیز درون یک تگ p قرار می دهیم:
<template id="single-project"> <li> <h2></h2> <h3></h3> <p></p> </li> </template>
حالا به App.ts برگردید تا آیتم جدید را درون این قالب پیاده سازی کنیم:
// ProjectItem Class class ProjectItem extends Component<HTMLUListElement, HTMLLIElement> { private project: Project; constructor(hostId: string, project: Project) { super('single-project', hostId, false, project.id); this.project = project; this.configure(); this.renderContent(); } configure() {} renderContent() { this.element.querySelector('h2')!.textContent = this.project.title; this.element.querySelector( 'h3' )!.textContent = this.project.people.toString(); this.element.querySelector('p')!.textContent = this.project.description; } }
همانطور که مشاهده می کنید متد renderContent مسئول هدف گرفتن ساختار Template ما و سپس جایگذاری مقادیر درون آن است. حالا به کلاس ProjectList می رویم تا از این کلاس استفاده کنیم. در این کلاس به متد renderProjects بروید و به جای گردش بین تک تک آیتم ها از کلاس جدیدمان استفاده کنید:
private renderProjects() { const listEl = document.getElementById( `${this.type}-projects-list` )! as HTMLUListElement; listEl.innerHTML = ''; for (const prjItem of this.assignedProjects) { new ProjectItem(this.element.querySelector('ul')!.id, prjItem); } }
حالا کدهای ما به درستی کار می کنند.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.