Knockoutjs 嵌套 ViewModel / 组件与打字稿的绑定不起作用

Knockoutjs nested ViewModel / component binding with typescript doesn't work

我一直在努力尝试让 viewModel 中的 viewModel 在 knockout 中工作。任何帮助将非常感激。我正在使用打字稿并想要一个地址控件列表,每个控件都有自己的视图模型。

该项目仅使用一个地址控件即可完美运行,但是当将控件添加到父容器视图模型并使用组件时,子视图模型始终为空(即 {},如下面的警报语句所示):

这是我的 app.ts,完整代码在 https://github.com/richbeales/knockout-test

///<reference path="../node_modules/retyped-knockout-tsd-ambient/knockout.d.ts"/>

import * as ko from 'knockout';
import {AddressViewModel, Address} from './components/paf-widget';

ko.components.register('paf-address', {
    viewModel: AddressViewModel, // { require: 'components/paf-widget' },
    template: { require: 'text!components/paf-widget.html' }
});

class AddressesViewModel {
    addressList: KnockoutObservableArray<AddressViewModel>;

    constructor() {
        this.addressList = ko.observableArray<AddressViewModel>();
    }

    addAddress = function () {
        alert(ko.toJSON(this)); // returns {"addressList":[{}]}

        var childVm = new AddressViewModel();
        alert(ko.toJSON(childVm)); // returns {}
        childVm.chosenAddress(new Address());
        childVm.chosenAddress().Organisation = "Test";
        alert(ko.toJSON(childVm)); // returns {}

        var a = new Address();
        a.AddressLine1 = "The Street";
        alert(ko.toJSON(a)); // returns {"AddressLine1":"The Street"}

        this.addressList.push(childVm);
    }
}

var vm = new AddressesViewModel();
ko.applyBindings(vm);

这是我的 index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Bootstrap with jQuery and KnockoutJS</title>
    <link rel="stylesheet"
          href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha.6/css/bootstrap.min.css"/>
    <link rel="stylesheet" href="css/style.css"/>
</head>
<body>

<header>

</header>

<h1>App</h1>

Choose an Address
 <pre data-bind="text: ko.toJSON(addressList, null, 2)"></pre>

<ul data-bind="foreach: {data: addressList, as: 'addrVm'}" style="list-style: none;">
    <li class="addressli">
        <pre data-bind="text: ko.toJSON(addrVm, null, 2)"></pre>
        <div data-bind="component: {name: 'paf-address', with: addrVm }"></div>
    </li>
</ul>
<button class="btn btn-primary" data-bind="click: addAddress">Add an address</button>

<footer>

</footer>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha.6/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.1/knockout-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.2/require.min.js" data-main="js/app"></script>
<script src="require-config.js"></script>
</body>
</html>

你遇到这个奇怪的问题是因为你多次加载 knockout 并且不一致。

第一次直接在你的index.html然后用require.js在你的app.js。因此,您的 AddressViewModel 使用与 AddressesViewModel 不同的 ko 实例,这就是您看到这些奇怪的空对象的原因。

最简单的修复方法是删除 index.html:

中对 KO 的直接引用
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.1/knockout-min.js"></script>

并在您的 paf-widget.ts 中正确包含淘汰赛,其中:

import * as ko from 'knockout';

注意:更改后请确保您的浏览器缓存已清除并正确获取新代码。