Прошел год с тех пор, как наша команда занималась разработкой веб-портала с использованием паттерна MVVM и фреймворка Knockout в частности.
Понемногу накапливался опыт, появлялись различные решения, хорошие и плохие практики, и теперь, так сказать, созрело.
Библиотека для синтаксиса linq в javascript уже есть, linq.js, и мы долго думали, стоит ли привносить ее в наш проект. И даже примеры использования вместе с нокаутом в интернете Есть .
Идея, которая пришла мне в голову, заключалась в том, чтобы инкапсулировать создание вычисляемых внутри методов Linq. Для сравнения код из скрипки:
и код, который я хотел бы написать вместо этого:this.filteredItems = ko.computed(function() { var term = this.searchTerm(); return this.items.where(function(item) { return item.name.indexOf(term) > -1; }); }, this);
this.filteredItems = this.items
.
Where(function(item) { return item.name.indexOf(this.searchTerm()) > -1; });
После описанной выше инкапсуляции вычислений выяснилось, что библиотека linq.js на самом деле не нужна.
В нокаут встроено достаточно инструментов.
Более того, вам нужно написать их всего один раз, и никакой разницы снаружи не будет, даже если это самый прямой и простой цикл for.
Итак, сначала подготавливаем объект с методами: var methods = {
First: function(predicate) {
return ko.computed(function() {
return ko.utils.arrayFirst(this(), predicate);
}, this, { deferEvaluation: true });
},
Select: function(func) {
return ko.computed(function() {
return ko.utils.arrayMap(this(), function(item) {
return ko.utils.unwrapObservable(func(item));
});
}, this, { deferEvaluation: true });
},
SelectMany: function(func) {
return ko.computed(function() {
var result = [];
ko.utils.arrayForEach(this(), function(item) {
result = result.concat(ko.utils.unwrapObservable(func(item)));
});
return result;
}, this, { deferEvaluation: true });
},
Where: function(predicate) {
return ko.computed(function() {
return ko.utils.arrayFilter(this(), predicate);
}, this, { deferEvaluation: true });
},
Distinct: function(func) {
if (!func) {
return this.DistinctValue();
}
return ko.computed(function() {
var obj = {};
return ko.utils.arrayFilter(this(), function(item) {
var val = ko.utils.unwrapObservable(func(item));
return obj[val] ? false : (obj[val] = true);
});
}, this, { deferEvaluation: true });
},
DistinctValue: function() {
return ko.computed(function() {
var obj = {};
return ko.utils.arrayFilter(this(), function(val) {
return obj[val] ? false : (obj[val] = true);
});
}, this, { deferEvaluation: true });
},
Sum: function(func) {
return func ? this.Select(func).
Sum() : this.SumValue(); }, SumValue: function() { return ko.computed(function() { var result = 0; ko.utils.arrayForEach(this(), function(item) { result = result + (+item); }); return result; }, this, { deferEvaluation: true }); }, StringJoin: function(joinString) { joinString = joinString || ', '; return ko.computed(function() { return this().
join(joinString);
}, this, { deferEvaluation: true });
},
};
Второй шаг — назначить методы obsrvableArray и вычислить: for (var i in methods) {
ko.observableArray.fn[i] = methods[i];
ko.computed.fn[i] = methods[i];
}
Блюдо готово, давайте его использовать.
Примеры: self.DistinctEntities = policy.Coverages
.
SelectMany(function(item) { return item.Entities; }) .
Distinct(function(item) { return item.Name; }); self.EmployeeCount = policy.CoveredTotalCurrentYear .
Sum(function (item) { return item.Quantity; }); self.LineOfCoverageColumnName = policy.Coverages .
Select(function (item) { return item.LineOfCoverage.ShortDisplayName; }) .
StringJoin();
И для начала метод Map, аналогичный методу Select, но для сложных/затратных операций, в частности, когда для каждой модели данных во входном массиве нужно создать модель представления в выходном массиве.
При добавлении элемента во входной массив операция Select повторно вызовет лямбду для всех элементов массива, а операция Map сделает это только для вновь добавленного элемента: Map: function (converter) {
var oldValues = [];
var oldResults = [];
return ko.computed(function() {
var values = this().
slice();
var results = [];
ko.utils.arrayForEach(values, function(item) {
var index = oldValues.indexOf(item);
results.push(index > -1 ? oldResults[index] : converter(item));
});
oldValues = values;
oldResults = results;
return results;
}, this, { deferEvaluation: true });
},
Использование: self.Coverages = policy.Coverages.Map(function(coverage) { return new coverageViewModel(coverage); });
PS Список методов пока не охватывает весь набор LinQ, но расширить его несложно.
Теги: #js #LINQ #knockout #JavaScript #.
NET
-
От Идеи До Реализации. Часть Первая – Провал
19 Oct, 24 -
Скорость Флешек (Usb-Флешка)
19 Oct, 24 -
Softkey Пришел В Молдову
19 Oct, 24