Skip to content

Commit b362334

Browse files
committed
Fix view mode rendering of select2Many/selectMany #256
1 parent 34ffb7c commit b362334

File tree

3 files changed

+32
-8
lines changed

3 files changed

+32
-8
lines changed

grails-app/assets/javascripts/forms-knockout-bindings.js

+15
Original file line numberDiff line numberDiff line change
@@ -1146,6 +1146,21 @@
11461146
ecodata.forms.OutputListSupport.apply(target, [options.metadata, options.constructorFunction, options.context, options.userAddedRows, options.config]);
11471147
};
11481148

1149+
/**
1150+
* The role of this extender is to provide a function the view model can use to render a list of
1151+
* values selected using a multi select component (select2Many / selectMany) that have also used a
1152+
* label/value configuration for the options.
1153+
* @param target the observable.
1154+
* @param options unused
1155+
*/
1156+
ko.extenders.toReadOnlyString = function(target, options) {
1157+
target.toReadOnlyString = function() {
1158+
var values = ko.utils.unwrapObservable(target);
1159+
var labels = target.constraints && _.isFunction(target.constraints.label) ? _.map(values, target.constraints.label) : values;
1160+
return labels.join(', ');
1161+
}
1162+
}
1163+
11491164
/**
11501165
* This is kind of a hack to make the closure config object available to the any components that use the model.
11511166
*/

grails-app/taglib/au/org/ala/ecodata/forms/ModelJSTagLib.groovy

+2-1
Original file line numberDiff line numberDiff line change
@@ -732,7 +732,8 @@ class ModelJSTagLib {
732732
}
733733

734734
def stringListViewModel(JSModelRenderContext ctx) {
735-
observableArray(ctx)
735+
String extender = '{toReadOnlyString:true}'
736+
observableArray(ctx, [extender])
736737
}
737738

738739
def setViewModel(JSModelRenderContext ctx) {

src/main/groovy/au/org/ala/ecodata/forms/ViewModelWidgetRenderer.groovy

+15-7
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,23 @@ class ViewModelWidgetRenderer implements ModelWidgetRenderer {
7272
context.writer << "<span ${context.attributes.toString()} data-bind='${context.databindAttrs.toString()}'></span>"
7373
}
7474

75+
/**
76+
* The binding looks for the toReadOnlyString function because there exist some misconfigurations that
77+
* use a "text" data model item with a selectMany/select2Many view. This is a workaround to prevent exceptions.
78+
*/
79+
private static String selectManyBindingString(WidgetRenderContext context) {
80+
'_.isFunction(('+context.source+' || []).toReadOnlyString) ? '+ context.source+'.toReadOnlyString() : ('+context.source+'() || []).join(", ")'
81+
}
82+
7583
@Override
7684
void renderSelectMany(WidgetRenderContext context) {
77-
context.databindAttrs.add 'text', '('+context.source+'() || []).join(", ")'
85+
context.databindAttrs.add 'text',selectManyBindingString(context)
86+
context.writer << "<span ${context.attributes.toString()} data-bind='${context.databindAttrs.toString()}'></span>"
87+
}
88+
89+
@Override
90+
void renderSelect2Many(WidgetRenderContext context) {
91+
context.databindAttrs.add 'text', selectManyBindingString(context)
7892
context.writer << "<span ${context.attributes.toString()} data-bind='${context.databindAttrs.toString()}'></span>"
7993
}
8094

@@ -195,12 +209,6 @@ class ViewModelWidgetRenderer implements ModelWidgetRenderer {
195209
context.writer << """\$<span data-bind='${context.databindAttrs.toString()}'></span>.00"""
196210
}
197211

198-
@Override
199-
void renderSelect2Many(WidgetRenderContext context) {
200-
context.databindAttrs.add 'text', '('+context.source+'() || []).join(", ")'
201-
context.writer << "<span ${context.attributes.toString()} data-bind='${context.databindAttrs.toString()}'></span>"
202-
}
203-
204212
@Override
205213
void renderMultiInput(WidgetRenderContext context) {
206214
context.databindAttrs.add 'text', '('+context.source+'() || []).join(", ")'

0 commit comments

Comments
 (0)