结合两个敲除示例

Combine two Knockout Examples

我正在尝试从 knockout.com 中获取两个示例,但我还没有弄清楚。任何帮助将不胜感激!

http://jsfiddle.net/gZC5k/2863/

当 运行 这个项目并使用调试器时,我得到一个错误: 未捕获的 ReferenceError:无法处理绑定 "foreach: function (){return linesa }" 消息:linesa 未定义

从最初的示例开始,我将 lines 更改为 linesa 以查看是否有其他问题将其搞砸了。还是不喜欢 linea

我的主要目标是让这两个示例协同工作。添加联系人按钮有效,但添加产品无效。

谢谢!

    <div class='liveExample'> 

    <h2>Contacts</h2>
    <div id='contactsList'>
        <table class='contactsEditor'>
            <tr>
                <th>First name</th>
                <th>Last name</th>
                <th>Phone numbers</th>
            </tr>
            <tbody data-bind="foreach: contactsa">
                <tr>
                    <td>
                        <input data-bind='value: firstName' />
                        <div><a href='#' data-bind='click: $root.removeContact'>Delete</a></div>
                    </td>
                    <td><input data-bind='value: lastName' /></td>
                    <td>
                        <table>
                            <tbody data-bind="foreach: phones">
                                <tr>
                                    <td><input data-bind='value: type' /></td>
                                    <td><input data-bind='value: number' /></td>
                                    <td><a href='#' data-bind='click: $root.removePhone'>Delete</a></td>
                                </tr>
                            </tbody>
                        </table>
                        <a href='#' data-bind='click: $root.addPhone'>Add number</a>
                    </td>
                </tr>
            </tbody>
        </table>
    </div>

    <p>
        <button data-bind='click: addContact'>Add a contact</button>
        <button data-bind='click: save, enable: contactsa().length > 0'>Save to JSON</button>
    </p>

    <textarea data-bind='value: lastSavedJson' rows='5' cols='60' disabled='disabled'> </textarea>

</div>

<div class='liveExample'> 

    <table width='100%'>
        <thead>
            <tr>
                <th width='25%'>Category</th>
                <th width='25%'>Product</th>
                <th class='price' width='15%'>Price</th>
                <th class='quantity' width='10%'>Quantity</th>
                <th class='price' width='15%'>Subtotal</th>
                <th width='10%'> </th>
            </tr>
        </thead>
        <tbody data-bind='foreach: linesa'>
            <tr>
                <td>
                    <select data-bind='options: sampleProductCategories, optionsText: "name", optionsCaption: "Select...", value: category'> </select>
                </td>
                <td data-bind="with: category">
                    <select data-bind='options: products, optionsText: "name", optionsCaption: "Select...", value: $parent.product'> </select>
                </td>
                <td class='price' data-bind='with: product'>
                    <span data-bind='text: formatCurrency(price)'> </span>
                </td>
                <td class='quantity'>
                    <input data-bind='visible: product, value: quantity, valueUpdate: "afterkeydown"' />
                </td>
                <td class='price'>
                    <span data-bind='visible: product, text: formatCurrency(subtotal())' > </span>
                </td>
                <td>
                    <a href='#' data-bind='click: $parent.removeLine'>Remove</a>
                </td>
            </tr>
        </tbody>
    </table>
    <p class='grandTotal'>
        Total value: <span data-bind='text: formatCurrency(grandTotal())'> </span>
    </p>
    <button data-bind='click: addLine'>Add product</button>
    <button data-bind='click: save'>Submit order</button>

</div>

    var initialData = [
    { firstName: "Danny", lastName: "LaRusso", phones: [
        { type: "Mobile", number: "(555) 121-2121" },
        { type: "Home", number: "(555) 123-4567"}]
    },
    { firstName: "Sensei", lastName: "Miyagi", phones: [
        { type: "Mobile", number: "(555) 444-2222" },
        { type: "Home", number: "(555) 999-1212"}]
    }
];

var ContactsModel = function(contactstest) {
    var self = this;
    self.contactsa = ko.observableArray(ko.utils.arrayMap(contactstest, function(contact) {
        return { firstName: contact.firstName, lastName: contact.lastName, phones: ko.observableArray(contact.phones) };
    }));

    self.addContact = function() {
        self.contactsa.push({
            firstName: "",
            lastName: "",
            phones: ko.observableArray()
        });
    };

    self.removeContact = function(contact) {
        self.contactsa.remove(contact);
    };

    self.addPhone = function(contact) {
        contact.phones.push({
            type: "",
            number: ""
        });
    };

    self.removePhone = function(phone) {
        $.each(self.contactsa(), function() { this.phones.remove(phone) })
    };

    self.save = function() {
        self.lastSavedJson(JSON.stringify(ko.toJS(self.contactsa), null, 2));
    };

    self.lastSavedJson = ko.observable("")
};

ko.applyBindings(new ContactsModel(initialData));

function formatCurrency(value) {
    return "$" + value.toFixed(2);
}

var CartLine = function() {
    var self = this;
    self.category = ko.observable();
    self.product = ko.observable();
    self.quantity = ko.observable(1);
    self.subtotal = ko.computed(function() {
        return self.product() ? self.product().price * parseInt("0" + self.quantity(), 10) : 0;
    });

    // Whenever the category changes, reset the product selection
    self.category.subscribe(function() {
        self.product(undefined);
    });
};

var Cart = function() {
    // Stores an array of lines, and from these, can work out the grandTotal
    var self = this;
    self.linesa = ko.observableArray([new CartLine()]); // Put one line in by default
    self.grandTotal = ko.computed(function() {
        var total = 0;
        $.each(self.linesa(), function() { total += this.subtotal() })
        return total;
    });

    // Operations
    self.addLine = function() { self.linesa.push(new CartLine()) };
    self.removeLine = function(line) { self.linesa.remove(line) };
    self.save = function() {
        var dataToSave = $.map(self.linesa(), function(line) {
            return line.product() ? {
                productName: line.product().name,
                quantity: line.quantity()
            } : undefined
        });
        alert("Could now send this to server: " + JSON.stringify(dataToSave));
    };
};

ko.applyBindings(new Cart());

ViewModel 是一个 ContactsModel,因为 ContactsModel 没有 linea 属性,它无法呈现 table.

的内容
<tbody data-bind='foreach: linesa'>

这是违规行。

您实际上正在使用 2 个 ViewModel,Cart ViewModel 和 Contacts ViewModel。

您需要创建一个新的 ViewModel 来实现这两个 ViewModel,并且您可以使用 with 绑定来绑定视图。

代码:

function CombinedViewModel(){
  this.cart=new Cart();
  this.contact=new Contact();
}

ko.appyBindings(new CombinedViewModel());

以及绑定

<div data-bind="with:cart"><!-- cart html view goes here --></div>
<div data-bind="with:contact"><!-- contact html view goes here --></div>