در قسمت قبل مقدار total calories را محاسبه کردیم و حالا باید کاری کنیم تا بتوانیم آیتم های ثبت شده را ویرایش کنیم. همانطور که در انتهای جلسه قبل توضیح دادم برای این کار باید دکمه Add Meal را مخفی کنیم و سپس دکمه های ویرایش را که در حال حاضر به صورت کامنت درون فایل index.html هستند را نمایش بدهیم. در ابتدا به این فایل رفته و آن ها را از حالت کامنت خارج کنید:
<button class="update-btn btn orange"><i class="fa fa-pencil-square-o"></i> Update Meal</button> <button class="delete-btn btn red"><i class="fa fa-remove"></i> Delete Meal</button>
سپس برای شروع متدی به نام clearEditState را در کنترلر UI تعریف می کنیم:
// بقیه کدها // showTotalCalories: function(totalCalories){ document.querySelector(UISelectors.totalCalories).textContent = totalCalories; }, clearEditState: function(){ UICtrl.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'; }
درون این تابع در قدم اول clearInput را صدا زده ایم که جلسات قبل تعریف کرده بودیم. این تابع فیلد های input را پاک می کند اما تابع clearInput را دقیقا برای همین نوشته بودیم و نیازی به تکرار کدهای قبلی نیست بنابراین آن را صدا زده ایم. سپس دکمه های update و delete و back را مخفی کرده ایم اما دکمه add را نمایش می دهیم. این برای شروع برنامه است که نمی خواهیم به صورت پیش فرض در حالت ویرایش باشیم. از آنجا که درون این تابع از selector های از پیش تعریف شده استفاده کرده ایم باید به ثابت UISelectors رفته تا خصوصیتی برای دریافت این دکمه ها بنویسیم:
// UI Controller const UICtrl = (function(){ const UISelectors = { itemList: '#item-list', addBtn: '.add-btn', updateBtn: '.update-btn', deleteBtn: '.delete-btn', backBtn: '.back-btn', itemNameInput: '#item-name', itemCaloriesInput: '#item-calories', totalCalories: '.total-calories' } // بقیه کدها //
من سه خصوصیت updateBtn و deleteBtn و backBtn را در این قسمت تعریف کرده ام که درون تابع clearEditState استفاده شده اند. حالا باید به init برویم تا زمان بارگذاری برنامه اولین متدی که صدا زده می شود clearEditState باشد:
// Public methods return { init: function(){ // Clear edit state / set initial set UICtrl.clearEditState(); // Fetch items from data structure const items = ItemCtrl.getItems(); // بقیه کدها //
حالا اگر برنامه را در مرورگر رفرش کنید تمام دکمه ها به جز Add Meal مخفی می شوند. در مرحله بعد باید کاری کنیم که با کلیک روی دکمه edit (آیکون مداد) وارد حالت ویرایش شویم. اگر توجه داشته باشید این آیکون ویرایش در ابتدای شروع برنامه موجود نیست چرا که کاربر هیچ لیستی از آیتم های غذایی را نداشته و تازه برنامه را باز کرده است. به همین دلیل نمی توانیم آیکون را به صورت عادی دریافت کنیم و گرنه جاوا اسکریپت به ما خطا می دهد. راه حل استفاده از event delegation است!
به کنترلر اصلی App بروید و درون قسمت loadEventListeners کدهای دریافت آیکون مداد را بنویسید:
// App Controller const App = (function(ItemCtrl, UICtrl){ // Load event listeners const loadEventListeners = function(){ // Get UI selectors const UISelectors = UICtrl.getSelectors(); // Add item event document.querySelector(UISelectors.addBtn).addEventListener('click', itemAddSubmit); // Edit icon click event document.querySelector(UISelectors.itemList).addEventListener('click', itemUpdateSubmit); } // بقیه کدها //
از آنجایی که نمی توانیم آیکون مداد را مستقیما هدف بگیریم، itemList را هدف گرفته ایم تا هنگام کلیک روی آن متدی به نام itemUpdateSubmit اجرا شود. این تابع هنوز تعریف نشده است، بنابراین برای تعریف آن به پایین تر از itemAddSubmit می رویم:
// Update item submit const itemUpdateSubmit = function(e){ console.log('test'); e.preventDefault(); } // Public methods return { // بقیه کدها //
در حال حاضر برای تست این کد به مرورگر بروید و یک آیتم غذایی را اضافه کنید. متوجه می شوید که با کلیک روی هر کدام از آیتم ها (و نه روی آیکون مداد) عبارت test برای ما log می شود. قطعا چنین حالتی ایده آل نیست. ما می خواهیم این تابع فقط زمانی اجرا شود که روی خود آیکون مداد کلیک شود بنابراین با یک شرط if آن را تصحیح می کنیم:
// Update item submit const itemUpdateSubmit = function(e){ if(e.target.classList.contains('edit-item')){ console.log('test'); } e.preventDefault(); }
این شرط if می گوید اگر target ما دارای کلاسی به نام edit-item بود (آیکون های مداد دارای کلاسی به این نام هستند) آن گاه test را log کن. حالا فقط با کلیک روی آیکون مداد عبارت Test نمایش داده می شود. در این مرحله باید کاری کنیم که آیتمی که روی آیکون مدادِ آن کلیک شده است، به currentItem اضافه شود. اگر یادتان باشد currentItem را درون dataStructure تعریف کرده بودیم:
// Data Structure / State const data = { items: [ // {id: 0, name: 'Steak Dinner', calories: 1200}, // {id: 1, name: 'Cookie', calories: 400}, // {id: 2, name: 'Eggs', calories: 300} ], currentItem: null, totalCalories: 0 }
بنابراین ابتدا باید id آن آیتم را بگیریم:
// Update item submit const itemUpdateSubmit = function(e){ if(e.target.classList.contains('edit-item')){ // Get list item id (item-0, item-1) const listId = e.target.parentNode.parentNode.id; console.log(listId); } e.preventDefault(); }
اگر این کد را در مرورگر اجرا کنیم متوجه خواهیم شد که با کلیک روی هر آیکون مداد، listId آن نمایش داده می شود. مثلا item-0 و item-1 و الی آخر. بنابراین کد تکمیل شده ما بدین شکل خواهد بود:
// Update item submit const itemUpdateSubmit = function(e){ if(e.target.classList.contains('edit-item')){ // Get list item id (item-0, item-1) const listId = e.target.parentNode.parentNode.id; // Break into an array const listIdArr = listId.split('-'); // Get the actual id const id = parseInt(listIdArr[1]); // Get item const itemToEdit = ItemCtrl.getItemById(id); // Set current item ItemCtrl.setCurrentItem(itemToEdit); // Add item to form UICtrl.addItemToForm(); } e.preventDefault(); }
من به شما وقت می دهم که خودتان نحوه کار کلی این کد را درک کنید، با اینکه هنوز متد هایی مانند getItemById را تعریف نکرده ایم اما باید نحوه کلی کار را درک کنید. در جلسه بعد به شما می گویم که این کد چطور کار خواهد کرد.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.