2

目标

阅读KnockoutJS 添加的内容data-product-idDOM

问题

我有以下标记:

<!-- 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 不考虑data-product-id由 KnockoutJS 生成的,因为如果我手动将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);
    }
});

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

4

3 回答 3

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。

于 2013-07-01T13:55:07.867 回答
1

根据这个小提琴,它应该可以工作。

确定在应用绑定后执行 $(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">

所以,我认为你应该:

  • 创建虚拟机实例
  • 应用绑定
  • 调用一个 init 函数,在该函数中调用 $(element).each
于 2013-07-01T13:27:37.580 回答
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);
    });
});
于 2013-07-01T13:45:25.850 回答