【问题标题】:Knockout nested foreach add and remove not working淘汰赛嵌套的foreach添加和删除不起作用
【发布时间】:2015-04-13 02:26:05
【问题描述】:

在嵌套的 foreach 中添加和删除时遇到问题。在这个例子中,我们有一个有很多房间的房子。每个房间都有许多家具。到目前为止,使用此代码,我可以正确显示数据并可以添加和删除房间,但我无法添加或删除家具。

HTML

//Other House fields work as expected above this section

<div data-bind='foreach: rooms'>
    <button type="button" data-bind='visible: $root.rooms().length > 1, click: $root.removeRoom'> Remove Room </button>

    <p> Room Name</p>
    <input type="text" data-bind="value: name"></input>

    //with: appears to work the same as a foreach -- neither seem to work
    <div data-bind="with: furnitures">
        <button type="button" data-bind='click: $root.rooms().furnitures().removeFurniture'> Remove Furniture </button>
        <p> Furniture Name</p>
        <input type="text" data-bind="value: name"></input>
    </div>
    <button type="button" data-bind='click: $root.rooms().furnitures().addFurniture'> Add Furniture </button>
</div>   

<button type="button" data-bind='click: $root.addRoom'> Add Room </button> 

JavaScript

var HouseModel = function(rooms) {

    var self = this;
    self.rooms = ko.observableArray(rooms);

    // Not sure what to put here for Furniture because each room array item has an array of many furnitures

    // ROOM MANAGEMENT ==========================
    self.addRoom = function() {
        self.rooms.push({
            name:"",
            furnitures[]: ""
        });
    };

    self.removeRoom = function(room) {
        self.rooms.remove(room);
    };

            // FURNITURE MANAGEMENT ==========================
            // Not sure where this goes
            self.addFurniture = function() {
                self.furnitures.push({
                    name: ""
                });
            };

            self.removeFurniture = function(furniture) {
                self.furnitures.remove(furniture);
            };
};

var viewModel = new HouseModel(rooms); // rooms are the pre-existing rooms and their furniture, in JSON format
ko.applyBindings(viewModel);

主要问题可能与按钮数据绑定的上下文以及模型的编码方式有关。有什么遗漏或错误。

感谢您的想法。

更新 这是一个问题: http://jsfiddle.net/zhLf1n61/

资源:

【问题讨论】:

  • 您能否也包括 Room 模型以及 AddFuniture 对您尝试做的事情最有意义的地方。也许即使是 jsfiddle 也是一个好主意
  • 就是这样。没有房间模型;只有House模型。所以当数据传入时,它是一个 House 对象,带有一个 Room 数组,每个 Room 都有一个 Furnitures 数组。如果您暗示应该有另一个模型(Room one),那当然是有道理的,但我的理解是,在使用 Knockout 时,每页一个模型是可取的。如果我错了,请纠正我。
  • @Max 每页有多个视图模型没有错。特别是如果这些视图模型是模块化的可重用代码。
  • @Max 我添加了按钮绑定示例。

标签: javascript html knockout.js


【解决方案1】:

更新了 javascript...

主要入口点是 HouseModel... 房屋有房间(以及删除添加它们的方法),房间有家具(带有添加和删除它们的方法)。一切都与封装和范围有关。

在这里提琴:http://jsfiddle.net/zqwom7kd/

var initialData = [{
    "name": "Living Room",
        "furnitures": [{
        "name": "Bookshelf",
            "size": "Medium"
    }]
}, {
    "name": "Bedroom",
        "furnitures": [{
        "name": "Bed",
            "size": "Large"
    }, {
        "name": "Night Table",
            "size": "Small"
    }, {
        "name": "Jacuzzi",
            "size": "Large"
    }]
}];
var Furniture = function(data) {
    var self = this;
    self.name = ko.observable('');
    self.size = ko.observable('');
    if (typeof data !== 'undefined') {
        self.name(data.name);
        self.size(data.size);
    }
}
var Room = function(name, furnitures) {
    var self = this;
    self.name = ko.observable(name);
    self.furnitures = ko.observableArray([]);
    if (typeof furnitures !== 'undefined') {
        $.each(furnitures, function(i, el) {
            self.furnitures.push(new Furniture({name: el.name, size: el.size}));
        });
    }
    self.removeFurniture = function(furniture) {
        self.furnitures.remove(furniture);
    };
    self.addFurniture = function() {
        console.log("added");
        self.furnitures.push(new Furniture({name: '', size: ''}));
    };
};

var HouseModel = function (rooms) {
    var self = this;
    self.save = function() {
        console.log("do stuff");
    };
    self.lastSavedJson = ko.observable('');
    self.rooms = ko.observableArray([]);
    if (typeof rooms !== 'undefined') {
        $.each(rooms, function(i, el) {
            self.rooms.push(new Room(el.name, el.furnitures));
        });
    }

    self.addRoom = function(name) {
        self.rooms.push(new Room(name));
    };

    self.removeRoom = function (room) {
        self.rooms.remove(room);
    };
};

ko.applyBindings(new HouseModel(initialData));

HTML

<h2>House Components</h2>

<div id='roomsList'>
    <table class='roomsEditor'>
        <tr>
            <th>Room Name</th>
            <th>Furnitures</th>
        </tr>
        <tbody data-bind="foreach: rooms">
            <tr class="well">
                <td valign="top">
                    <input type="text" data-bind='value: name' />
                    <div> <button class="btn btn-danger" data-bind='click: $root.rooms.removeRoom'>Remove Room</button>
                    </div>
                </td>
                <td>
                    <table>
                        <tbody data-bind="foreach: furnitures">
                            <tr>
                                <td>
                                    <input type="text" data-bind='value: name' />
                                </td>
                                <td>
                                    <input type="text" data-bind='value: size' />
                                </td>
                                <td>
                                    <button class="btn btn-danger" data-bind='click: $parent.removeFurniture'>Delete Furniture</button>
                                </td>
                            </tr>
                        </tbody>
                    </table>
                    <button class="btn btn-success" data-bind='click: addFurniture'>Add Furniture</button>

                </td>
            </tr>
        </tbody>
    </table>
</div>
<p>
    <button class="btn btn-success" data-bind='click: $root.rooms.addRoom'>Add Room</button>
    <button data-bind='click: save, enable: rooms().length > 0'>Save to JSON</button>
</p>
<textarea data-bind='value: lastSavedJson' rows='5' cols='60' disabled='disabled'></textarea>

【讨论】:

  • 感谢您的回答,但不幸的是这不起作用。它显示数据,但按钮不起作用。也许按钮调用上下文是错误的?我试过$root.rooms().addFurniture$data.addFurniture
  • 确实需要将房间和家具组合成不仅具有属性,而且具有功能的对象。
  • 你可能是对的。我在http://stackoverflow.com/questions/29572088/multiple-arrays-in-one-knockout-js-viewmodel/29609645#29609645 看到了你的其他帖子,一定会尝试的。
  • 是的...非常相似。重新编写上面的代码以显示另一种看起来更像这样的方法。
  • 我实施了建议,这是一个小提琴http://jsfiddle.net/zhLf1n61/。正如我对 CrimsonChris 提到的,当没有房子并且只有房间和家具时,它可以正常工作,但是一旦我尝试将房间和家具放在房子里,我就无法再操纵家具了。 @brettwgreen
【解决方案2】:

这是一个开始的地方。正如@Nathan Fisher 提到的,创建一个Room 甚至可能创建一个Furniture 类是有意义的。

HTML

<button data-bind="click: addRoom"></button>
<div data-bind='foreach: rooms'>
    <button data-bind="click: $parent.removeRoom"></button>
    <button data-bind="click: $parent.addFurnitureToRoom"></button>
    <div data-bind="foreach: furnitures">
        <button data-bind="click: $parents[1].removeFurnitureFromRoom.bind($root, $data, $parent)"></button>
    </div>
</div>   

JS

function HouseViewModel (rooms) {
    var self = this;
    this.rooms = ko.observableArray(rooms || []);

    this.addRoom = function () {
        self.rooms.push({
            name: ko.observable(''),
            furnitures: ko.observableArray(),
        });
    };

    this.removeRoom = function (room) {
        self.rooms.remove(room);
    };

    this.addFurnitureToRoom = function (room) {
        room.furnitures.push({
            name: ko.observable(''),
        });
    };

    self.removeFurnitureFromRoom = function (furniture, room) {
        room.furnitures.remove(furniture);
    };
};

【讨论】:

  • 这会起作用,但应该注意主要问题是家具需要是一个 observableArray。这就是您原来的解决方案不起作用的原因。
  • 这是我的意思。 http://jsfiddle.net/zhLf1n61/在没有房子,只有房间和家具的情况下可以正常工作,但是一旦我尝试将房间和家具放在房子里,我就无法再操作家具了
  • @Max 确保您将正确的参数传递给添加/删除家具。我已经更新了上面的绑定。
  • 请注意,这不使用 RoomsViewModel。如果您将添加/删除家具功能移动到房间中,那么绑定将需要不同。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-12-11
  • 2011-08-11
  • 2012-01-30
  • 2014-01-10
  • 1970-01-01
  • 2013-04-20
  • 2013-05-15
相关资源
最近更新 更多