在 Knockout.js 中从模型内部加载可观察量

Load observables from inside a model in Knockout.js

我有一个非常简单的项目视图模型。有一个用于编辑项目的点击处理程序,它应该将项目数据从服务器加载到模型中。单击处理程序称为 editProject。我想要的只是从服务器加载我的 observables。这种来自模型内部的方法不起作用。

this.editProject = function(){
    $.getJSON("/projects/get_by_id", {
        id: "7"
    }).done(function(data){
        ko.mapping.fromJSON(data[0], self);
    });
};

我不确定哪里出了问题,因为您没有显示您的视图或整个视图模型。在调用 editProject 之前,您如何初始化视图模型?

这是一个在实际 project 之上的层中使用 editProject 方法的示例。

  • 每个项目都有自己的视图模型,通过调用 ko.mapping.toJS 普通对象(来自服务器)创建
  • 初始对象已具有所有属性,但有些没有值。
  • 在 ajax 请求的成功回调中,通过将其作为第二个参数传递来更新单击的项目:ko.mapping.fromJS(data, project)

如果 data 包含新属性,这些属性在 ko.applyBindings 时将不可用,因此不会被数据绑定。

const $ = fakeJQuery();

// The project should have its own viewmodel with initial data
// probably received from the server during first load
const myProjects =[
  ko.mapping.fromJS({ id: "1", additionalInfo: null }),
  ko.mapping.fromJS({ id: "7", additionalInfo: null })
];

const ViewModel = function() {
  this.projects = ko.observableArray(
    myProjects
  );

  // Take the project to edit as an argument
  this.editProject = function(project) {
    $.getJSON("/projects/get_by_id", project)
      .done(function(data) {
        // Because we have access to the clicked project,
        // we map to its existing viewmodel using `fromJS`
        ko.mapping.fromJS(data, project);
      });
  };
};

ko.applyBindings(new ViewModel());

// Mocks
function fakeJQuery() {
  return {
    // Mock ajax request
    getJSON: function(url, opts) {
      let done = () => true;

      setTimeout(function() {
        // Test data to indicate an update:
        done({
          id: opts.id(),
          additionalInfo: "Test " + opts.id()
        });
      }, 1000);

      return {
        done: cb => done = cb
      };
    }
  };
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.4.1/knockout.mapping.min.js"></script>

<ul data-bind="foreach: projects">
  <li>
    <code data-bind="text: 'id: ' + id()"></code>
    <button data-bind="click: $parent.editProject">edit</button>

    <p>
      Info:
      <strong data-bind="text: additionalInfo"></strong>
      <em data-bind="visible: !additionalInfo()">not loaded</em>
    </p>
  </li>
</ul>