MATIN MOLKARA
SERIES: JavaScript — PART 95 OF 108

95- آموزش جاوااسکریپت | پروژه عملی: قسمت 8 از 12- مدیریت Edit State و آماده‌سازی فرم برای ویرایش آیتم‌ها

در این بخش یاد می‌گیرید چگونه در زمان کلیک روی آیکن ویرایش، فرم را وارد حالت ویرایش کنید، دکمه‌های مناسب را نمایش دهید، از Event Delegation استفاده کنید و آیتم انتخاب‌شده را داخل فرم بارگذاری کنید.

در این بخش هدف ما پیاده‌سازی حالت ویرایش برای آیتم‌ها است.
وقتی کاربر روی آیکن ویرایش یک آیتم کلیک می‌کند، باید چند اتفاق مهم بیفتد:

  • فرم وارد حالت ویرایش شود.
  • دکمه‌های Update، Delete و Back نمایش داده شوند.
  • دکمه Add Meal مخفی شود.
  • اطلاعات آیتم انتخاب‌شده داخل فیلدهای فرم قرار بگیرد.
  • آیتم انتخاب‌شده به‌عنوان currentItem ذخیره شود.

ایجاد متد clearEditState

اولین قدم این است که یک متد برای خروج از حالت ویرایش و بازگرداندن رابط کاربری به حالت اولیه بسازیم.

در این متد باید:

  • ورودی‌ها پاک شوند.
  • دکمه‌های مربوط به ویرایش مخفی شوند.
  • دکمه افزودن دوباره نمایش داده شود.

کد

clearEditState: function () {
  UIController.clearInput();

  document.querySelector(UISelectors.updateBtn).style.display = 'none';
  document.querySelector(UISelectors.deleteBtn).style.display = 'none';
  document.querySelector(UISelectors.backBtn).style.display = 'none';
  document.querySelector(UISelectors.addBtn).style.display = 'inline';
}

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

برای کنترل دکمه‌های ویرایش، حذف و بازگشت باید آن‌ها را به بخش UISelectors اضافه کنیم.

کد

const UISelectors = {
  itemList: '#item-list',
  addBtn: '.add-btn',
  updateBtn: '.update-btn',
  deleteBtn: '.delete-btn',
  backBtn: '.back-btn',
  itemNameInput: '#item-name',
  itemCaloriesInput: '#item-calories'
};

اجرای clearEditState در شروع برنامه

بعد از ساخت این متد، باید آن را در ابتدای اجرای برنامه صدا بزنیم تا فرم از همان ابتدا در حالت عادی قرار بگیرد.

کد

const init = function () {
  UIController.clearEditState();

  // سایر event listenerها
};

init();

تشخیص کلیک روی آیکن ویرایش با Event Delegation

از آن‌جا که آیتم‌های لیست بعد از بارگذاری صفحه ساخته می‌شوند، نمی‌توانیم مستقیماً روی دکمه ویرایش آن‌ها event listener قرار دهیم.
به همین دلیل باید از Event Delegation استفاده کنیم.

یعنی event را روی عنصر والد قرار می‌دهیم و سپس بررسی می‌کنیم آیا کلیک روی آیکن ویرایش انجام شده است یا نه.

کد ثبت رویداد

document.querySelector(UISelectors.itemList).addEventListener('click', itemEditClick);

کد تابع ویرایش

const itemEditClick = function (e) {
  e.preventDefault();

  if (e.target.classList.contains('edit-item')) {
    console.log('edit item');
  }
};

چرا به Event Delegation نیاز داریم؟

چون دکمه یا آیکن ویرایش از ابتدا در DOM وجود ندارد و بعداً به صفحه اضافه می‌شود.
بنابراین اگر بخواهیم مستقیم روی آن listener تعریف کنیم، در زمان شروع برنامه عنصر موردنظر هنوز وجود ندارد.

راه‌حل استاندارد این است که listener را روی والد مشترک، یعنی لیست آیتم‌ها، قرار دهیم.


دریافت شناسه آیتم انتخاب‌شده

بعد از تشخیص کلیک روی آیکن ویرایش، باید شناسه آیتم را از ساختار HTML استخراج کنیم.

فرض کنید id آیتم‌ها به این شکل باشد:

<li id="item-0">...</li>
<li id="item-1">...</li>

برای دسترسی به این id باید از parentNode.parentNode استفاده کنیم، چون خود آیکن داخل عناصر تو در تو قرار گرفته است.

کد

const listId = e.target.parentNode.parentNode.id;

اگر مقدار listId برابر item-0 باشد، باید فقط عدد 0 را جدا کنیم.

کد

const listIdArr = listId.split('-');
const id = parseInt(listIdArr[1]);

دریافت آیتم براساس شناسه

حالا که شناسه عددی آیتم را داریم، باید آبجکت کامل آن را از داده‌ها پیدا کنیم.
برای این کار یک متد در ItemController می‌سازیم.

کد

getItemById: function (id) {
  let found = null;

  data.items.forEach(function (item) {
    if (item.id === id) {
      found = item;
    }
  });

  return found;
}

ذخیره آیتم انتخاب‌شده به‌عنوان currentItem

وقتی آیتم موردنظر پیدا شد، باید آن را در currentItem ذخیره کنیم تا در بخش‌های دیگر برنامه نیز به آن دسترسی داشته باشیم.

کد

setCurrentItem: function (item) {
  data.currentItem = item;
}

ساخت متد getCurrentItem

برای خواندن مقدار آیتم جاری، یک متد دیگر هم نیاز داریم.

کد

getCurrentItem: function () {
  return data.currentItem;
}

تکمیل تابع کلیک روی ویرایش

اکنون می‌توانیم کل فرایند انتخاب آیتم را در تابع ویرایش پیاده‌سازی کنیم.

کد

const itemEditClick = function (e) {
  e.preventDefault();

  if (e.target.classList.contains('edit-item')) {
    const listId = e.target.parentNode.parentNode.id;
    const listIdArr = listId.split('-');
    const id = parseInt(listIdArr[1]);

    const itemToEdit = ItemController.getItemById(id);

    ItemController.setCurrentItem(itemToEdit);

    UIController.addItemToForm();
  }
};

قرار دادن اطلاعات آیتم داخل فرم

بعد از تعیین currentItem، باید اطلاعات آن را داخل inputهای فرم قرار دهیم.

کد

addItemToForm: function () {
  document.querySelector(UISelectors.itemNameInput).value =
    ItemController.getCurrentItem().name;

  document.querySelector(UISelectors.itemCaloriesInput).value =
    ItemController.getCurrentItem().calories;

  UIController.showEditState();
}

نمایش حالت ویرایش با showEditState

این متد دقیقاً برعکس clearEditState عمل می‌کند.
در اینجا باید دکمه‌های ویرایش نمایش داده شوند و دکمه افزودن مخفی شود.

کد

showEditState: function () {
  document.querySelector(UISelectors.updateBtn).style.display = 'inline';
  document.querySelector(UISelectors.deleteBtn).style.display = 'inline';
  document.querySelector(UISelectors.backBtn).style.display = 'inline';
  document.querySelector(UISelectors.addBtn).style.display = 'none';
}

جمع‌بندی منطق این بخش

در این بخش روند کامل ورود به حالت ویرایش را پیاده‌سازی کردیم:

  1. ساخت متد clearEditState برای بازگشت فرم به حالت اولیه
  2. اضافه کردن سلکتورهای دکمه‌های جدید
  3. اجرای حالت اولیه در زمان init
  4. استفاده از Event Delegation برای تشخیص کلیک روی آیکن ویرایش
  5. استخراج شناسه آیتم از DOM
  6. پیدا کردن آیتم از روی id
  7. ذخیره آیتم در currentItem
  8. نمایش اطلاعات آیتم در فرم
  9. تغییر رابط کاربری به حالت ویرایش

کد نهایی این بخش

const ItemController = (function () {
  const data = {
    items: [],
    currentItem: null
  };

  return {
    getItemById: function (id) {
      let found = null;

      data.items.forEach(function (item) {
        if (item.id === id) {
          found = item;
        }
      });

      return found;
    },

    setCurrentItem: function (item) {
      data.currentItem = item;
    },

    getCurrentItem: function () {
      return data.currentItem;
    }
  };
})();

const UIController = (function () {
  const UISelectors = {
    itemList: '#item-list',
    addBtn: '.add-btn',
    updateBtn: '.update-btn',
    deleteBtn: '.delete-btn',
    backBtn: '.back-btn',
    itemNameInput: '#item-name',
    itemCaloriesInput: '#item-calories'
  };

  return {
    clearInput: function () {
      document.querySelector(UISelectors.itemNameInput).value = '';
      document.querySelector(UISelectors.itemCaloriesInput).value = '';
    },

    clearEditState: function () {
      UIController.clearInput();
      document.querySelector(UISelectors.updateBtn).style.display = 'none';
      document.querySelector(UISelectors.deleteBtn).style.display = 'none';
      document.querySelector(UISelectors.backBtn).style.display = 'none';
      document.querySelector(UISelectors.addBtn).style.display = 'inline';
    },

    showEditState: function () {
      document.querySelector(UISelectors.updateBtn).style.display = 'inline';
      document.querySelector(UISelectors.deleteBtn).style.display = 'inline';
      document.querySelector(UISelectors.backBtn).style.display = 'inline';
      document.querySelector(UISelectors.addBtn).style.display = 'none';
    },

    addItemToForm: function () {
      document.querySelector(UISelectors.itemNameInput).value =
        ItemController.getCurrentItem().name;

      document.querySelector(UISelectors.itemCaloriesInput).value =
        ItemController.getCurrentItem().calories;

      UIController.showEditState();
    },

    getSelectors: function () {
      return UISelectors;
    }
  };
})();

const App = (function (ItemController, UIController) {
  const UISelectors = UIController.getSelectors();

  const loadEventListeners = function () {
    document
      .querySelector(UISelectors.itemList)
      .addEventListener('click', itemEditClick);
  };

  const itemEditClick = function (e) {
    e.preventDefault();

    if (e.target.classList.contains('edit-item')) {
      const listId = e.target.parentNode.parentNode.id;
      const listIdArr = listId.split('-');
      const id = parseInt(listIdArr[1]);

      const itemToEdit = ItemController.getItemById(id);
      ItemController.setCurrentItem(itemToEdit);
      UIController.addItemToForm();
    }
  };

  return {
    init: function () {
      UIController.clearEditState();
      loadEventListeners();
    }
  };
})(ItemController, UIController);

App.init();

نتیجه

با پیاده‌سازی این بخش، کاربر می‌تواند با کلیک روی آیکن ویرایش:

  • آیتم موردنظر را انتخاب کند،
  • اطلاعات آن را داخل فرم ببیند،
  • و رابط کاربری را وارد حالت ویرایش کند.
// 0 comments
#جاوااسکریپت#JavaScript#Edit State#Event Delegation#DOM#فرم ویرایش#مدیریت وضعیت#آموزش جاوااسکریپت#CRUD#UI Controller

نظرات (0)

نظر خود را بنویسید