در قسمت قبل آیتم های خود را به Data structure اضافه کردیم و طی این مکانیسم آیدی های هر آیتم را نیز تعیین کردیم. اگر یادتان باشد برای اضافه کردن آیتم ها به data structure از متد زیر استفاده کرده بودیم:
// Add item submit const itemAddSubmit = function(e){ // Get form input from UI Controller const input = UICtrl.getItemInput(); // Check for name and calorie input if(input.name !== '' && input.calories !== ''){ // Add item const newItem = ItemCtrl.addItem(input.name, input.calories); } e.preventDefault(); }
بنابراین ثابتی به نام newItem داریم که همان آیتم جدید ما است و حالا باید آن را به UI برنامه اضافه کنیم. من برای اضافه کردن آن از متد زیر استفاده می کنم:
// Add item submit const itemAddSubmit = function(e){ // Get form input from UI Controller const input = UICtrl.getItemInput(); // Check for name and calorie input if(input.name !== '' && input.calories !== ''){ // Add item const newItem = ItemCtrl.addItem(input.name, input.calories); // Add item to UI list UICtrl.addListItem(newItem); // Clear fields UICtrl.clearInput(); } e.preventDefault(); }
من در این کد از متد addListItem برای اضافه کردن آیتم به UI استفاده کرده ام و همچنین متدی به نام clearInput را نیز صدا زده ام که کارش پاک کردن فیلدهای input است (بعد از ثبت یک آیتم نمی خواهیم درون input باقی بماند). می دانید که هنوز هیچ کدام از این توابع را تعریف نکرده ایم بنابراین با تعریف addListItem در UICtrl شروع می کنیم:
// بقیه کدها // getItemInput: function(){ return { name:document.querySelector(UISelectors.itemNameInput).value, calories:document.querySelector(UISelectors.itemCaloriesInput).value } }, addListItem: function(item){ // Create li element const li = document.createElement('li'); // Add class li.className = 'collection-item'; // Add ID li.id = `item-${item.id}`; // Add HTML li.innerHTML = `<strong>${item.name}: </strong> <em>${item.calories} Calories</em> <a href="#" class="secondary-content"> <i class="edit-item fa fa-pencil"></i> </a>`; // Insert item document.querySelector(UISelectors.itemList).insertAdjacentElement('beforeend', li) }
تابع addListItem در کد بالا تعریف شده است. ما یک <li> ساخته و کلاس 'collection-item' را به آن داده ایم. سپس انتظار داریم که id عنصر به همراه خود item به ما پاس داده شود بنابراین id عنصر <li> را برابر همان id گذاشته ایم. در واقع اگر یادتان باشد هر item ما یک شیء است که خصوصیت id و name و calories را درون خودش دارد. سپس کلاس ها و ساختار این <li> را مطابق بقیه <li> ها در فایل index.html تعریف کرده ایم (innerHTML). در نهایت با استفاده از insertAdjacentElement مشخص کرده ایم که عنصر تازه ساخته شده باید beforeend (آخرین مورد) در لیست باشد و آن را وارد UI کرده ایم.
حالا می توانید به مرورگر رفته و کدها را تست کنید، با کلیک روی دکمه Add Meal هر آیتم اضافه خواهد شد اما متوجه می شوید که هیچ کدام از فیلدهای input خالی نمی شوند و هر چه تایپ کردید در آن باقی می ماند. به همین خاطر است که باید clearInput را تعریف کنیم. من clearInput را بعد از تابع addListItem اضافه می کنم:
addListItem: function(item){ // Create li element const li = document.createElement('li'); // Add class li.className = 'collection-item'; // Add ID li.id = `item-${item.id}`; // Add HTML li.innerHTML = `<strong>${item.name}: </strong> <em>${item.calories} Calories</em> <a href="#" class="secondary-content"> <i class="edit-item fa fa-pencil"></i> </a>`; // Insert item document.querySelector(UISelectors.itemList).insertAdjacentElement('beforeend', li) }, clearInput: function(){ document.querySelector(UISelectors.itemNameInput).value = ''; document.querySelector(UISelectors.itemCaloriesInput).value = ''; },
از آنجایی که فقط دو input داریم، باید آن دو را خالی کنیم که با قرار دادن Value روی یک رشته خالی انجام می شود و کار سختی نیست. حالا می توانیم آیتم های پیش فرضی که درون کدها نوشته بودیم را کامنت کنیم:
// 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 }
از این لحظه به بعد باید خودمان آیتم ها را اضافه کنیم و اگر صفحه را refresh کنید هیچ آیتم پیش فرضی نخواهیم داشت. حتی اگر خودتان آیتمی را اضافه کنید اما صفحه را refresh کنید، آن آیتم از بین می رود. چرا؟ به دلیل اینکه هنوز آیتم ها را وارد local storage نکرده ایم.
نکته بعدی اینجاست که اگر صفحه را refresh کنید تا هیچ آیتمی نداشته باشید و سپس کدهای HTML مرورگر را نگاه کنید، به <ul> برمی خورید. یعنی با اینکه هیچ آیتمی وجود ندارد اما <ul> را داریم! من نمی خواهم این اتفاق بیفتد بنابراین در همان کنترلر UI، متد دیگری به نام hideList تعریف می کنم:
// بقیه کدها // clearInput: function(){ document.querySelector(UISelectors.itemNameInput).value = ''; document.querySelector(UISelectors.itemCaloriesInput).value = ''; }, hideList: function(){ document.querySelector(UISelectors.itemList).style.display = 'none'; }, getSelectors: function(){ return UISelectors; } } })();
این کار با استفاده از خصوصیت display در CSS به راحتی قابل انجام است بنابراین از همین راه ساده و none کردن Display توانسته ایم <ul> را حذف کنیم. اما به نظر شما باید در چه قسمتی از برنامه آن را صدا بزنیم؟ اگر یادتان باشد تابع init در همان ابتدای بارگذاری برنامه به شکل زیر اجرا می شد:
// بقیه کدها // // Public methods return { init: function(){ // Fetch items from data structure const items = ItemCtrl.getItems(); // Populate list with items UICtrl.populateItemList(items); // Load event listeners loadEventListeners(); } } })(ItemCtrl, UICtrl); // Initialize App App.init();
بنابراین بهترین کار این است که پس از دریافت آیتم ها (متد getItems در کد بالا) وجود آن ها را با یک شرط if ساده چک کنیم. در صورتی که آیتمی وجود نداشت می توانیم متد hideList را صدا بزنیم:
// بقیه کدها // // Public methods return { init: function(){ // Fetch items from data structure const items = ItemCtrl.getItems(); // Check if any items if(items.length === 0){ UICtrl.hideList(); } else { // Populate list with items UICtrl.populateItemList(items); } // Load event listeners loadEventListeners(); } } })(ItemCtrl, UICtrl); // Initialize App App.init();
به عبارت ساده تر اگر آیتمی وجود داشت با استفاده از متد populateItemList درون <ul> قرار می گیرد و اگر آیتمی وجود نداشت، خود <ul> خالی را از نظر کاربر مخفی می کنیم تا فضا را بیهوده اشغال نکند. در حال حاضر برنامه ما مشکلی دارد. آیا می توانید مشکل را حدس بزنید؟
فرض کنید برنامه برای اولین بار اجرا شود. در بار اول هیچ آیتمی وجود ندارد بنابراین hideList صدا زده شده و <ul> ما مخفی می شود. سپس کاربر یک آیتم جدید را اضافه می کند اما <ul> دیگر هیچ گاه از حالت مخفی خارج نمی شود بنابراین هیچ آیتمی برای کاربر نمایش داده نمی شود. متوجه مشکل شدید؟ برای حل این مشکل باید به تابع addListItem برویم (در کنترلر UI) و <ul> را به حالت قبلی برگردانیم:
addListItem: function(item){ // Show the list document.querySelector(UISelectors.itemList).style.display = 'block'; // Create li element const li = document.createElement('li'); // Add class li.className = 'collection-item'; // Add ID li.id = `item-${item.id}`; // Add HTML li.innerHTML = `<strong>${item.name}: </strong> <em>${item.calories} Calories</em> <a href="#" class="secondary-content"> <i class="edit-item fa fa-pencil"></i> </a>`; // Insert item document.querySelector(UISelectors.itemList).insertAdjacentElement('beforeend', li) }
با block کردن حالت display می توانیم دوباره آن را نمایش بدهیم.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.