diff --git a/grails-app/assets/javascripts/forms-knockout-bindings.js b/grails-app/assets/javascripts/forms-knockout-bindings.js
index 027d107..b27ffa2 100644
--- a/grails-app/assets/javascripts/forms-knockout-bindings.js
+++ b/grails-app/assets/javascripts/forms-knockout-bindings.js
@@ -1146,6 +1146,21 @@
ecodata.forms.OutputListSupport.apply(target, [options.metadata, options.constructorFunction, options.context, options.userAddedRows, options.config]);
};
+ /**
+ * The role of this extender is to provide a function the view model can use to render a list of
+ * values selected using a multi select component (select2Many / selectMany) that have also used a
+ * label/value configuration for the options.
+ * @param target the observable.
+ * @param options unused
+ */
+ ko.extenders.toReadOnlyString = function(target, options) {
+ target.toReadOnlyString = function() {
+ var values = ko.utils.unwrapObservable(target);
+ var labels = target.constraints && _.isFunction(target.constraints.label) ? _.map(values, target.constraints.label) : values;
+ return labels.join(', ');
+ }
+ }
+
/**
* This is kind of a hack to make the closure config object available to the any components that use the model.
*/
diff --git a/grails-app/taglib/au/org/ala/ecodata/forms/ModelJSTagLib.groovy b/grails-app/taglib/au/org/ala/ecodata/forms/ModelJSTagLib.groovy
index 52ea12a..bc31395 100644
--- a/grails-app/taglib/au/org/ala/ecodata/forms/ModelJSTagLib.groovy
+++ b/grails-app/taglib/au/org/ala/ecodata/forms/ModelJSTagLib.groovy
@@ -732,7 +732,8 @@ class ModelJSTagLib {
}
def stringListViewModel(JSModelRenderContext ctx) {
- observableArray(ctx)
+ String extender = '{toReadOnlyString:true}'
+ observableArray(ctx, [extender])
}
def setViewModel(JSModelRenderContext ctx) {
diff --git a/src/main/groovy/au/org/ala/ecodata/forms/ViewModelWidgetRenderer.groovy b/src/main/groovy/au/org/ala/ecodata/forms/ViewModelWidgetRenderer.groovy
index f8cfd00..2f7ac82 100644
--- a/src/main/groovy/au/org/ala/ecodata/forms/ViewModelWidgetRenderer.groovy
+++ b/src/main/groovy/au/org/ala/ecodata/forms/ViewModelWidgetRenderer.groovy
@@ -72,9 +72,23 @@ class ViewModelWidgetRenderer implements ModelWidgetRenderer {
context.writer << ""
}
+ /**
+ * The binding looks for the toReadOnlyString function because there exist some misconfigurations that
+ * use a "text" data model item with a selectMany/select2Many view. This is a workaround to prevent exceptions.
+ */
+ private static String selectManyBindingString(WidgetRenderContext context) {
+ '_.isFunction(('+context.source+' || []).toReadOnlyString) ? '+ context.source+'.toReadOnlyString() : ('+context.source+'() || []).join(", ")'
+ }
+
@Override
void renderSelectMany(WidgetRenderContext context) {
- context.databindAttrs.add 'text', '('+context.source+'() || []).join(", ")'
+ context.databindAttrs.add 'text',selectManyBindingString(context)
+ context.writer << ""
+ }
+
+ @Override
+ void renderSelect2Many(WidgetRenderContext context) {
+ context.databindAttrs.add 'text', selectManyBindingString(context)
context.writer << ""
}
@@ -195,12 +209,6 @@ class ViewModelWidgetRenderer implements ModelWidgetRenderer {
context.writer << """\$.00"""
}
- @Override
- void renderSelect2Many(WidgetRenderContext context) {
- context.databindAttrs.add 'text', '('+context.source+'() || []).join(", ")'
- context.writer << ""
- }
-
@Override
void renderMultiInput(WidgetRenderContext context) {
context.databindAttrs.add 'text', '('+context.source+'() || []).join(", ")'