If one modifies the String array from ko.computed, the value is propagated back to Java model. MutableArrays
authorJaroslav Tulach <jtulach@netbeans.org>
Tue, 26 Aug 2014 17:30:45 +0200
branchMutableArrays
changeset 82471625816f1c6
parent 823 57ad1f8ee35a
child 825 0ff870db0f5c
If one modifies the String array from ko.computed, the value is propagated back to Java model.
json-tck/src/main/java/net/java/html/json/tests/KnockoutTest.java
json-tck/src/main/java/net/java/html/json/tests/Utils.java
json/src/main/java/org/apidesign/html/json/spi/Proto.java
json/src/main/java/org/netbeans/html/json/impl/ModelProcessor.java
     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