Knockout.js:重新选择对数组元素的更改的问题

时间:2013-05-03 15:16:56

标签: twitter-bootstrap knockout.js

我正在努力制作一个基于淘汰赛的应用程序,我遇到了一个看似无法解决的问题:我正在制作一个用于操作事件对象列表的UI。事件对象列表显示在主视图中,其中包含一个事件对象表,其中包含一些可在主视图中更改的属性。

但是因为事件对象将包含复杂数据,如子数组等,我希望能够从事件对象列表中打开模态视图,以便对单个事件对象进行详细编辑。模态视图从与主视图相同的页面内部运行,因此我可以为两个视图使用相同的数据模型。

我能够在模态视图中编辑单个事件对象中的属性,但由于某种原因,更改不会反映在主视图中。当我迭代事件数组时,我可以看到有问题的数组元素已被更改。我尝试在数组上执行valueHasMutated方法(这是一个可观察的数组),但这没有任何效果。希望在这里有一些好的建议。我试图编译一个自包含的HTML页面,它比文字更好地解释了问题。但我担心代码有点长。但无论如何它在这里:                        淘汰赛测试                            

<form id="photograph-form">
    <div class="row-fluid span12">
        <h4>Events</h4>
        <table class="table table-condensed table-hover span11 table-striped">
            <thead>
            <tr>
                <th class="span1">Delete</th><th class="span1">Edit</th><th class="span1">Type</th><th class="span1">Dating basis</th>
            </tr>
            </thead>
            <!-- Todo: Generate table body -->
            <tbody data-bind="foreach: events">
            <tr>
                <td><a href="#" data-bind="click: $root.removeEvent"><i
                        class="icon-trash"></i></a></td>
                <td><a data-bind="click: $root.setCurrentEvent" href="#eventView" role="button"
                       data-toggle="modal">
                    <i class="icon-edit"></i></a></td>

                <td><select class="input-medium" data-bind="value: event_type,
                                   options: event_types,
                                   optionsValue: 'identifier',
                                   optionsText: 'name'"></select></td>
                <td><input class="input-medium" data-bind="value: foundation"/>
                </td>
            </tr>
            </tbody>
        </table>
    </div>
</form>
<p>Current item foundation: <span data-bind="text: currentEvent().foundation"></span></p>

<div class="row-fluid">
    <!-- Button to trigger modal -->
    <a role="button" class="btn" data-toggle="modal" href="#eventView" data-bind="click: $root.addEvent">New</a>
</div>

<!-- Modal window -->
<div id="eventView" class="modal hide fade" tabindex="-1" role="dialog"
     aria-labelledby="eventLabel" aria-hidden="true">
    <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal"
                aria-hidden="true">×
        </button>
        <h3 id="eventLabel">Event</h3>
    </div>
    <div class="modal-body">
        <label for="eventType">Event type</label>

        <select id="eventType" class="input-medium" data-bind="value: currentEvent().event_type,
                                   options: event_types,
                                   optionsValue: 'identifier',
                                   optionsText: 'name'"></select>
        <label for="eventFoundation">Dating basis</label>
        <input id="eventFoundation" class="input-medium"
               data-bind="value: currentEvent().foundation"/>

    </div>
    <div class="modal-footer">
        <button class="btn btn-primary" data-dismiss="modal"
                aria-hidden="true" data-bind="click: $root.updateEvent">OK
        </button>
    </div>
</div>

<script src="js/jquery.js"></script>
<script src="js/bootstrap.min.js"></script>
<script src="js/knockout.js"></script>

<script>
    var event_types = [
        { identifier: "accession", name: "Accession" },
        { identifier: "other", name: "Other" },
        { identifier: "ownership", name: "Ownership" }
    ];

    var model = new ArtifactModel("photograph");
    model.history_description = ko.observable();
    model.events = ko.observableArray([
        { event_type: "accession", foundation: "Found"},
        { event_type: "ownership", foundation: "Museum"}
    ]);
    model.currentEvent = ko.observable({ event_type: "accession", foundation: "Found"});

    ko.applyBindings(model);


    function ArtifactModel(artifact_type) {
        var self = this;
        self.artifact_id = ko.observable();
        self.events = ko.observableArray();
        self.currentEvent = ko.observable();

        // Operations
        self.addEvent = function () {
            self.events.push({
                event_type: "",
                foundation: ""
            });
            self.currentEvent(self.events()[self.events().length - 1]);
        };

        self.setCurrentEvent = function(event) {
            self.currentEvent(event);
            console.log("Before: Event.foundation: " + self.currentEvent().foundation);
        };

        self.updateEvent = function(event) {
            for (var t = 0 ; t < event.events().length ; t++) {
                console.log("After: Event.foundation: " + event.events()[t].foundation);
            }
            event.events.valueHasMutated(); // No effect!
        }
    }
</script>
</body>
</html>

2 个答案:

答案 0 :(得分:0)

问题可能是因为您的event对象本身没有可观察的属性。尝试将事件定义更改为以下内容:

{
    event_type: ko.observable("accession"),
    foundation: ko.observable("Found")
}

您可能需要进行一些其他更改以解释这些属性现在可以观察到的事实,但这意味着从一个位置对对象所做的更改将反映在其他位置。

答案 1 :(得分:0)

您需要拥有的是具有可观察值的对象数组。那你就不需要做任何额外的事了。

如果您要在http://jsfiddle.net/

中进行演示,将会很有帮助