KnockoutJS - 将对象推入可观察数组不是数据绑定

时间:2014-08-11 15:09:27

标签: knockout.js knockout-mapping-plugin

我的视图模型是一个带场景的游戏,每个场景都有一些消息。

视图模型是一个普通的JSON对象,映射为使用映射插件可观察。整个应用程序工作正常,所有数据绑定和其他功能正在接受。但...

我使用拖放操作将消息添加到场景中,以便我在侧面呈现空消息(不包含在场景消息数组中,但作为独立对象)并且在删除时拖动消息我把它推到了场景消息可观察数组中,当我查看我的游戏对象时,我可以看到添加了一条新消息,但是在ui中没有效果,让假设我们从数组中的2条消息开始,它们在应用程序的加载中呈现得很好,现在我在数组中有3条消息,但只有2条显示在ui中。

以下是一些代码:

这是拖放代码 -

(function () {
        var _dragged;
        ko.bindingHandlers.drag = {
            init: function (element, valueAccessor, allBindingsAccessor, viewModel) {
                var dragElement = $(element);
                var dragOptions = {
                    helper: 'clone',
                    appendTo: 'body',
                    revert: true,
                    revertDuration: 0,
                    start: function () {
                        _dragged = ko.utils.unwrapObservable(valueAccessor().value);
                    },
                    cursor: 'default'
                };
                dragElement.draggable(dragOptions).disableSelection();
            }
        };

        ko.bindingHandlers.drop = {
            init: function (element, valueAccessor, allBindingsAccessor, viewModel) {
                var dropElement = $(element);
                var dropOptions = {
                    drop: function (event, ui) {
                        valueAccessor().value.push(ko.mapping.fromJS(_dragged));
                    }
                };
                dropElement.droppable(dropOptions);
            }
        };
    })();

这些消息预先绑定了drop -

<div id="sceneMessages" data-bind="foreach: game.ContentScenes()[0].ContentMessages(), drop: { value: game.ContentScenes()[0].ContentMessages() }">
    <span data-bind="text: id"></span>
    <br />
</div>

这是带有拖动的空白新消息 -

<ul data-bind="foreach: messagesTypes">
    <li data-bind="text: MessageType.name, drag: { value: $data }"></li>
</ul>

知道我在做什么吗?可能是因为映射插件?!正如我所提到的,新消息正确地添加到数组中。

修改

实际上,我已经意识到,即使是没有拖放的简单推送也不会被接受。

来自服务器的JSON看起来像这样:

"ContentScenes": [
{
  "ContentMessages": [
    {
      "PrivateMessageType": null,
      "MessageType": {
        "id": 1,
        "name": "Public"
      },
      "id": 7,
      "scene_id": 3,
      "parent_id": null,
      "time_offset": null,
      "from": null,
      "to": null,
      "msg_type": 1,
      "is_system": true
    },
    {
      "PrivateMessageType": null,
      "MessageType": {
        "id": 1,
        "name": "Public"
      },
      "id": 8,
      "scene_id": 3,
      "parent_id": null,
      "time_offset": null,
      "from": null,
      "to": null,
      "msg_type": 1,
      "is_system": true
    }
  ],
  "ContentResources": [],
  "id": 3,
  "game_id": 28,
  "name": null,
  "discussion_duration": null,
  "break_duration": null,
  "vote_duration": null,
  "is_template": true
},
{
  "ContentDilemmaOptions": [],
  "ContentMessages": [],
  "ContentResources": [],
  "id": 4,
  "game_id": 28,
  "name": null,
  "discussion_duration": null,
  "break_duration": null,
  "vote_duration": null,
  "is_template": false
}
],
"id": 28,
"mainImage": null,
"sideImage": null,
"description": "Game description",
"name": "Game Name",
"locale": null

这个JSON映射如下:

 var Scene = function (data){
        ko.mapping.fromJS(data,{},this);
        this.isCurrent = function(){
            return pageOptions.queryString("scene") == this.id();
        };
        this.url = function(){
            return _url + this.id();
        };
    }

 var mappingOptions = {
        'ContentScenes':{
            create:function(options){
                return new Scene(options.data);
            }
        },
        'ContentCharacters': {
            key: function(data) {
                return ko.utils.unwrapObservable(data.id);
            }
        }
    }

 var _gameJson = {

        game: ko.mapping.fromJS(_jsonObject,mappingOptions)
 }

  ko.applyBindings(_gameJson);

那么,知道我做什么了吗?

2 个答案:

答案 0 :(得分:1)

好吧,谢谢KnockoutJS的“方便”语法让我花了一些时间才注意到它

以下是documentation的引用:

  

语法更方便。要调用KO的推送方法,只需写   myObservableArray.push(...)。这比打电话要好一点   底层数组的push方法通过编写   myObservableArray()。推(...)。

这意味着当你想要一个对象添加到数组时,你不能以正常和直观的方式通过读取对象获取数组并按下它来推送它: myArray() .push(obj),你应该得到可观察对象并推送到这样的对象: myArray .push(obj)。太棒了!

答案 1 :(得分:0)

因此,当您初始化拖动时,您只是在加载时评估世界状态,而不是在更新元素时​​...例如,这是我实施的方法

ko.bindingHandlers.DragEmployee = {
    update: function (element, valueAccessor) {
        var dragElement = $(element);
        if (valueAccessor()) {

            dragElement.toggleClass('draggable', true);
            dragElement.kendoDraggable({
                hint: function(e) {
                    return $("<label class='grabbedObject' style='font-weight: bold;'>" + $(e).text() + "</label>");
                },
                cursorOffset: { top: -4, left: -20 },
                dragstart: function(e) { $(e.currentTarget).kendoAddClass('grabbed'); },
                dragend: function (e) { $(e.currentTarget).kendoRemoveClass('grabbed'); }
            });
        } else {
            if (dragElement.data('kendoDraggable')) {
                dragElement.toggleClass('draggable', false);
                dragElement.data('kendoDraggable').destroy();
            }
        }
    }

};

效果很好......但是我使用的是剑道的拖拽功能......但它确实不应该那么重要。我将drop方法仅保留在init中,但是我传递给它的值是事件的属性...在我的情况下::

$(e.draggable.element[0])

然后,当我想获取绑定到此元素的数据时

ko.dataFor(e.draggable.element[0])

Boom ......然后我可以访问我绑定的整个模型。