3

変数データを内部に持つネストされたJSONオブジェクトでKnockoutのマッピングプラグインを使用しようとしています。ただし、HTMLで表示する方法がわかりません。ネストされたすべてのJSONオブジェクトを正しくマッピングし、たとえば単純な文字列として表示するにはどうすればよいですか?これが私のコードです:

JS

var ListModel = function(jsonData) {
  var self = this;
  self.master = ko.mapping.fromJS(jsonData);
}
var listModel = new ListModel(jsonData);
ko.applyBindings(listModel);

HTML

<!-- ko foreach: master -->
  <div data-bind="text: $data"></div> 
<!-- /ko -->

サンプルJSON

{"Level 1a":"Hi","Level 1b":{
  "Level 2a":"Hello","Level 2b":{
    "Level 3":"Bye"}
  }
}

サンプル出力

Hi
  Hello
    Bye

ここで私がやろうとしている主なことは、ネストされたすべてのレベルから値を出力することです。キーの値とネストされたレベルの数は完全に可変です(SOおよびオンラインで見つけたネストされたJSONの例のほとんどは固定キー用でした)。これは可能ですか?

更新:jQueryに相当するものを見つけましたが、それでもオブザーバブルのKnockout実装が必要です。

4

2 に答える 2

5

JSONオブジェクトには可変キーがあるため、最初に固定の予測可能な構造に変換する必要があります。そうしないと、ネストされたテンプレートマッピングが機能しません(ノックアウトは宣言型であるため、キー名を事前に知っておく必要があります)。

次のカスタムマッピングコードを検討してください(ノックアウトマッピングプラグインは必要ありません)。

var ListModel = function(jsonData) {
    var self = this;

    self.master = ko.observableArray([]);

    function nestedMapping(data, level) {
        var key, value, type;

        for (key in data) {
            if (data.hasOwnProperty(key)) {
                if (data[key] instanceof Object) {
                    type = "array";
                    value = ko.observableArray([]);
                    nestedMapping(data[key], value());
                } else {
                    type = "simple";
                    value = ko.observable(data[key]);
                }
                level.push({key: key, type: type, value: value});
            }
        }
    }

    nestedMapping(jsonData, self.master());
}

この関数nestedMapping()はデータ構造を変えます:

{
    "Level 1a": "Hi",
    "Level 1b": {
        "Level 2a": "Hello",
        "Level 2b": {
            "Level 3": "Bye"
        }
    }
}

の中へ:

[
    {
        "key": "Level 1a",
        "type": "simple",
        "value": "Hi"
    },
    {
        "key": "Level 1b",
        "type": "array",
        "value": [
            {
                "key": "Level 2a",
                "type": "simple",
                "value": "Hello"
            },
            {
                "key": "Level 2b",
                "type": "array",
                "value": [
                    {
                        "key": "Level 3",
                        "type": "simple",
                        "value": "Bye"
                    }
                ]
            }
        ]
    }
]

これで、次のようなテンプレートを作成できます。

<script type="text/html" id="nestedTemplate">
  <!-- ko if: type == 'simple' -->
  <div class="name" data-bind="text: value, attr: {title: key}"></div>
  <!-- /ko -->
  <!-- ko if: type == 'array' -->
  <div class="container" data-bind="
    template: {
      name: 'nestedTemplate', 
      foreach: value
    }
  "></div>
  <!-- /ko -->
</script>

それが機能していることを確認してください:http://jsfiddle.net/nwdhJ/2/

についての微妙ですが重要な点に注意してくださいnestedMapping()。ネストされたobservables/observableArraysを作成します。ただし、ネイティブ配列インスタンスで機能します(再帰に渡すことによって)self.master()value()

このようにして、オブジェクト構築中の不必要な遅延を回避します。observableArrayに値をプッシュするたびに、ノックアウト変更の追跡がトリガーされますが、それは必要ありません。ネイティブアレイでの作業はかなり高速になります。

于 2012-06-22T09:55:47.410 に答える
2

JSONデータを次のように変更します(配列に注意してください!):

[
  {
    "Text": "Hi",
    "Children": [
      {
        "Text": "Hello",
        "Children": [
          {
            "Text": "Bye"
          }
        ]
      }
    ]
  }
]

自己参照テンプレートを使用します。

<script type="text/html" id="nestedTemplate">
  <div class="name" data-bind="text: Text"></div>
  <div class="container" data-bind="
    template: {
      name: 'nestedTemplate', 
      foreach: Children
    }
  "></div>
</script>

あなたがこのように呼ぶこと:

<div class="container" data-bind="
  template: {
    name: 'nestedTemplate', 
    foreach: master
  }
"></div>

次に、CSSを使用してインデントを管理できます。

/* indent from second level only */
div.container div.container {
  margin-left: 10px;
}

jsFiddleでご覧ください:http://jsfiddle.net/nwdhJ/1/

于 2012-06-22T08:45:59.360 に答える