Я знаю, что с помощью примеров List.js почти тривиально создать список с возможностью поиска через List.js.С помощью некоторых дополнительных усилий вы можете добавить нумерацию страниц в списки.Тем не менее, нет никакого способа настроить пейджеры.Кроме того, данные, которые передаются в список со стороны JavaScript, выглядят немного ... статично.
Мои бизнес-требования следующие:
inстраница «Редактировать меню», категории и элементы могут быть добавлены в меню.Для этого пользователь нажимает кнопку «Добавить категорию» или «Добавить элемент», и появляется соответствующий модальный
пользователь не должен видеть, в этом модальном, категории, которые уже существуют наменю, а также любые элементы, которые уже находятся в той категории, в которой они находятся (например, если Category1 содержит ItemA, ItemB, ... ItemK, то, когда Category1 активна, ни один из этих элементов не должен появиться в модальном состоянии. Однако, если Category2пусто, и они нажимают на него, затем на модал, затем они все должны появиться.)
Эти требования уже выполнены, но, благодаря возможности появления буквально тысяч предметовв модальном режиме мне теперь поручено разбивать на страницы модалы и соответствующим образом обновлять стратегию фильтрации.
Вот IIFE, которое служит в качестве состояния меню (в котором все действует и использует (я включаю весь код так, чтобыпредоставить средства добавления / удаления категорий / элементов в / из их состояния):
/* all the categories, items, and modifiers that power this page */
const menuState = (function() {
class MenuData {
constructor(attached = [], available = []) {
// attached,available MUST be arrays!
if ((!Array.isArray(attached)) || (!Array.isArray(available))) {
throw TypeError("passed data MUST be in the form of Arrays!")
}
this.attached = attached;
this.available = available;
}
add(entities) {
// entities MUST be Array
if (!Array.isArray(entities)) throw ReferenceError("entities must be array")
// from here, we simply move from this.available to this.attached, the entities
// but first, let's check if they're even available
if (hasEntities(entities, this.available)) {
// attach them
this.attached = this.attached.concat(entities)
// they are no longer available
this.available= this.available
.filter(excluderFactory(entities))
}
// if they're not attached, that is an error
if (!hasEntities(entities, this.attached)) {
throw Error('The entities you were trying to add were neither attached nor available')
}
}
remove(entities) {
// entities MUST be Array
if (!Array.isArray(entities)) throw ReferenceError("entities must be array")
// from here, we simply move from this.attached to this.available, the entities
// but first, let's check if they're even attached
if (hasEntities(entities, this.attached)) {
// make them available
this.available = this.available.concat(entities)
// detach them
this.attached = this.attached
.filter(excluderFactory(entities))
}
// if they're not available, that is an error
if (!hasEntities(entities, this.available)) {
throw Error('The entities you were trying to remove were neither attached nor available')
}
}
};
let _categories = new MenuData(),
_items = new MenuData()
let _itemPool = [],
_categoryItems = {}
/**
* Determines if an array has entities with an Id.
* @param {Object[]} entities
* @param {Object[]} arrayToCheck
* @returns {boolean} whether arrayToCheck has objects with entities' Ids.
*/
function hasEntities(entities, arrayToCheck) {
for (let idx in entities) {
if (arrayToCheck.find((element) => element.Id === entities[idx].Id)) {
if (idx == entities.length - 1) {
return true;
}
continue;
}
return false;
}
}
/**
* Returns a callback for the purpose of excluding entities
* @param {Object[]} entities the entities to exclude
*/
function excluderFactory(entities) {
return function(model) {
return !entities.find((entity) => entity.Id === model.Id)
}
}
return {
getAllCategories : () => _categories.attached.concat(_categories.available),
getAttachedCategories : () => _categories.attached.slice(),
getAvailableCategories : () => _categories.available.slice(),
addCategories : (categories) => {
_categories.add(categories)
},
removeCategories : (categories) => {
_categories.remove(categories)
},
/**
* Updates the _items to the category.
* @param {Object} category the category object to update to. MUST HAVE ID!
*/
changeCurrentCategory : function(category) {
if (category.Id === undefined) {
throw ReferenceError("Category MUST have Id!")
}
_items = _categoryItems[category.Id]
},
// because _items can be reset to reference other states, we MUST
// directly reference it in these public methods
getAllItems : () => _items.attached.concat(_items.available).slice(),
getAttachedItems : () => _items.attached.slice(),
getAvailableItems : () => _items.available.slice(),
addItems : function(entities) {
return _items.add(entities)
},
removeItems : function(entities) {
return _items.remove(entities)
},
/**
* initializes the item pool of the menu state.
* All category-item states are constructed from the item pool.
*
* @param {Object[]} items
*/
initItemPool : (items) => {
if (!Array.isArray(items)) {
throw TypeError("item pool can only be initialized with an Array.")
}
// if _itemPool already has data, we're done here
if (_itemPool.length) {
throw Error("item pool is already initialized!")
}
_itemPool = items
},
getItemPool : () => _itemPool.slice(),
initCategories : (categories) => {
if (!Array.isArray(categories)) {
throw TypeError("categories can only be initialized with an Array.")
}
// if _categories already has data, we're done here
if ((_categories.attached.length) || (_categories.available.length)) {
throw Error("categories is already initialized!")
}
_categories = new MenuData([], categories)
},
/**
* Creates an entry in the category items object
* @param {number} categoryId : the ID of the category containing these items
* @param {Object[]} categoryItems : the category items. These are assumed attached to a category
*/
addCategoryItems : function(categoryId, categoryItems) {
categoryId = parseInt(categoryId) || 0
// if there is entry for categoryId already
if (_categoryItems[categoryId]) {
// throw an error
throw Error(`There already exists data for category with ID ${categoryId} !`)
}
// make the "complement" of categoryItems, using _itemPool
let availableItems = _itemPool.filter(excluderFactory(categoryItems))
// write categoryItems,availableItems to key categoryId of _categoryItems
_categoryItems[categoryId] = new MenuData(categoryItems,
availableItems)
},
getCategoryItems : () => _categoryItems
}
})()
Согласно первой ссылке, есть способпередать объект в API List.js.Однако, поскольку JavaScript не передается по ссылке, мне нужно, чтобы каким-то образом List.js вызывал правильные методы для получения правильных данных для списка, а именно getAvailableItems
, getAvailableCategories
для выбора элементов и категории-селектор модалов соответственно.
Есть ли способ заставить List.js сделать это (я не могу найти пример в любом месте )?