Если вы хорошо смыслите в KnockoutJS и JavaScript не проходите мимо!, нам нужны ваши знания.
Новичок, не пропусти. В комментариях к этому посту будут советы о том, как правильно писать на KnockoutJS.
Есть: фильтрация списка с сохранением состояния фильтров в Cookie.
Ищем: Лучшие практики KnockoutJS, чтобы не плодить плохой код.
Предостережение: редко пишу статьи, из-за чего оформление страдает. Не пугайтесь. Присылайте ошибки и рекомендации по оформлению в личку. Спасибо.
Скриншот
Исходные коды
Фильтр
<div class="filter-list">
<div class="filter">
<label for="filter_ended"><input type="checkbox" data-bind="checked: filterEnded" id="filter_ended" /> Закончившиеся</label>
</div>
<div class="filter">
<label for="filter_simple"><input type="checkbox" data-bind="checked: isSimpleView" id="filter_simple"/>
Упрощенный вид</label>
</div>
<div class="filter">
<label for="filter_sort_date"><input type="radio" data-bind="checked: sorting" id="filter_sort_date" value="date"/> По дате добавления</label>
</div>
<div class="filter">
<label for="filter_sort_abc"><input type="radio" data-bind="checked: sorting" id="filter_sort_abc" value="asc" /> По алфавиту</label>
</div>
</div>
View
<div class="items" data-bind="foreach: filteredItems, css: {items_simple: isSimpleView}">
<div class="item" data-bind="text: name, css: {item_is_ended: is_ended}"></div>
</div>
Данные
$items_json = json_encode( array(
array(
'name' => 'Ван-Пис',
'is_ended' => false,
'order_date' => 1
),
array(
'name' => 'Наруто',
'is_ended' => false,
'order_date' => 2
),
array(
'name' => 'Радость рыбалки',
'is_ended' => true,
'order_date' => 3
),
array(
'name' => 'GTO',
'is_ended' => true,
'order_date' => 4
),
))
Подключаемый JS (перед закрывающим body
)
<script type="text/javascript" src="/assets/js/cookie.js"></script>
<script type="text/javascript" src="/assets/js/libs/knockout-2.1.0.js"></script>
<script type="text/javascript">
var data_items = <?= $items_json ?>;
</script>
<script type="text/javascript" src="/assets/js/filters.ko.js"></script>
ViewModel (filters.ko.js
)
(function () {
var getParamBool = function (paramName) {
return !!((getCookie(paramName) === 'true'));
};
var getParam = function (paramName, defaultValue) {
return getCookie(paramName) ? getCookie(paramName) : defaultValue;
};
var viewModel = {
items: ko.observableArray(data_items),
filterEnded: ko.observable(getParamBool('filterEnded')),
isSimpleView: ko.observable(getParamBool('isSimpleView')),
sorting: ko.observable(getParam('sorting', 'date')),
sortTypes: {
'asc': function (left, right) {
return left.name === right.name ? 0 : (left.name < right.name ? -1 : 1)
},
'date': function (left, right) {
return left.order_date === right.order_date ? 0 : (left.order_date < right.order_date ? -1 : 1)
}
},
sortProcesssing: function (sortType) {
sortType = sortType || this.sorting();
if (this.sortTypes[sortType]) {
setCookie('sorting', sortType, 30);
this.items.sort(this.sortTypes[sortType]);
}
}
};
viewModel.filteredItems = ko.computed(function () {
var onlyEnded = this.filterEnded();
if (onlyEnded)
return ko.utils.arrayFilter(this.items(), function (item) {
return item.is_ended == onlyEnded;
});
else
return this.items();
}, viewModel);
viewModel.sorting.subscribe(function (sortType) {
viewModel.sortProcesssing(sortType);
});
viewModel.filterEnded.subscribe(function (newValue) {
setCookie('filterEnded', newValue, 30);
});
viewModel.isSimpleView.subscribe(function (newValue) {
setCookie('isSimpleView', newValue, 30);
});
viewModel.sortProcesssing();
ko.applyBindings(viewModel);
})();
Материалы по теме
- Отслеживание изменений
Observable
- Работа с формами: привязка
checked
кcheckbox
иradio
- Утилита
arrayFilter
, как и где стоит её применять - Манипуляции над
observableArray
Мастера, как же сделать код ещё лучше?
UPD: код обновлен.
По совету xdenser
- Код
filters.ko.js
завернут вself-invoking
функцию. Это оставит пространство имен в чистоте. - Сортировки сгруппированы под одним объектом
sortTypes
По совету mac2000 и xdenser параметрам даны более логичные имена, которые лучше отображают их суть.
Автор: aTei