Search code examples
xmlbindingknockout.jsko.observablearray

How to handle unknown properties at design time in knockoutJS


I am not sure, if I ask the question properly, so I try to explain the scenario. I have the feeling that I miss something simple in handling knockout.

I read (and later write to) multiple xml files. These files have some entries that are equal and some entries that differs:

<elements>
  <id>123</id>
  <unknown>some text</unknown>
</elements>

After reading the xml files I come up with an observableArray which I can access as mentioned in most tutorials without any problem.

So in this example I have no problem to read and edit the "id", cause I know that it calls "id":

<span data-bind="text: $data.id"></span>

But there are entries in the xml that i dont know, but they are in the observableArray and I can "see" that, if I refer to $data:

<pre data-bind="text: ko.toJSON($data, null, 2)"></pre>

This shows me the unknown parts:

...
{
  "unknown": "some text"
}
...   

To edit this property I had to access them by name or is there another option? So my problem is to access this for example via:

<input data-bind="value: $data.???" />

If more information is required, please let me know.

Thanks for ideas and answers.


Solution

  • The html-markup:

    <div data-bind="foreach: $data.elemente">
      <pre data-bind="text: ko.toJSON($data)"></pre>
      <ul data-bind="foreach: $root.element">
        <div data-bind="if: $parent[$data]" >
          <label data-bind="text: $data"></label>
          <input data-bind="value: $parent[$data]" />
        </div>
      </ul>
    </div>
    

    The Javascript Code:

        // this is for "click: selected"
        this.selected = ko.observableArray();
    
        this.element = ko.computed(function () {
          if (self.selected().length === 0) {
            return [];
          }
          var bez = [];
          var obj = self.selected().elemente;
          console.log(obj);
          for (var n in obj) {
            for (var i in obj[n]) {
              bez.push(i);
            }
          }
          return bez;
        });
    

    The JsonObject which I correspond to (chrome view):

    0: Object
       elemente: Array[3]
       0: Object
          meinfeld: "feldBalue1"
          __proto__: Object
       1: Object
          feldxyz: "xyzValue"
          __proto__: Object
       2: Object
          feld123: "Top 123"
         __proto__: Object
    

    and the result in the browser:

    the result in the browser

    edit: A nice way is using a custom binding-handler:

    ko.bindingHandlers.readXml = {
      init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
        console.log(allBindings());
        var xmlElements = getValueAccessor(valueAccessor());
        ko.bindingHandlers.foreach.init(element, xmlElements, allBindings, viewModel,   bindingContext);
      return {
        controlsDescendantBindings: true
      };
    },
    update: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
      var xmlElements = getValueAccessor(valueAccessor());
      ko.bindingHandlers.foreach.update(element, xmlElements, allBindings, viewModel, bindingContext);
    }
    };