4

我正在尝试从列表中删除一个项目。我正在使用带有映射插件的 knockout.js。我的代码如下所示:

序列化为 Json

@{ var jsonData = new HtmlString(new JavaScriptSerializer().Serialize(Model));}

模板

<script type="text/html" id="imgsList">
    {{each model.Imgs}}
        <div style="float:left; margin: 10px 10px 10px 0;">
            <div><a href="${Filename}"><img src="${Filename}" style="width:100px;"></img></a></div>
            <div data-bind="click: deleteImage">Delete</div>
        </div>
    {{/each}}
</script>

KO JavaScript

<script type="text/javascript">
     $(function() {
        //KO Setup
        var viewModel = { 
            "model": ko.mapping.fromJS(@jsonData),
            "deleteImage" : function(item) {alert(item.Filename + ' deleted.');}
        }

        ko.applyBindings(viewModel);
    });
</script>

的HTML

<div data-bind="template: 'imgsList'"></div>

问题

一切都按预期工作。但是,当您单击按钮项时,会显示带有删除按钮的图像列表。文件名未定义。想法?

编辑:取自 KNockout.js 手册:“调用处理程序时,Knockout 将提供当前模型值作为第一个参数。如果您为集合中的每个项目呈现一些 UI,这将特别有用,并且您需要知道点击了哪个项目的 UI。”

看来我没有得到我期待的 Img 对象。我不知道我得到了什么!

4

2 回答 2

7

我注意到这里有一个如何做到这一点的例子:

http://blog.stevensanderson.com/2011/12/21/knockout-2-0-0-released/

查看4. Cleaner 事件处理部分,Steve 展示了从列表中删除项目的示例。

<h3>Products</h3>

<ul data-bind="foreach: products">
    <li>
        <strong data-bind="text: name"></strong>
        <button data-bind="click: $parent.removeProduct">Delete</button>
    </li>
</ul>

Javascript:

    function appViewModel() {
        var self = this;
        self.products = ko.observableArray([
            { name: "XBox" },
            { name: "PlayStation" },
            { name: "Banana" },
            { name: "Wii" }
        ]);

        self.removeProduct = function(product) {
            self.products.remove(product);   
        }
    };

ko.applyBindings(new appViewModel());

但请注意,上面的示例适用于最新版本的 KnockoutJS 2.0。

于 2012-01-02T23:35:32.713 回答
6

当您在 jQuery 模板中使用 {{each}} 语法时,数据上下文是整个模板所绑定的任何内容。在您的情况下,这就是整个视图模型。

几个选项:

1-您可以使用您当前的代码并将您“eaching”的项目传递给函数,例如(http://jsfiddle.net/rniemeyer/qB9tp/1/):

<div data-bind="click: function() { $root.deleteImage($value); }">Delete</div>

不过,在数据绑定中使用异常函数非常难看。有更好的选择。

2-您可以使用foreach模板绑定的参数,它与 jQuery 模板一起使用并且比 {{each}} 更有效,例如(http://jsfiddle.net/rniemeyer/qB9tp/2/):

<script type="text/html" id="imgsList">
    <div style="float:left; margin: 10px 10px 10px 0;">
        <div>
            <a href="${Filename}">${Filename}</a>
        </div>
        <div data-bind="click: $root.deleteImage">Delete</div>
    </div>
</script>

<div data-bind="template: { name: 'imgsList', foreach: model.Imgs }"></div>

现在,模板的上下文是单个图像对象,调用$root.deleteImage会将其作为第一个参数传递。

3- 由于 jQuery 模板插件已被弃用并且 Knockout 现在支持原生模板,您可能希望选择删除对 j​​Query 模板插件的依赖。您仍然可以使用命名模板(只需使用数据绑定属性替换任何 jQuery 模板语法),例如:http: //jsfiddle.net/rniemeyer/qB9tp/3/甚至删除模板并使用foreach控件-流绑定如:http: //jsfiddle.net/rniemeyer/qB9tp/4/

<div data-bind="foreach: model.Imgs">
    <div style="float:left; margin: 10px 10px 10px 0;">
        <div>
            <a data-bind="text: Filename, attr: { href: Filename }"></a>
        </div>
        <div data-bind="click: $root.deleteImage">Delete</div>
    </div>
</div>

4-虽然我更喜欢选项 #3,但您甚至可以选择使用事件委托并附加一个“实时”处理程序,例如:http: //jsfiddle.net/rniemeyer/qB9tp/5/

$("#main").on("click", ".del", function() {
   var data = ko.dataFor(this);
   viewModel.deleteImage(data); 
});

如果您要通过绑定附加大量相同的处理程序click(例如在网格中),这可能特别有用。

于 2012-01-03T03:42:22.783 回答