Skip to content

Commit c761430

Browse files
committed
Fixed initialisation of key/value constraint exclusion #177
1 parent 4cb9efe commit c761430

File tree

2 files changed

+49
-40
lines changed

2 files changed

+49
-40
lines changed

grails-app/assets/javascripts/forms.js

+38-26
Original file line numberDiff line numberDiff line change
@@ -666,27 +666,20 @@ function orEmptyArray(v) {
666666
};
667667

668668
};
669-
670669
function applyIncludeExclude(metadata, outputModel, dataModelItem, initialConstraints) {
671670
var path = metadata.constraints.excludePath || metadata.constraints.includePath;
672671

673672
var currentValue = dataModelItem();
674-
var selectedSoFar = [];
675-
outputModel.eachValueForPath(path, function (val) {
676-
if (_.isArray(val)) {
677-
selectedSoFar = selectedSoFar.concat(val);
678-
} else if (val != null) {
679-
selectedSoFar.push(val);
680-
}
681-
});
673+
var selectedSoFar = outputModel.getModelValuesForPath(path);
682674

683675
if (metadata.constraints.excludePath) {
684676
var filteredConstraints = _.filter(initialConstraints, function (value) {
685677
// Handle object valued constraints - however the functions are attached after the first call to
686678
// the computed observable, so we need to guard against that.
687-
value = _.isFunction(dataModelItem.constraints.value) ? dataModelItem.constraints.value(value) : value;
679+
value = _.isFunction(dataModelItem.constraintValue) ? dataModelItem.constraintValue(value) : value;
688680
var isCurrentSelection = _.isArray(currentValue) ? currentValue.indexOf(value) >= 0 : value == currentValue;
689-
return (isCurrentSelection || selectedSoFar.indexOf(value) < 0);
681+
var include = (isCurrentSelection || selectedSoFar.indexOf(value) < 0);
682+
return include;
690683
});
691684
return filteredConstraints;
692685
} else {
@@ -703,9 +696,7 @@ function orEmptyArray(v) {
703696

704697
return constraints;
705698
}
706-
707699
}
708-
709700
/**
710701
* Implements the constraints specified on a single data model item using the "constraints" attribute in the metadata.
711702
* Also provides access to global configuration and context for components that need it.
@@ -780,7 +771,20 @@ function orEmptyArray(v) {
780771
valueProperty = metadata.constraints.valueProperty || valueProperty;
781772
textProperty = metadata.constraints.textProperty || textProperty;
782773
}
783-
774+
// These need to be defined before the computed constraint is defined to support correct evaluation
775+
// of the excludePath function.
776+
self.constraintValue = function (constraint) {
777+
if (_.isObject(constraint)) {
778+
return constraint[valueProperty];
779+
}
780+
return constraint;
781+
};
782+
self.constraintText = function(constraint) {
783+
if (_.isObject(constraint)) {
784+
return constraint[textProperty];
785+
}
786+
return constraint;
787+
};
784788
self.constraints = [];
785789
var includeExcludeDefined = metadata.constraints.excludePath || metadata.constraints.includePath;
786790
// Support existing configuration style.
@@ -835,18 +839,8 @@ function orEmptyArray(v) {
835839
}
836840
}
837841

838-
self.constraints.value = function (constraint) {
839-
if (_.isObject(constraint)) {
840-
return constraint[valueProperty];
841-
}
842-
return constraint;
843-
};
844-
self.constraints.text = function (constraint) {
845-
if (_.isObject(constraint)) {
846-
return constraint[textProperty];
847-
}
848-
return constraint;
849-
};
842+
self.constraints.value = self.constraintValue;
843+
self.constraints.text = self.constraintText;
850844
self.constraints.label = function(value) {
851845

852846
if (!value && ko.isObservable(self)) {
@@ -1272,6 +1266,24 @@ function orEmptyArray(v) {
12721266
self.iterateOverPath(pathAsArray, callback, self.data);
12731267
}
12741268

1269+
/**
1270+
* Iterates over every instance of the DataModelItem defined by path and returns an array containing
1271+
* the values found at each item.
1272+
* @param path the path to the data model item of interest (e.g. list.nestedList.textValue1)
1273+
* @returns {*[]}
1274+
*/
1275+
self.getModelValuesForPath = function(path) {
1276+
var values = [];
1277+
self.eachValueForPath(path, function (val) {
1278+
if (_.isArray(val)) {
1279+
values = values.concat(val);
1280+
} else if (val != null) {
1281+
values.push(val);
1282+
}
1283+
});
1284+
return values;
1285+
}
1286+
12751287
/**
12761288
* Recursively iterates over each element in the supplied pathAsArray, taking into
12771289
* account when values are lists.

src/test/js/spec/DataModelItemSpec.js

+11-14
Original file line numberDiff line numberDiff line change
@@ -148,11 +148,9 @@ describe("DataModelItem Spec", function () {
148148

149149
var invokedWithPath;
150150
var vals = ['1', '3'];
151-
var customContext = _.extend({}, context, {outputModel: { eachValueForPath: function(path, callback) {
151+
var customContext = _.extend({}, context, {outputModel: { getModelValuesForPath: function(path) {
152152
invokedWithPath = path;
153-
for (var i=0; i<vals.length; i++) {
154-
callback(vals[i]);
155-
}
153+
return _.flatten(vals);
156154
}}});
157155

158156
var dataItem = ko.observable().extend({metadata:{metadata:metadata, context:customContext, config:config}});
@@ -165,6 +163,12 @@ describe("DataModelItem Spec", function () {
165163
vals = [['1', '2'], ['3']];
166164
dataItem = ko.observableArray().extend({metadata:{metadata:metadata, context:customContext, config:config}});
167165
expect(dataItem.constraints()).toEqual(['4']);
166+
167+
168+
vals = ['v1'];
169+
metadata.constraints.default = [{text:'t1', id:'v1'}, {text:'t2', id:'v2'}];
170+
dataItem = ko.observableArray().extend({metadata:{metadata:metadata, context:customContext, config:config}});
171+
expect(dataItem.constraints()).toEqual([{text:'t2', id:'v2'}]);
168172
});
169173

170174

@@ -182,11 +186,10 @@ describe("DataModelItem Spec", function () {
182186

183187
var invokedWithPath;
184188
var vals = ['1', '3'];
185-
var customContext = _.extend({}, context, {outputModel: { eachValueForPath: function(path, callback) {
189+
var customContext = _.extend({}, context, {outputModel: { getModelValuesForPath: function(path) {
186190
invokedWithPath = path;
187-
for (var i=0; i<vals.length; i++) {
188-
callback(vals[i]);
189-
}
191+
console.log(_.flatten(vals));
192+
return _.flatten(vals);
190193
}}});
191194

192195
var dataItem = ko.observable().extend({metadata:{metadata:metadata, context:customContext, config:config}});
@@ -199,11 +202,5 @@ describe("DataModelItem Spec", function () {
199202
vals = [['1', '2'], ['3']];
200203
dataItem = ko.observableArray().extend({metadata:{metadata:metadata, context:customContext, config:config}});
201204
expect(dataItem.constraints()).toEqual(['1', '2', '3']);
202-
203-
vals = ['v1'];
204-
metadata.constraints.default = [{text:'t1', value:'v1'}, {text:'t2', value:'v2'}];
205-
dataItem = ko.observableArray().extend({metadata:{metadata:metadata, context:customContext, config:config}});
206-
expect(dataItem.constraints()).toEqual(['v2']);
207-
208205
});
209206
});

0 commit comments

Comments
 (0)