【问题标题】:Parse json string into knockout observables将 json 字符串解析为淘汰赛 observables
【发布时间】:2017-07-04 04:38:51
【问题描述】:

我从 REST 端点得到以下响应,我需要用这些值填充字典。 json 看起来像这样: {"name":"A", "id:"A", "properties":{"description":"A", "text":"A", "number":"one" }} 最终,我会得到这个 json 对象的数组。

我在我的 ajax 成功回调中尝试了以下操作:

    console.log(result)
        for (x in result){
            console.log(result[x])
            if (x  === 'object'){
                for (y in x){
                    console.log(x[y]);
                }
            }
        }

这真的不是我想要的。如果用户选择名称,我需要能够将属性值加载到剔除变量中。

【问题讨论】:

标签: javascript json knockout.js


【解决方案1】:

我认为你的问题有两个方面:

  • 将数据从 json 字符串转换为 视图模型
  • 管理 UI 并确保它可以处理(外部)数据更改而不会丢失状态

将 json 转换为视图模型

这可以自动完成(例如,通过评论中链接的 ko-mapping 插件)或手动完成。我赞成手动映射。基础:

  1. 解析 JSON。

    例如:从'{ "name": "A" }'{ name: "A" }

  2. 通过prototypeobservablecomputed 属性添加功能。

    例如:从{ name: "A" }{ name: ko.observable("A"), index: 0, /* ... */ }

管理状态和外部数据更改

创建视图模型数组后,您需要一个地方来管理选择。基础:

this.items = ko.observableArray([ { name: "A" }, { name: "B" } ]);
this.selection = ko.observable(items[0]);

您可以将项目和选择数据绑定到您的 UI。例如,使用<select> 元素:

<select data-bind="options: items, optionsText: 'name', value: selection></select>

这完成了链:json > array of objects > array of viewmodels + selected viewmodel reference

现在,唯一的挑战是确保您可以从服务器重新加载数据而不会丢失选择。为此,您可以将update 方法添加到设置可观察属性的视图模型中,或者替换所有视图模型并存储选定的id 而不是对对象的引用。

一个例子:

var createItem = function (obj) {
  // Up to you how you map to "viewmodels", 
  // If you want two-way binding (for editing),
  // wrap in an observable.
  // Example for 1-way binding
  return Object.assign({
    name: obj.name,
    id: obj.id,
    randomNr: Math.random()
  }, Object.keys(obj.properties).reduce(function(res, key) {
    res[key] = obj.properties[key];
    return res;
  }, {}));
};

var VM = function() {
  this.rawData = ko.observableArray([]);

  // Create "item" view models from the array of objects
  this.items = ko.pureComputed(function() {
    return this.rawData().map(createItem);
  }, this);
  
  // Store items by `id` prop. (Could also be a plain object)
  var itemMap = ko.pureComputed(function() {
    return new Map(
      this.items().map(function(item) {
        return [item.id, item];
      })
    );
  }, this);
  
  // Store the id of the selected item
  this.selectedId = ko.observable(null);
  
  // Whenever either the selected id, _or_ the  array of items changes,
  // update the selected item
  this.selectedItem = ko.pureComputed(function() {
    return itemMap().get(this.selectedId());
  }, this);
  
};

VM.prototype.loadData = function(json) {
  // Hardcoded
  json = '[{"name":"A", "id":"A", "properties":{"description":"A", "text":"A", "number":"one"}}, {"name":"B", "id":"B", "properties":{"description":"B", "text":"B", "number":"two"}},{"name":"C", "id":"C", "properties":{"description":"C", "text":"C", "number":"three"}}]';
  
  // Might want to wrap in a try catch
  this.rawData(JSON.parse(json));
}

var vm = new VM();
ko.applyBindings(vm);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>


<select data-bind="options: items, 
                   optionsText: 'name', 
                   optionsValue: 'id',
                   value: selectedId"></select>

<p>Your selection:<p>
<div data-bind="with: selectedItem">
  <h3>Name: <span data-bind="text: name"></span></h3>
  <h4>Description:<span data-bind="text: description + randomNr"></span></h4>
  <p>Nr:<span data-bind="text: number"></span></p>
</div>
<button data-bind="click: loadData">load data</button>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-04-10
    • 1970-01-01
    • 1970-01-01
    • 2013-06-07
    • 2012-06-06
    • 2016-09-03
    • 1970-01-01
    • 2013-10-21
    相关资源
    最近更新 更多