数据绑定“attr”不起作用(?)

时间:2013-07-01 13:07:24

标签: javascript jquery html knockout.js

目标

阅读KnockoutJS添加的data-product-id中的DOM

问题

我有以下标记:

<!-- ko foreach: Summary.products -->
<li data-bind="attr: { 'data-product-id': id }">
    <div class="product-summary-actions float-right">
        <button class="btn btn-danger btn-mini remove-item">
            <i class="icon-remove"></i>
        </button>
    </div>
    <div class="product-summary-quantity">
        <h6 data-bind="text: infoComposition"></h6>
    </div>
    <div class="product-summary-description">
        <p data-bind="text: name"></p>
    </div>
</li>
<!-- /ko -->

如您所见,在attr绑定注释后的第一行有一个数据绑定。看:

<li data-bind="attr: { 'data-product-id': id }">

当我使用Chrome控制台检查我的DOM时,我有以下内容:

<li data-bind="attr: { 'data-product-id': id }" data-product-id="1">...</li>

如您所见,data-product-id 已成功应用。但是,当我必须与他进行交流时,没有成功

我的应用程序中有一个函数负责检查我的产品摘要中是否存在某个项目,以下循环执行此操作:

$(element).each(function () {
    var $productId = $(this).closest("li").data("product-id"),
    $match = $(".summary")
             .find("li[data-product-id=" + $productId + "]").length > 0;
     console.log($match);
});

总是返回 false 。换句话说,似乎jQuery不考虑KnockoutJS生成的data-product-id,因为如果我手动将data-product-id属性添加到我的项目(如下面的标记),那么一切正常。

<!-- ko foreach: Summary.products -->
<li data-product-id="1">
    <div class="product-summary-actions float-right">
        <button class="btn btn-danger btn-mini remove-item">
            <i class="icon-remove"></i>
        </button>
    </div>
    <div class="product-summary-quantity">
        <h6 data-bind="text: infoComposition"></h6>
    </div>
    <div class="product-summary-description">
        <p data-bind="text: name"></p>
    </div>
</li>
<!-- /ko -->

好的......代码

我的必要 HTML:

<button class="btn btn-success btn-small add"
        title="Add to comparison list">
    <i data-bind="attr: { class: ProductLayout.existsAtSummary($element) ? 
                  'icon-minus' : 'icon-plus' }">
    </i>
</button>

我的JS:

function ProductLayoutViewModel() {
    var self = this;

    self.itemQuantity = ko.observable("");
    self.itemQuantityValid = ko.computed(function () {
        var q = self.itemQuantity();
        return q != "0" && q != "00" && q != null && q != "";
    }, this);

    self.existsAtSummary = function (element) {
        $(element).each(function () {
            $productId = $(this).closest("li").data("product-id");
            $match = $(".summary")
                     .find("li[data-product-id=" + $productId + "]").length;

            if (!$match)
                return true;
            else
                return false;
        });
    });
};

ViewModel = {
    Summary: new SummaryViewModel(),
    ProductLayout: new ProductLayoutViewModel()
};

$.ajax({
    url: "/ProductsSummary/List?output=json",
    dataType: "json",
    success: function (data) {
        var mappingOptions = {
            create: function (options) {
                return (new (function () {
                    this.finalMeasure = ko.computed(function () {
                        return this.quantity() > 1 ? 
                               this.measure() + "s" : this.measure();
                    }, this);

                    this.infoComposition = ko.computed(function () {
                        return this.quantity() + ' ' + this.finalMeasure();
                    }, this);

                    ko.mapping.fromJS(options.data, {}, this);
                })());
            }
        };

        ViewModel.Summary.products = ko.mapping.fromJS(data, mappingOptions);
        ko.applyBindings(ViewModel);
    }
});

有人知道如何解决这个问题?谢谢!

3 个答案:

答案 0 :(得分:1)

根据this fiddle,它应该有用。

确保在应用绑定后执行$(element).each?

JS:

var vm = { id:'myID-product'};    
ko.applyBindings(vm);    
var element = $("#myID").data("product-id");             
console.log(element);

查看:

<li data-bind="attr: { 'data-product-id': id }" id="myID">

所以,我认为你应该:

  • 创建VM实例
  • 应用绑定
  • 调用一个init函数,在该函数中调用$(element).each

答案 1 :(得分:1)

我猜你在你的DOM准备好之前(在Knockout进行修改之前)你正在做$ .each。

从ViewModel中取出每个并将其放入此代码块中:

$(function() {
    $(element).each(function () {
        var $productId = $(this).closest("li").data("product-id"),
        $match = $(".summary")
                 .find("li[data-product-id=" + $productId + "]").length > 0;
        console.log($match);
    });
});

答案 2 :(得分:1)

看起来你有时间问题。

请注意,knockoutjs首先通过你的js模型,然后用内容填充视图。因此,如果您正在测试或在您的情况下迭代某些DOM结构,则直接进入计时错误。

尝试重新思考你在那里做的事情。由于knockoutjs正在为html提供数据,因此您已经拥有了js代码中的所有数据。对我而言,这看起来像是一轮工作。

例如: 你的模板:

<!-- ko foreach: Summary.products -->
<li data-bind="attr: { 'data-product-id': id }">
</li>
<!-- /ko -->

在knockoutjs中,您已经拥有了产品清单和特定产品ID。所以你需要做的就是检查列表的长度?或者我会错过那里的东西吗?

如果我弄错了,你只是想触发另一个javascript,当你的列表被呈现时它正在做某事,当knockoutjs填满你的内容时,尝试触发一些事件。或者在dom准备好后触发你的javascript。