برنامه مدیریت کالری غذا: دکمه back و حذف آیتم‌ها

Tracalorie Project: Back Button + Deleting Items

04 شهریور 1399
برنامه ی مدیریت کالری غذا: دکمه ی back و حذف آیتم ها

تا این قسمت از این سری آموزشی، بسیار خوب جلو رفته ایم و قسمت اصلی کار را پیاده سازی کرده ایم. حالا تنها جزئیات آن باقی مانده است. در این جلسه ابتدا با دکمه back و کارایی آن شروع می کنیم که کار بسیار ساده ای می باشد. برای شروع باید به کنترلر app برویم و یک event-listener دیگر ایجاد کنیم:

// بقیه کدها //
    // Edit icon click event
    document.querySelector(UISelectors.itemList).addEventListener('click', itemEditClick);

    // Update item event
    document.querySelector(UISelectors.updateBtn).addEventListener('click', itemUpdateSubmit);

     // Back button event
     document.querySelector(UISelectors.backBtn).addEventListener('click', UICtrl.clearEditState);
  }

تنها کاری که لازم بود انجام دهیم، صدا زدن متد clearEditState می باشد! مرحله بعد اضافه کردن یک event-listener دیگر برای حذف کردن آیتم ها است بنابراین:

// بقیه کدها //
    // Edit icon click event
    document.querySelector(UISelectors.itemList).addEventListener('click', itemEditClick);

    // Update item event
    document.querySelector(UISelectors.updateBtn).addEventListener('click', itemUpdateSubmit);

    // Delete item event
    document.querySelector(UISelectors.deleteBtn).addEventListener('click', itemDeleteSubmit);

     // Back button event
     document.querySelector(UISelectors.backBtn).addEventListener('click', UICtrl.clearEditState);
  }

متد itemDeleteSubmit که در کد بالا استفاده شده است، هنوز هیچ جایی از فایل ما تعریف نشده است بنابراین باید آن را تعریف کنیم. من این متد را در همان کنترلر app و پس از متد itemUpdateSubmit تعریف می کنم. در مرحله اول باید آیتم فعلی را دریافت کنیم تا بدانیم کدام آیتم را حذف کنیم:

  // Delete button event
  const itemDeleteSubmit = function(e){
    // Get current item
    const currentItem = ItemCtrl.getCurrentItem();

    e.preventDefault();
  }

مثل همیشه از preventDefault استفاده کرده ام تا ناهماهنگی در کدها نباشد. در مرحله بعد باید آیتم دریافت شده از getCurrentItem را بر اساس آیدی برگردانده شده از data structure حذف کنیم. این کار نیز ساده است:

  // Delete button event
  const itemDeleteSubmit = function(e){
    // Get current item
    const currentItem = ItemCtrl.getCurrentItem();

    // Delete from data structure
    ItemCtrl.deleteItem(currentItem.id);

    e.preventDefault();
  }

از آنجایی که هنوز متدی به نام deleteItem نداریم باید به کنترلر item ها برویم و پس از متد updateItem آن را تعریف کنیم:

    deleteItem: function(id){
      // Get ids
      const ids = data.items.map(function(item){
        return item.id;
      });

      // Get index
      const index = ids.indexOf(id);

      // Remove item
      data.items.splice(index, 1);
    },
    clearAllItems: function(){
      data.items = [];
    }

ما با استفاده از تابع map بین آیتم ها گردش کرده ایم و id تک تک آن ها را برمی گرداند. کار تابع map فیلتر کردن طبق تابع پاس داده شده به آن است، بنابراین چیزی شبیه به forEach است اما چیزی را در نهایت برمی گرداند. حالا تمام id های تمام آیتم ها درون ثابت ids می باشد. در مرحله بعد باید index مربوط به آیتم پاس داده شده را پیدا کنیم. این کار با indexOf انجام شده است. در نهایت نیز با استفاده از متد splice آن آیتم را از آرایه data.items حذف کرده ایم. این قسمت تکمیل شده است.

حالا دوباره به itemDeleteSubmit برگردید. کد بالا آیتم را از data structure حذف می کرد اما هنوز تغییرات ما درون UI قابل مشاهده نیست بنابراین می گوییم:

  // Delete button event
  const itemDeleteSubmit = function(e){
    // Get current item
    const currentItem = ItemCtrl.getCurrentItem();

    // Delete from data structure
    ItemCtrl.deleteItem(currentItem.id);

    // Delete from UI
    UICtrl.deleteListItem(currentItem.id);

    e.preventDefault();
  }

این متد (deleteListItem) نیز تعریف نشده است بنابراین به کنترلر UI می رویم و پس از updateListItem آن را تعریف می کنیم:

    deleteListItem: function(id){
      const itemID = `#item-${id}`;
      const item = document.querySelector(itemID);
      item.remove();
    }

به همین سادگی می توانیم آیتم ها را حذف کنیم. در حال حاضر اگر به مرورگر بروید و این کد را تست کنید، قابلیت حذف آیتم ها به برنامه اضافه شده است. تنها مشکل اینجاست که پس از حذف آیتم مورد نظر از UI و data structure دیگر از حالت ویرایش خارج نمی شویم و تمام دکمه های Update Meal و Back و... هنوز نمایش داده می شوند. همچنین کالری کل نیز به روز رسانی نمی شود و روی مقدار قبلی باقی می ماند. اگر یادتان باشد در قسمت قبل دقیقا همین مشکل را داشتیم و با چند خط کد آن را حل کردیم. برای حل مشکل به itemDeleteSubmit برگردید و کدهای آن را تکمیل کنید:

  // Delete button event
  const itemDeleteSubmit = function(e){
    // Get current item
    const currentItem = ItemCtrl.getCurrentItem();

    // Delete from data structure
    ItemCtrl.deleteItem(currentItem.id);

    // Delete from UI
    UICtrl.deleteListItem(currentItem.id);

    // Get total calories
    const totalCalories = ItemCtrl.getTotalCalories();
    // Add total calories to UI
    UICtrl.showTotalCalories(totalCalories);

    UICtrl.clearEditState();

    e.preventDefault();
  }

دوباره چیزی که در جلسه قبل توضیح دادم را عینا توضیح می دهم. پس از صدا زدن deleteListItem و به روز رسانی آیتم ها، دوباره متد getTotalCalories را صدا زده ایم. باید یادتان باشد که این متد را در جلسات قبل نوشته ایم و کارش محاسبه تعداد کل کالری ها بود. با این حساب تعداد کل کالری ها (آپدیت شده) درون totalCalories قرار می گیرد. سپس showTotalCalories را صدا می زنیم تا مقدار کل کالری را در UI به روز رسانی کند. در نهایت اگر متد clearEditState را صدا بزنیم، از حالت ویرایش خارج می شویم. در ضمن این متد درون خودش متد پاک کردن فیلدها را نیز دارد بنابراین نیازی به پاکسازی جداگانه فیلد ها نداریم. حالا کدها بدون مشکل کار می کنند.

در مرحله بعد باید روی دکمه Clear All (قسمت بالا و سمت راست برنامه) کار کنیم. اگر کاربر روی این دکمه کلیک کند باید تمام آیتم ها یکجا حذف شوند. بنابراین قدم اول تعریف یک event-listener برای آن است:

    // Update item event
    document.querySelector(UISelectors.updateBtn).addEventListener('click', itemUpdateSubmit);

    // Delete item event
    document.querySelector(UISelectors.deleteBtn).addEventListener('click', itemDeleteSubmit);

     // Back button event
     document.querySelector(UISelectors.backBtn).addEventListener('click', UICtrl.clearEditState);

     // Clear items event
    document.querySelector(UISelectors.clearBtn).addEventListener('click', clearAllItemsClick);
  }

حالا باید متد clearAllItemsClick را تعریف کنیم. البته یادتان نرود که clearBtn را نیز به مجموعه سلکتورهایتان اضافه کنید:

  const UISelectors = {
    itemList: '#item-list',
    listItems: '#item-list li',
    addBtn: '.add-btn',
    updateBtn: '.update-btn',
    deleteBtn: '.delete-btn',
    backBtn: '.back-btn',
    clearBtn: '.clear-btn',
    itemNameInput: '#item-name',
    itemCaloriesInput: '#item-calories',
    totalCalories: '.total-calories'
  }

من متد clearAllItemsClick را پس از itemDeleteSubmit تعریف می کنم:

  // Clear items event
  const clearAllItemsClick = function(){
    // Delete all items from data structure
    ItemCtrl.clearAllItems();
    
  }

ابتدا متدی به نام clearAllItems تمام آیتم های ما را حذف می کند. من این متد را درون کنترلر item و پس از deleteItem تعریف می کنم:

    clearAllItems: function(){
      data.items = [];
    }

یعنی آرایه data را خالی می کنیم. همچنین تابع دیگری به نام removeItems را نیز در کنترلر UI تعریف می کنیم تا آیتم ها را از UI نیز حذف کند:

    removeItems: function(){
      let listItems = document.querySelectorAll(UISelectors.listItems);

      // Turn Node list into array
      listItems = Array.from(listItems);

      listItems.forEach(function(item){
        item.remove();
      });
    }

این کد را در جلسات قبل نیز دیده ایم، بنابراین چیز جدیدی برای توضیح ندارد. حالا می توانیم clearAllItemsClick را تکمیل کنیم:

  // Clear items event
  const clearAllItemsClick = function(){
    // Delete all items from data structure
    ItemCtrl.clearAllItems();

    // Get total calories
    const totalCalories = ItemCtrl.getTotalCalories();
    // Add total calories to UI
    UICtrl.showTotalCalories(totalCalories);

    // Remove from UI
    UICtrl.removeItems();

    // Hide UL
    UICtrl.hideList();
    
  }

بدین صورت برنامه ما کامل شده است. ما می توانیم آموزش را در همین مرحله متوقف کنیم اما من دوست دارم از local storage استفاده کنیم تا با رفرش شدن صفحه، اطلاعات وارد شده پاک نشود. در جلسات بعد به این موضوع می پردازیم.

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

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

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