If one modifies the String array from ko.computed, the value is propagated back to Java model.
1.1 --- a/json-tck/src/main/java/net/java/html/json/tests/KnockoutTest.java Sat Aug 23 22:55:00 2014 +0200
1.2 +++ b/json-tck/src/main/java/net/java/html/json/tests/KnockoutTest.java Tue Aug 26 17:30:45 2014 +0200
1.3 @@ -569,6 +569,38 @@
1.4 assert first.getSex() == Sex.FEMALE : "Transverted to female: " + first.getSex();
1.5 }
1.6
1.7 + @KOTest public void stringArrayModificationVisible() throws Exception {
1.8 + Object exp = Utils.exposeHTML(KnockoutTest.class,
1.9 + "<div>\n"
1.10 + + "<ul id='ul' data-bind='foreach: results'>\n"
1.11 + + " <li data-bind='text: $data'></li>\n"
1.12 + + "</ul>\n"
1.13 + + "</div>\n"
1.14 + );
1.15 + try {
1.16 + KnockoutModel m = Models.bind(new KnockoutModel(), newContext());
1.17 + m.getResults().add("Ahoj");
1.18 + m.getResults().add("Hello");
1.19 + m.applyBindings();
1.20 +
1.21 + int cnt = Utils.countChildren(KnockoutTest.class, "ul");
1.22 + assert cnt == 2 : "Two children " + cnt;
1.23 +
1.24 + Object arr = Utils.addChildren(KnockoutTest.class, "ul", "Hi");
1.25 + assert arr instanceof Object[] : "Got back an array: " + arr;
1.26 + final int len = ((Object[])arr).length;
1.27 +
1.28 + assert len == 3 : "Three elements in the array " + len;
1.29 +
1.30 + int newCnt = Utils.countChildren(KnockoutTest.class, "ul");
1.31 + assert newCnt == 3 : "Three children in the DOM: " + newCnt;
1.32 +
1.33 + assert m.getResults().size() == 3 : "Three java strings: " + m.getResults();
1.34 + } finally {
1.35 + Utils.exposeHTML(KnockoutTest.class, "");
1.36 + }
1.37 + }
1.38 +
1.39 @Function
1.40 static void call(KnockoutModel m, String data) {
1.41 m.setName(data);
2.1 --- a/json-tck/src/main/java/net/java/html/json/tests/Utils.java Sat Aug 23 22:55:00 2014 +0200
2.2 +++ b/json-tck/src/main/java/net/java/html/json/tests/Utils.java Tue Aug 26 17:30:45 2014 +0200
2.3 @@ -139,6 +139,21 @@
2.4 , id
2.5 )).intValue();
2.6 }
2.7 +
2.8 + static Object addChildren(Class<?> caller, String id, Object value) throws Exception {
2.9 + return executeScript(caller,
2.10 + "var e = window.document.getElementById(arguments[0]);\n" +
2.11 + "var v = arguments[1];\n" +
2.12 + "if (typeof e === 'undefined') return -2;\n " +
2.13 + "var c = ko.contextFor(e);\n" +
2.14 + "var fn = c.$rawData.results;\n" +
2.15 + "var arr = c.$rawData.results();\n" +
2.16 + "arr.push(v);\n" +
2.17 + "fn(arr);\n" +
2.18 + "return arr;\n"
2.19 + , id, value
2.20 + );
2.21 + }
2.22
2.23 static String prepareURL(
2.24 Class<?> clazz, String content, String mimeType, String... parameters) {
3.1 --- a/json/src/main/java/org/apidesign/html/json/spi/Proto.java Sat Aug 23 22:55:00 2014 +0200
3.2 +++ b/json/src/main/java/org/apidesign/html/json/spi/Proto.java Tue Aug 26 17:30:45 2014 +0200
3.3 @@ -806,5 +806,29 @@
3.4 return type.cast(val);
3.5 }
3.6
3.7 + /** Special dealing with array & {@link List} values. This method
3.8 + * takes the provided collection, empties it and fills it again
3.9 + * with values extracted from <code>value</code> (which is supposed
3.10 + * to be an array).
3.11 + *
3.12 + * @param <T> the type of list elements
3.13 + * @param arr collection to fill with elements in value
3.14 + * @param type the type of elements in the collection
3.15 + * @param value array of elements to put into the collecition. If
3.16 + * value is not an array it is wrapped into array with only element
3.17 + * @since 1.0
3.18 + */
3.19 + public final <T> void replaceValue(Collection<? super T> arr, Class<T> type, Object value) {
3.20 + Object[] newArr;
3.21 + if (value instanceof Object[]) {
3.22 + newArr = (Object[]) value;
3.23 + } else {
3.24 + newArr = new Object[] { value };
3.25 + }
3.26 + arr.clear();
3.27 + for (Object e : newArr) {
3.28 + arr.add(extractValue(type, e));
3.29 + }
3.30 + }
3.31 }
3.32 }
4.1 --- a/json/src/main/java/org/netbeans/html/json/impl/ModelProcessor.java Sat Aug 23 22:55:00 2014 +0200
4.2 +++ b/json/src/main/java/org/netbeans/html/json/impl/ModelProcessor.java Tue Aug 26 17:30:45 2014 +0200
4.3 @@ -316,7 +316,7 @@
4.4 {
4.5 for (int i = 0; i < propsGetSet.size(); i++) {
4.6 w.append(" registerProperty(\"").append(propsGetSet.get(i).name).append("\", ");
4.7 - w.append((i) + ", " + (propsGetSet.get(i).setter == null) + ");\n");
4.8 + w.append((i) + ", " + propsGetSet.get(i).readOnly + ");\n");
4.9 }
4.10 }
4.11 {
4.12 @@ -329,17 +329,25 @@
4.13 w.append(" @Override public void setValue(" + className + " data, int type, Object value) {\n");
4.14 w.append(" switch (type) {\n");
4.15 for (int i = 0; i < propsGetSet.size(); i++) {
4.16 - final String set = propsGetSet.get(i).setter;
4.17 - String tn = propsGetSet.get(i).type;
4.18 + final GetSet pgs = propsGetSet.get(i);
4.19 + if (pgs.readOnly) {
4.20 + continue;
4.21 + }
4.22 + final String set = pgs.setter;
4.23 + String tn = pgs.type;
4.24 String btn = findBoxedType(tn);
4.25 if (btn != null) {
4.26 tn = btn;
4.27 }
4.28 - if (set != null) {
4.29 - w.append(" case " + i + ": data." + strip(set) + "(TYPE.extractValue(" + tn + ".class, value)); return;\n");
4.30 + w.append(" case " + i + ": ");
4.31 + if (pgs.setter != null) {
4.32 + w.append("data.").append(strip(pgs.setter)).append("(TYPE.extractValue(" + tn + ".class, value)); return;\n");
4.33 + } else {
4.34 + w.append("TYPE.replaceValue(data.").append(strip(pgs.getter)).append("(), " + tn + ".class, value); return;\n");
4.35 }
4.36 }
4.37 w.append(" }\n");
4.38 + w.append(" throw new UnsupportedOperationException();\n");
4.39 w.append(" }\n");
4.40 w.append(" @Override public Object getValue(" + className + " data, int type) {\n");
4.41 w.append(" switch (type) {\n");
4.42 @@ -591,7 +599,8 @@
4.43 p.name(),
4.44 gs[2],
4.45 gs[3],
4.46 - castTo
4.47 + tn,
4.48 + gs[3] == null && !p.array()
4.49 ));
4.50 }
4.51 return ok;
4.52 @@ -714,7 +723,8 @@
4.53 e.getSimpleName().toString(),
4.54 gs[2],
4.55 null,
4.56 - tn
4.57 + tn,
4.58 + true
4.59 ));
4.60 }
4.61
4.62 @@ -1821,11 +1831,13 @@
4.63 final String getter;
4.64 final String setter;
4.65 final String type;
4.66 - GetSet(String name, String getter, String setter, String type) {
4.67 + final boolean readOnly;
4.68 + GetSet(String name, String getter, String setter, String type, boolean readOnly) {
4.69 this.name = name;
4.70 this.getter = getter;
4.71 this.setter = setter;
4.72 this.type = type;
4.73 + this.readOnly = readOnly;
4.74 }
4.75 }
4.76