patternjavascriptMinor
Knockout.js binding 2D table with rowspan
Viewed 0 times
withknockoutbindingtablerowspan
Problem
The app I'm working on should allows it's users to create tables. I have a view in which users are able to create a table. They should be able to define here the table's columns. The columns that the user adds will be part from some predefined types of columns: BusinessFields, SourceKeys, SourceAttrs,...; At the same time columns should have some other proprieties that define the value they will contain: minlength, minValue, defaultValue,...
These tables have to have a format(at least a column for the SourceKeys and TargetKeys categories), but this format is not so restrictive. The image will help to describe the point:
I have made it work as you see in the image, but I don't like how I've made the bindings. My code design also reduces the flexibility (For example: It would be much more difficult to add a click binding for a row).
JavaScript:
```
//column definition
function Column(columnName, minLength, maxLength, minValue, maxValue, reg_ex, role, order, defaultValue) {
var self = {};
self.name = ko.observable(columnName || 'new column');
self.minLength = ko.observable(minLength || null);
self.maxLength = ko.observable(maxLength || null);
self.minValue = ko.observable(minValue || null);
self.maxValue = ko.observable(maxValue || null);
self.reg_exp = ko.observable(reg_ex || null);
self.role = ko.observable(role ? role : 1);
self.order = ko.observable(order || null);
self.defaultValue = ko.observable(defaultValue || null);
return self;
}
//table definition
function Table() {
var self = {};
self.tableName = ko.observable('New table');
self.tableDescription = ko.observable('description');
self.businessFields = ko.observableArray([]);
self.sourceKeys = ko.observableArray([]);
self.sourceAttr = ko.observableArray([]);
self.targetKeys = ko.observableArray([]);
self.targetAttr = ko.observableArray([]);
self.attrFields = ko.observableArray([]);
self.technicalFields = ko.observableArray
These tables have to have a format(at least a column for the SourceKeys and TargetKeys categories), but this format is not so restrictive. The image will help to describe the point:
I have made it work as you see in the image, but I don't like how I've made the bindings. My code design also reduces the flexibility (For example: It would be much more difficult to add a click binding for a row).
JavaScript:
```
//column definition
function Column(columnName, minLength, maxLength, minValue, maxValue, reg_ex, role, order, defaultValue) {
var self = {};
self.name = ko.observable(columnName || 'new column');
self.minLength = ko.observable(minLength || null);
self.maxLength = ko.observable(maxLength || null);
self.minValue = ko.observable(minValue || null);
self.maxValue = ko.observable(maxValue || null);
self.reg_exp = ko.observable(reg_ex || null);
self.role = ko.observable(role ? role : 1);
self.order = ko.observable(order || null);
self.defaultValue = ko.observable(defaultValue || null);
return self;
}
//table definition
function Table() {
var self = {};
self.tableName = ko.observable('New table');
self.tableDescription = ko.observable('description');
self.businessFields = ko.observableArray([]);
self.sourceKeys = ko.observableArray([]);
self.sourceAttr = ko.observableArray([]);
self.targetKeys = ko.observableArray([]);
self.targetAttr = ko.observableArray([]);
self.attrFields = ko.observableArray([]);
self.technicalFields = ko.observableArray
Solution
I would just add a
You then just have to iterate over
columnGroup attribute to Column and then do a groupBy-type operation on that attribute. That would reduce your Table view-model to just a collection of Rows, which would be nice. Here's what I'm thinking for Columnfunction Column(columnName, columnGroup /* ... all your other attributes ... */) {
var self = {};
self.name = ko.observable(columnName || 'new column');
self.groupName = ko.observable(columnGroup || 'Misc.');
/* all your other boilerplate setting */
return self;
}
// returns a group object, which has a name and an array of items.
// this will only be created once in the groups array.
function ensureGroup (groups, groupName) {
var foundGroup;
groups.some(function (group) {
if (group.name === groupName) {
return foundGroup = group;
}
});
if (!foundGroup) {
foundGroup = {
name: groupName,
items: []
};
groups.push(foundGroup);
}
return foundGroup;
}
function Table() {
var self = {};
self.tableName = ko.observable('New table');
self.tableDescription = ko.observable('description');
self.columns = ko.observableArray([]);
self.columnGroups = ko.computed(function () {
var groups = self.columns().reduce(function (groups, column) {
var group = ensureGroup(groups, column.fieldGroup();
group.items.push(column);
}, []);
return groups;
});
return self;
}You then just have to iterate over
table.columnGroups in your template. Of course, this code is untested, and there are certainly ways to clean it up more, but I wanted to give you an approach to work from.Code Snippets
function Column(columnName, columnGroup /* ... all your other attributes ... */) {
var self = {};
self.name = ko.observable(columnName || 'new column');
self.groupName = ko.observable(columnGroup || 'Misc.');
/* all your other boilerplate setting */
return self;
}
// returns a group object, which has a name and an array of items.
// this will only be created once in the groups array.
function ensureGroup (groups, groupName) {
var foundGroup;
groups.some(function (group) {
if (group.name === groupName) {
return foundGroup = group;
}
});
if (!foundGroup) {
foundGroup = {
name: groupName,
items: []
};
groups.push(foundGroup);
}
return foundGroup;
}
function Table() {
var self = {};
self.tableName = ko.observable('New table');
self.tableDescription = ko.observable('description');
self.columns = ko.observableArray([]);
self.columnGroups = ko.computed(function () {
var groups = self.columns().reduce(function (groups, column) {
var group = ensureGroup(groups, column.fieldGroup();
group.items.push(column);
}, []);
return groups;
});
return self;
}Context
StackExchange Code Review Q#40276, answer score: 5
Revisions (0)
No revisions yet.