امیدوارم تا این قسمت پیش آمده و خسته نشده باشید. قبل از شروع این جلسه باید نکته ای را از جلسه قبل تصحیح کنیم. ما در جلسه قبل در قسمت کنترلر App متدی را به نام itemUpdateSubmit صدا زدیم (روی event-listener مربوط به آیکون مداد) اما کار این متد واقعا ثبت (submit) تغییرات نیست بنابراین نام بهتر itemEditClick است. این موضوع در واقع باعث خطا نمی شود و تقریبا سلیقه ای است اما من نام itemEditClick را ترجیح می دهم بنابراین کد زیر را:
// Edit icon click event document.querySelector(UISelectors.itemList).addEventListener('click', itemUpdateSubmit);
تبدیل به این کد کنید:
// Edit icon click event document.querySelector(UISelectors.itemList).addEventListener('click', itemEditClick);
سپس نام این تابع را در هنگام تعریف نیز باید تغییر دهیم:
// Click edit item const itemEditClick = function(e){ if(e.target.classList.contains('edit-item')){ // بقیه کدها //
حالا که این مشکل برطرف شد به روال عادی برمی گردیم. در حال حاضر اگر روی آیکون مداد یکی از آیتم ها کلیک کنیم دکمه های Update Meal و Delete Meal و Back ظاهر می شوند و وارد حالت ویرایش می شویم. زمانی که کاربر مقادیر ظاهر شده در input ها را تغییر داد و روی دکمه Update Meal کلیک کرد باید تابعی اجرا شود و اطلاعات را به روز رسانی کند. مشخصا چنین کاری نیاز به یک event-listener دارد بنابراین به کنترلر App بروید و مثل من آن را تعریف کنید:
// 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', itemEditClick); // Update item event document.querySelector(UISelectors.updateBtn).addEventListener('click', itemUpdateSubmit); }
اینجاست که متدی به نام itemUpdateSubmit را صدا می زنیم، حالا باید آن را تعریف کنیم. برای این کار پایین تر از itemEditClick رفته و آن را تعریف می کنیم. مثل همیشه اولین کار preventDefault است:
// Update item submit const itemUpdateSubmit = function (e) { console.log('update'); e.preventDefault(); }
حالا برای تست کردن این کد وارد مرورگر شده و یک آیتم را تعریف کنید. سپس روی آیکون مداد کلیک کنید تا به حالت ویرایش بروید. بعد از آن روی دکمه Update Meal کلیک کنید. اگر کدها را درست نوشته باشید، باید در قسمت کنسول مرورگر شاهد کلمه update باشید. اما در حال حاضر کدهای ما مشکلی دارند. اگر در همین حالت ویرایش باشیم:
سپس به جای کلیک روی Update Meal دکمه Enter روی کیبورد را فشار بدهیم، این اتفاق می افتد:
به عبارت دیگر به جای به روز رسانی، فرم را ثبت می کند بنابراین یک غذا دو بار ثبت شده و به شکل بالا کپی می شود! همچنین input ها نیز خالی می شوند که اصلا جالب نیست. راه های مختلفی برای حل این مشکل وجود دارد که یکی از آن ها غیرفعال کردن enter است. برای انجام این کار به کنترلر App رفته و در قسمت event-listener ها یک event-listener جدید به شکل زیر تعریف کنید:
// Add item event document.querySelector(UISelectors.addBtn).addEventListener('click', itemAddSubmit); // Disable submit on enter document.addEventListener('keypress', function(e){ if(e.keyCode === 13 || e.which === 13){ e.preventDefault(); return false; } }); // بقیه کدها //
هر کدام از کلیدهای کیبورد دارای کد خاصی هستند و کد enter برابر 13 می باشد. از طرفی برخی از مرورگر های قدیمی از keyCode پشتیبانی نمی کنند و باید به جای آن از which استفاده کنیم. من در کد بالا گفته ام اگر keycode برابر 13 بود و یا اینکه e.which برابر 13 بود، perventDefault کن و مقدار false را برگردان. از این به بعد کلید enter در برنامه ما از کار می افتد. حالا به تابع خودمان برمی گردیم:
// Update item submit const itemUpdateSubmit = function (e) { console.log('update'); e.preventDefault(); }
حالا که مشکل را رفع کرده ایم، به جای این دستور console باید شروع به کدنویسی واقعی کنیم. قدم اول دریافت مقدار درون input ها است. چرا؟ به دلیل اینکه کاربر قصد ویرایش دارد و قطعا مقدار input را عوض می کند بنابراین باید دوباره آن را دریافت کنیم:
// Update item submit const itemUpdateSubmit = function (e) { // Get item input const input = UICtrl.getItemInput(); e.preventDefault(); }
getItemInput را در جلسات قبل تعریف کرده بودیم و می دانید که دو input داریم بنابراین این متد یک شیء حاوی دو input را برمی گرداند. حالا می توانیم متدی بنویسیم که مقادیر برگردانده شده را به روز رسانی کند:
// Update item submit const itemUpdateSubmit = function (e) { // Get item input const input = UICtrl.getItemInput(); // Update item const updatedItem = ItemCtrl.updateItem(input.name, input.calories); e.preventDefault(); }
حالا باید updateItem را درون کنترلر Item ها تعریف کنیم. من دقیقا زیر getItemById این کار را انجام می دهم:
getItemById: function(id){ let found = null; // Loop through items data.items.forEach(function(item){ if(item.id === id){ found = item; } }); return found; }, updateItem: function(name, calories){ // Calories to number calories = parseInt(calories); let found = null; data.items.forEach(function(item){ if(item.id === data.currentItem.id){ item.name = name; item.calories = calories; found = item; } }); return found; },
همانطور که می بینید این تابع دو پارامتر ورودی می گیرد: نام غذا و کالری آن. از آنجا که تعداد کالری را از input ها می گیریم، قطعا نوع آن ها رشته است بنابراین در همان ابتدا با parseInt آن را تبدیل به عدد می کنیم. در مرحله بعد با یک حلقه forEach بین آیتم ها گردش می کنیم. یادتان باشد که زمانی که روی آیکون مدادِ یک آیتم کلیک کنیم، آن آیتم برابر با currentItem در نظر گرفته می شود (کدهای آن را در جلسات قبل نوشتیم) بنابراین اگر id یکی از item ها برابر currentItem.id بود یعنی آیتم مورد نظر را پیدا کرده ایم بنابراین باید نام و کالری را تغییر می دهیم. در نهایت نیز found را برمی گردانیم.
در قسمت بعد کار را ادامه می دهیم تا بتوانیم مقدار جدید را کامل ثبت کرده و total calories را هم دوباره محاسبه کنیم.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.