92- آموزش جاوااسکریپت | پروژه عملی: قسمت 5 از 12- افزودن آیتم جدید به برنامه Calorie Tracker با Event Listener و Item Controller
در این بخش، فرایند افزودن آیتم جدید به برنامه Calorie Tracker را پیادهسازی میکنیم. ابتدا Event Listener مربوط به دکمه افزودن را میسازیم، سپس ورودیهای فرم را از UI Controller میگیریم و در نهایت آیتم جدید را در Item Controller به ساختار داده اضافه میکنیم.
در بخش قبل، آیتمها را از Item Controller دریافت کردیم و با استفاده از UI Controller آنها را در رابط کاربری نمایش دادیم.
در این بخش، هدف ما این است که امکان افزودن یک وعده غذایی جدید همراه با مقدار کالری آن را فراهم کنیم.
برای این کار، باید رویداد کلیک روی دکمه افزودن را مدیریت کنیم، دادههای فرم را بخوانیم، اعتبارسنجی اولیه انجام دهیم و در نهایت آیتم جدید را به ساختار داده اضافه کنیم.
ایجاد تابع loadEventListeners
بهتر است تمام رویدادهای برنامه را داخل یک تابع جداگانه قرار دهیم تا ساختار App Controller تمیزتر و قابلمدیریتتر باشد.
کد
// App Controller
const App = (function (ItemCtrl, UICtrl) {
// بارگذاری رویدادها
const loadEventListeners = function () {
};
return {
init: function () {
const items = ItemCtrl.getItems();
UICtrl.populateItemList(items);
loadEventListeners();
}
};
})(ItemCtrl, UICtrl);
App.init();
توضیح
در این ساختار، تمام Event Listenerها داخل تابع loadEventListeners قرار میگیرند و هنگام اجرای init فراخوانی میشوند.
دسترسی به UISelectors از داخل App Controller
از آنجا که آبجکت UISelectors داخل UI Controller تعریف شده و خصوصی است، نمیتوانیم مستقیماً از App Controller به آن دسترسی داشته باشیم.
برای حل این موضوع، یک متد عمومی به نام getSelectors ایجاد میکنیم.
کد
// UI Controller
const UICtrl = (function () {
const UISelectors = {
itemList: '#item-list'
};
return {
populateItemList: function (items) {
let html = '';
items.forEach(function (item) {
html += `
<li class="collection-item" id="item-${item.id}">
<strong>${item.name}: </strong>
<em>${item.calories} Calories</em>
<a href="#" class="secondary-content">
<i class="edit-item fa fa-pencil"></i>
</a>
</li>
`;
});
document.querySelector(UISelectors.itemList).innerHTML = html;
},
getSelectors: function () {
return UISelectors;
}
};
})();
افزودن سلکتور دکمه Add
برای ثبت رویداد کلیک روی دکمه افزودن، ابتدا باید سلکتور آن را به UISelectors اضافه کنیم.
کد
const UISelectors = {
itemList: '#item-list',
addBtn: '.add-btn'
};
توجه: مقدار کلاس باید مطابق HTML پروژه شما باشد. اگر در فایل HTML از کلاس دیگری استفاده کردهاید، همان مقدار را اینجا قرار دهید.
تعریف رویداد افزودن آیتم
حالا میتوانیم در App Controller رویداد مربوط به افزودن آیتم را ثبت کنیم.
کد
// App Controller
const App = (function (ItemCtrl, UICtrl) {
const loadEventListeners = function () {
const UISelectors = UICtrl.getSelectors();
document
.querySelector(UISelectors.addBtn)
.addEventListener('click', itemAddSubmit);
};
const itemAddSubmit = function (e) {
e.preventDefault();
};
return {
init: function () {
const items = ItemCtrl.getItems();
UICtrl.populateItemList(items);
loadEventListeners();
}
};
})(ItemCtrl, UICtrl);
App.init();
توضیح
در اینجا:
- با
UICtrl.getSelectors()به سلکتورهای رابط کاربری دسترسی پیدا میکنیم - روی دکمه
Addیک Event Listener از نوعclickثبت میکنیم - با
e.preventDefault()از رفتار پیشفرض فرم جلوگیری میکنیم
دریافت دادههای فرم از UI Controller
برای گرفتن مقدار فیلدهای فرم، بهتر است یک متد جداگانه در UI Controller تعریف کنیم.
این متد مقدار نام آیتم و کالری را برمیگرداند.
افزودن سلکتورهای فیلدهای ورودی
ابتدا باید شناسه فیلدهای فرم را به UISelectors اضافه کنیم.
کد
const UISelectors = {
itemList: '#item-list',
addBtn: '.add-btn',
itemNameInput: '#item-name',
itemCaloriesInput: '#item-calories'
};
ساخت متد getItemInput
حالا یک متد عمومی ایجاد میکنیم که ورودیهای فرم را برگرداند.
کد
// UI Controller
const UICtrl = (function () {
const UISelectors = {
itemList: '#item-list',
addBtn: '.add-btn',
itemNameInput: '#item-name',
itemCaloriesInput: '#item-calories'
};
return {
populateItemList: function (items) {
let html = '';
items.forEach(function (item) {
html += `
<li class="collection-item" id="item-${item.id}">
<strong>${item.name}: </strong>
<em>${item.calories} Calories</em>
<a href="#" class="secondary-content">
<i class="edit-item fa fa-pencil"></i>
</a>
</li>
`;
});
document.querySelector(UISelectors.itemList).innerHTML = html;
},
getItemInput: function () {
return {
name: document.querySelector(UISelectors.itemNameInput).value,
calories: document.querySelector(UISelectors.itemCaloriesInput).value
};
},
getSelectors: function () {
return UISelectors;
}
};
})();
توضیح
این متد یک آبجکت شامل دو مقدار برمیگرداند:
namecalories
به این ترتیب، منطق خواندن دادههای فرم داخل UI Controller باقی میماند.
استفاده از ورودی فرم در itemAddSubmit
حالا میتوانیم داخل تابع itemAddSubmit دادههای فرم را دریافت کنیم.
کد
const itemAddSubmit = function (e) {
const input = UICtrl.getItemInput();
console.log(input);
e.preventDefault();
};
اگر همه چیز درست باشد، با کلیک روی دکمه افزودن، آبجکتی شامل name و calories در کنسول نمایش داده میشود.
اعتبارسنجی اولیه فرم
قبل از افزودن آیتم، باید مطمئن شویم هر دو فیلد فرم مقدار دارند.
کد
const itemAddSubmit = function (e) {
const input = UICtrl.getItemInput();
if (input.name !== '' && input.calories !== '') {
console.log('Valid Input');
}
e.preventDefault();
};
توضیح
در این مرحله فقط بررسی میکنیم که هر دو فیلد خالی نباشند.
اگر هر دو مقدار داشته باشند، میتوانیم ادامه فرایند را اجرا کنیم.
ساخت متد addItem در Item Controller
اکنون باید متدی در Item Controller بسازیم که آیتم جدید را به آرایه items اضافه کند.
کد
// Item Controller
const ItemCtrl = (function () {
const Item = function (id, name, calories) {
this.id = id;
this.name = name;
this.calories = calories;
};
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
};
return {
getItems: function () {
return data.items;
},
addItem: function (name, calories) {
let id;
if (data.items.length > 0) {
id = data.items[data.items.length - 1].id + 1;
} else {
id = 0;
}
calories = parseInt(calories);
const newItem = new Item(id, name, calories);
data.items.push(newItem);
return newItem;
}
};
})();
منطق تولید id
هر آیتم باید یک شناسه یکتا داشته باشد.
برای این کار:
- اگر آرایه
itemsخالی نباشد،idآخرین آیتم را میگیریم و یک واحد به آن اضافه میکنیم - اگر آرایه خالی باشد،
idرا برابر0قرار میدهیم
کد
if (data.items.length > 0) {
id = data.items[data.items.length - 1].id + 1;
} else {
id = 0;
}
این روش یک رفتار شبیه auto-increment ایجاد میکند.
تبدیل کالری به عدد
مقدار فیلدهای فرم بهصورت رشته دریافت میشود.
اما کالری باید عدد باشد، بنابراین با parseInt آن را تبدیل میکنیم.
کد
calories = parseInt(calories);
ساخت و ذخیره آیتم جدید
بعد از آماده شدن id و calories، یک نمونه جدید از Item میسازیم و آن را به آرایه اضافه میکنیم.
کد
const newItem = new Item(id, name, calories);
data.items.push(newItem);
return newItem;
توضیح
در پایان، newItem را برمیگردانیم تا در مراحل بعد بتوانیم از آن برای بهروزرسانی رابط کاربری استفاده کنیم.
فراخوانی addItem هنگام ثبت فرم
حالا باید بعد از اعتبارسنجی، آیتم جدید را از طریق Item Controller اضافه کنیم.
کد
const itemAddSubmit = function (e) {
const input = UICtrl.getItemInput();
if (input.name !== '' && input.calories !== '') {
const newItem = ItemCtrl.addItem(input.name, input.calories);
console.log(newItem);
}
e.preventDefault();
};
توضیح
اگر فرم معتبر باشد:
nameوcaloriesبهItemCtrl.addItem()ارسال میشوند- آیتم جدید ساخته میشود
- آیتم به آرایه
itemsاضافه میشود - همان آیتم جدید در متغیر
newItemذخیره میشود
بررسی نتیجه در ساختار داده
در این مرحله، آیتم جدید به ساختار داده اضافه میشود، حتی اگر هنوز در رابط کاربری نمایش داده نشود.
برای بررسی این موضوع، میتوانید از متدی مثل logData استفاده کنید.
کد
console.log(ItemCtrl.logData());
اگر متد logData را از قبل داشته باشید، میتوانید ببینید که آیتم جدید با id مناسب و مقدار کالری عددی به آرایه اضافه شده است.
نسخه کامل کد این بخش
app.js
// Storage Controller
// Item Controller
const ItemCtrl = (function () {
const Item = function (id, name, calories) {
this.id = id;
this.name = name;
this.calories = calories;
};
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
};
return {
getItems: function () {
return data.items;
},
addItem: function (name, calories) {
let id;
if (data.items.length > 0) {
id = data.items[data.items.length - 1].id + 1;
} else {
id = 0;
}
calories = parseInt(calories);
const newItem = new Item(id, name, calories);
data.items.push(newItem);
return newItem;
}
};
})();
// UI Controller
const UICtrl = (function () {
const UISelectors = {
itemList: '#item-list',
addBtn: '.add-btn',
itemNameInput: '#item-name',
itemCaloriesInput: '#item-calories'
};
return {
populateItemList: function (items) {
let html = '';
items.forEach(function (item) {
html += `
<li class="collection-item" id="item-${item.id}">
<strong>${item.name}: </strong>
<em>${item.calories} Calories</em>
<a href="#" class="secondary-content">
<i class="edit-item fa fa-pencil"></i>
</a>
</li>
`;
});
document.querySelector(UISelectors.itemList).innerHTML = html;
},
getItemInput: function () {
return {
name: document.querySelector(UISelectors.itemNameInput).value,
calories: document.querySelector(UISelectors.itemCaloriesInput).value
};
},
getSelectors: function () {
return UISelectors;
}
};
})();
// App Controller
const App = (function (ItemCtrl, UICtrl) {
const loadEventListeners = function () {
const UISelectors = UICtrl.getSelectors();
document
.querySelector(UISelectors.addBtn)
.addEventListener('click', itemAddSubmit);
};
const itemAddSubmit = function (e) {
const input = UICtrl.getItemInput();
if (input.name !== '' && input.calories !== '') {
const newItem = ItemCtrl.addItem(input.name, input.calories);
console.log(newItem);
}
e.preventDefault();
};
return {
init: function () {
const items = ItemCtrl.getItems();
UICtrl.populateItemList(items);
loadEventListeners();
}
};
})(ItemCtrl, UICtrl);
App.init();
جمعبندی
در این بخش، امکان افزودن آیتم جدید به برنامه را از نظر منطقی پیادهسازی کردیم.
در این مرحله:
- تابع
loadEventListenersرا برای مدیریت رویدادها ساختیم - متد
getSelectorsرا برای دسترسی به سلکتورها ایجاد کردیم - ورودیهای فرم را با
getItemInputدریافت کردیم - اعتبارسنجی اولیه برای خالی نبودن فیلدها انجام دادیم
- متد
addItemرا درItem Controllerپیادهسازی کردیم - برای هر آیتم جدید
idیکتا تولید کردیم - مقدار کالری را از رشته به عدد تبدیل کردیم
- آیتم جدید را به ساختار داده اضافه کردیم
در بخش بعدی، آیتم جدید را بعد از ثبت، مستقیماً در رابط کاربری نمایش میدهیم تا فرایند افزودن آیتم کامل شود.