برنامه لیست کتاب: حذف کتاب ها + تبدیل پروژه به ES6

برنامه لیست کتاب: حذف کتاب ها + تبدیل پروژه به ES6

حذف کتاب ها + تبدیل پروژه به ES6

امیدوارم که توانسته باشید تا این قسمت پیش بیایید. حالا که قسمت اعظم برنامه را کدنویسی کرده ایم فقط بحث حذف کتاب ها و تبدیل به کلاس های ES6 مانده است. در پروژه ای که پیش روی ما است حروف x کوچکی وجود دارد که برای حذف کتاب ها در نظر گرفته شده اند اما مشکلی وجود دارد. در زمان بارگذاری سایت و شروع برنامه هیچ کتابی وجود ندارد بنابراین هیچ دکمه ی حذفی نیز وجود ندارد و نمی توانیم در همان ابتدا این دکمه های حذف را درون یک const قرار دهیم. حتی اگر یک دکمه ی حذف وجود داشته باشد، بقیه ی دکمه هایی که بعدا توسط کاربر اضافه می شوند را چه کار کنیم؟

اگر یادتان باشد در چندین قسمت قبل و به زبان ساده مفهومی به نام event delegation را توضیح داده بودم که می توانید به آن مراجعه کنید. در اینجا هم راه حل همان event delegation است! بنابراین به انتهای فایل App.js و پس از event-listener فعلی بروید و یک event-listener دیگر ایجاد کنید:

// Event Listener for delete
document.getElementById('book-list').addEventListener('click', function (e) {

    e.preventDefault();
}

همانطور که می بینید بر اساس مفهوم event delegation به جای هدف گرفتن دکمه های حذف (حروف x) پدر آن ها را (خود لیست) هدف قرار گرفته ایم. سپس اولین کاری که کرده ایم preventDefault کردن فرم بوده است تا چیزی ثبت نشود. من نمی خواهم کدهای بیشتری را به این قسمت اضافه کنم بلکه آن را به صورت یک متد در prototype می نویسم. من بالا تر از متد clearFields می نویسم:

// Delete Book
UI.prototype.deleteBook = function(target){
  if(target.className === 'delete') {
    target.parentElement.parentElement.remove();
  }
}

سوال: پارامتر target به صورت خودکار به این متد پاس داده خواهد شد. آیا می دانید چرا؟

پاسخ: همانطور که می دانید، شیء target به صورت خودکار درون event-listener ها وجود دارد و می توانید هر جایی از آن استفاده کنید. target به هدف آن event-listener اشاره می کند؛ به طور مثال اگر روی نام کتاب کلیک کنیم، target می شود قسمت «نام کتاب». با اینکه این متد خارج از event-listener ما تعریف شده است اما بعدا آن را برای اجرا، درون event-listener فراخوانی خواهیم کرد بنابراین شیء target را نیز به صورت دستی به آن پاس خواهیم داد.

قبل از اینکه این کد را توضیح بدهم باید به ساختار کلید های حذف کتاب (حروف X) در فایل HTML نگاهی بیندازیم. اگر یادتان باشد کد زیر مسئول ساخت این کلید ها در فایل HTML بود:

// Add Book To List
UI.prototype.addBookToList = function(book){
  const list = document.getElementById('book-list');
  // Create tr element
  const row = document.createElement('tr');
  // Insert cols
  row.innerHTML = `
    <td>${book.title}</td>
    <td>${book.author}</td>
    <td>${book.isbn}</td>
    <td><a href="#" class="delete">X<a></td>
  `;

  list.appendChild(row);
}
ساختار ایجاد شده در HTML برای حرف X
ساختار ایجاد شده در HTML برای حرف X

بنابراین یک تگ <a> درون <td> ما وجود دارد که همان حرف x است و کلاس delete را نیز دارد. همچنین برای حذف کامل یک ردیف از جدول باید تمام <tr> را حذف کنیم. از آنجایی که کلید حذف (کلاس delete) درون <td> است باید این مسیر را تا <tr> مسیر دهی کرده و سپس آن را حذف کنیم. حالا متوجه کد زیر می شوید؟

// Delete Book
UI.prototype.deleteBook = function(target){
  if(target.className === 'delete') {
    target.parentElement.parentElement.remove();
  }
}

بله <tr> پدر دوم تگ <a> است بنابراین دوبار از parentElement استفاده کرده ایم تا به آن برسیم. حالا می توانیم به event-listener خود برگردیم و از این متد در آن استفاده کنیم:

// Event Listener for delete
document.getElementById('book-list').addEventListener('click', function(e){

  // Instantiate UI
  const ui = new UI();

  // Delete book
  ui.deleteBook(e.target);

  // Show message
  ui.showAlert('Book Removed!', 'success');

  e.preventDefault();
});

از آنجایی که متد deleteBook در prototype مربوط به UI قرار دارد برای استفاده از آن باید یک نمونه (instance) از UI را بسازیم (new UI). سپس از متد deleteBook استفاده کرده ایم و همانطور که گفتم target را به صورت دستی به آن پاس داده ایم. در نهایت نیز با استفاده از متد showAlert پیام حذف موفقیت آمیز ردیف را نمایش خواهیم داد. اگر کد بالا را در مرورگر خود تست کنید، باید بدون هیچ نقصی کار کند. در صورت برخورد با مشکل سعی کنید دوباره کدهایتان را بررسی کنید و یا کدهای خود را با سورس کد این جلسه مقایسه نمایید (دانلود در انتهای این مقاله).

تبدیل پروژه به کلاس های ES6

حالا که پروژه را به صورت کامل کدنویسی کردیم باید یک بار هم آن را با کلاس های ES6 بنویسیم تا با نحوه ی استفاده از آن ها نیز آشنا شویم. اولین کاری که باید انجام دهید، مراجعه به فایل index.html و تبدیل دستور script به appes6.js است:

  <script src="appes6.js"></script>

حالا وارد فایل appes6.js شوید تا کار را شروع کنیم. اگر فایل app.js را به یاد داشته باشید، در آن دو constructor برای Book و UI داشتیم، بنابراین باید در appes6.js نیز دو کلاس به نام های Book و UI ایجاد کنیم:

class Book {

}

class UI {

}

کلاس Book بسیار ساده خواهد بود. در واقع فقط یک constructor خواهد داشت:

class Book {
  constructor(title, author, isbn) {
    this.title = title;
    this.author = author;
    this.isbn = isbn;
  }
}

این کد دقیقا معادل کد زیر در app.js است:

// Book Constructor
function Book(title, author, isbn) {
  this.title = title;
  this.author = author;
  this.isbn = isbn;
}

حالا به سراغ کلاس UI می رویم. متد اول ما addBookToList بود، همچنین متدهای دیگری را نیز داشتیم. بنابراین ابتدا بدنه ی خالی تمام متدهایمان را وارد فایل appes6.js می کنیم:

class UI {
  addBookToList(book) {

  }

  showAlert(message, className) {

  }

  deleteBook(target) {

  }

  clearFields() {

  }
}

در همین ابتدا متوجه می شوید که استفاده از کلاس ها چقدر تمیزتر و جمع و جور تر است! کدهای درون این متدها دقیقا مانند ES5 عمل می کند. بنابراین می توانیم بدنه ی این توابع را از فایل App.js کپی کنیم:

class UI {
  addBookToList(book) {
    const list = document.getElementById('book-list');
    // Create tr element
    const row = document.createElement('tr');
    // Insert cols
    row.innerHTML = `
      <td>${book.title}</td>
      <td>${book.author}</td>
      <td>${book.isbn}</td>
      <td><a href="#" class="delete">X<a></td>
    `;
  
    list.appendChild(row);
  }

  showAlert(message, className) {
    // Create div
    const div = document.createElement('div');
    // Add classes
    div.className = `alert ${className}`;
    // Add text
    div.appendChild(document.createTextNode(message));
    // Get parent
    const container = document.querySelector('.container');
    // Get form
    const form = document.querySelector('#book-form');
    // Insert alert
    container.insertBefore(div, form);

    // Timeout after 3 sec
    setTimeout(function(){
      document.querySelector('.alert').remove();
    }, 3000);
  }

  deleteBook(target) {
    if(target.className === 'delete') {
      target.parentElement.parentElement.remove();
    }
  }

  clearFields() {
    document.getElementById('title').value = '';
    document.getElementById('author').value = '';
    document.getElementById('isbn').value = '';
  }
}

این کلاس UI نیز کامل شده است و برای بقیه ی این موارد نیز می توانیم کدهای app.js را کپی کنیم:

class Book {
  constructor(title, author, isbn) {
    this.title = title;
    this.author = author;
    this.isbn = isbn;
  }
}

class UI {
  addBookToList(book) {
    const list = document.getElementById('book-list');
    // Create tr element
    const row = document.createElement('tr');
    // Insert cols
    row.innerHTML = `
      <td>${book.title}</td>
      <td>${book.author}</td>
      <td>${book.isbn}</td>
      <td><a href="#" class="delete">X<a></td>
    `;
  
    list.appendChild(row);
  }

  showAlert(message, className) {
    // Create div
    const div = document.createElement('div');
    // Add classes
    div.className = `alert ${className}`;
    // Add text
    div.appendChild(document.createTextNode(message));
    // Get parent
    const container = document.querySelector('.container');
    // Get form
    const form = document.querySelector('#book-form');
    // Insert alert
    container.insertBefore(div, form);

    // Timeout after 3 sec
    setTimeout(function(){
      document.querySelector('.alert').remove();
    }, 3000);
  }

  deleteBook(target) {
    if(target.className === 'delete') {
      target.parentElement.parentElement.remove();
    }
  }

  clearFields() {
    document.getElementById('title').value = '';
    document.getElementById('author').value = '';
    document.getElementById('isbn').value = '';
  }
}

// Event Listener for add book
document.getElementById('book-form').addEventListener('submit', function(e){
  // Get form values
  const title = document.getElementById('title').value,
        author = document.getElementById('author').value,
        isbn = document.getElementById('isbn').value

  // Instantiate book
  const book = new Book(title, author, isbn);

  // Instantiate UI
  const ui = new UI();

  console.log(ui);

  // Validate
  if(title === '' || author === '' || isbn === '') {
    // Error alert
    ui.showAlert('Please fill in all fields', 'error');
  } else {
    // Add book to list
    ui.addBookToList(book);

    // Show success
    ui.showAlert('Book Added!', 'success');
  
    // Clear fields
    ui.clearFields();
  }

  e.preventDefault();
});

// Event Listener for delete
document.getElementById('book-list').addEventListener('click', function(e){

  // Instantiate UI
  const ui = new UI();

  // Delete book
  ui.deleteBook(e.target);

  // Show message
  ui.showAlert('Book Removed!', 'success');

  e.preventDefault();
});

به همین راحتی توانستیم پروژه ی خودمان را از ES5 به ES6 بیاوریم. درست است که این پروژه یک پروژه ی ساده بود اما انجام این کار برای پروژه های سنگین نیز آنچنان سخت نیست. باور ندارید؟ خودتان امتحان کنید! در قسمت بعد تمام این پروژه را به Local Storage نیز اضافه می کنم تا با refresh شدن صفحه، محتوای آن از بین نرود.

دانلود سورس کد کامل تا این جلسه

تمام فصل‌های سری ترتیبی که روکسو برای مطالعه‌ی دروس سری پروژه‌های مدرن جاوا اسکریپت توصیه می‌کند:
نویسنده شوید
دیدگاه‌های شما (3 دیدگاه)

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

zeinab
26 آذر 1398
سلام فک کنم جلسه ۱۳ به اشتباه گذاشته شده است. لطفا بررسی کنید.

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

مهدی
26 آذر 1398
سلام ممنون از آموزشهای خوبتون. امیدوارم تو کارتون پایدار و موفق باشید. فقط این جلسه (برنامه لیست کتاب) رو متوجه نمیشم اینکه این وسط (آموزش جاوا اسکریپت) قرار گرفته؟!!! قبلش کجاس؟

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

Pej
24 آذر 1398
سلام . کارتون خیلی درسته . من میخواستم بدونم برای یادگرفتن جاوااسکریپت چقدر باید زمان گذاشت ؟ من میخواهم شبانه روز روش وقت بزارم . 1 سال طول میکشه تا یادش بگیرم یا بیشتر ؟ ویدئو آموزشی بهتر هست یا خواندن مقاله ؟

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

امیر زوارمی
27 آذر 1398
سلام دوست عزیز، خسته نباشید برای جاوا اسکریپت یا هر زبان برنامه نویسی دیگه ای که بخواید یاد بگیرید، چند عامل تعیین کننده است: 1- آیا قبلا زبان برنامه نویسی دیگه ای رو کار کردید یا جاوا اسکریپت اولین زبان برنامه نویسی شما است؟ زبان های HTML و ... زبان نشانه گذاری هستند نه برنامه نویسی. 2- استعداد خودتون در یادگیری اینطور مباحث (داشتن منطق ریاضیاتی) 3- تعداد ساعت های کد نویسی برای آموزش ها بهتره با آموزش های عادی شروع کنید که خیلی طولانی نباشن (فرقی نداره ویدیویی یا متنی). بهترین راه اینه که بعد مطالعه یا تماشای آموزش ها، شروع کنید به کد نویسی. برنامه نویسی از اون چیز هایی هست که تا خودتون کد ننویسید نمی تونید یاد بگیرد. وقتی خودتون شروع به کدنویسی کنید، به مشکلات مختلف برمی خورید و اونجا باید از توی اینترنت دنبال جوابشون باشید. اون وقت واقعا یاد می گیرید! بنابراین مهم ترین عامل کدنویسی هست. اگر واقعا تلاش کنید جاوا اسکریپت رو در کمتر از یک سال یاد می گیرید. خیلی ها توی 6 ماه تمومش می کنن.

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