【问题标题】:Firing actions after foreach finishes in knockout.js在敲除.js 中 foreach 完成后触发操作
【发布时间】:2015-09-18 19:50:06
【问题描述】:

我看过this questionthis other 的一篇关于该主题的文章,但似乎都没有解决我的问题。

我正在尝试为表格的每一行中的元素初始化一个 javascript 插件(BootStrap javascript 工具提示)。

为此,表格必须在 DOM 中呈现。这就是问题所在。 据我所知,knockout.js 没有提供正确的方法来了解 foreach 何时呈现整个表格。

我试图通过应用我发布的第一个链接中提供的解决方案来解决它,即通过创建自定义绑定,但这在我的情况下不起作用。 我猜是因为数据是通过 AJAX 调用调用 API 来显示的。

Reproduction of the issue

ko.bindingHandlers.doSomething = {
    update: function (element) {
        console.log("table loaded???");

        //applying the tooltip
        $('.actions').tooltip({
            title: 'Actions'
        });
    }
};

function ViewModel(){
    var self = this;
    self.myItems= ko.observableArray(['A', 'B', 'C']);

    //emulating the delay of calling an external API 
    self.getdata = function(){
        setTimeout(function(){
            self.myItems.push('D');
            self.myItems.push('E');
            self.myItems.push('F');
        }, 200);       
    };

    self.addItem = function () {
        this.myItems.push('New item');
    };

    //getting the data on loading    
    self.getdata();
}

ko.applyBindings(new ViewModel());

我不希望在foreach 情况下使用 Knockout.js 提供的 afterRender 回调,因为这样插件必须在每次迭代时初始化,而不是在最后只初始化一次。

我找到的唯一解决方案是在应用工具提示插件之前应用setTimeout,但这远非理想:

ko.bindingHandlers.doSomething = {
    update: function (element) {
        console.log("table loaded???");

        setTimeout(function(){
            //applying the tooltip
            $('.actions').tooltip({
                title: 'Actions'
            });
        }, 2000);
    }
};

另一种解决方案是在从 API 获取数据后调用tooltip 插件:

//emulating the delay of calling an external API 
self.getdata = function(){
    setTimeout(function(){
        //simulating 
        $.get(url, function(data){
            self.orders(data);
            self.loading(false);

            $('.actions').tooltip({
                title: 'Actions'
            });
        });
    }, 200);       
};

有没有更好的方法?

【问题讨论】:

  • 你见过Knockstrap吗?它具有绑定以帮助弥合淘汰赛和引导程序之间的差距。第一个例子是工具提示 - 可以帮助你吗?

标签: knockout.js knockout-3.0 knockout-3.2


【解决方案1】:

这里有一个选项,它以不同的方式混合了您已经知道的一些内容,可能更可口。

http://jsfiddle.net/xveEP/260/

我首先在视图模型中添加了一个名为tooltipHandle 的变量。此变量将是对任何为应用工具提示而进行的 setTimeout 调用的引用(或指针)。

我为<li> 元素而不是父<ul> 元素创建了一个自定义绑定。此自定义绑定首先清除所有现有的 setTimeout 实例以添加工具提示。然后它会创建一个新的setTimeout 实例,该实例将在 5 毫秒内运行。 setTimeout 中的函数会将工具提示应用于所有具有 .actions 类但尚未应用工具提示的元素。

在您的示例中,总共添加了 6 个元素:立即添加了 3 个元素,之后添加了 3 200 毫秒。我的绑定将执行 6 次,但是,它只会应用工具提示两次:前 3 次和第二次 3 一次。由于我在执行 tooltipHandle 之前清除了 tooltipHandle 函数,所以它只在 2 套中的每套的第 3 件完成装订后运行。我在 setTimeout 函数中添加了一个 console.log 调用,这样您就会看到在前面的示例中它只被调用了 2 次。

此外,当您单击“添加”按钮时,绑定将执行,并且只会将工具提示应用于新添加的元素。

<ul data-bind="foreach: myItems">
    <li data-bind="text: $data, doSomething2: true" class="actions"></li>
</ul>

ko.bindingHandlers.doSomething2 = {
    init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
        clearTimeout(bindingContext.$parent.tooltipHandle);
        bindingContext.$parent.tooltipHandle = setTimeout(function() {
            $('.actions:not([data-original-title])').tooltip({
                title: 'Actions'
            });
            window.console.log('tooltip applied');
        }, 5);
    }
};

function ViewModel(){
    var self = this;
    self.tooltipHandle = undefined;
    self.myItems= ko.observableArray(['A', 'B', 'C']);

    //emulating the delay of calling an external API 
    self.getdata = function(){
        setTimeout(function(){
            self.myItems.push('D');
            self.myItems.push('E');
            self.myItems.push('F');
        }, 200);       
    };

    self.addItem = function () {
        this.myItems.push('New item');
    };

    //getting the data on loading    
    self.getdata();
}

ko.applyBindings(new ViewModel());

【讨论】:

  • 感谢您的回复,抱歉耽搁了! :) 顺便说一句,你有什么理由使用bindingContext.$parent.tooltipHandle 而不是普通的var tooltipHandle 吗?
  • 绑定处理程序中的本地var tooltipHandle 意味着您可能会对.tooltip 进行多次不必要的调用。想象一下,如果您一次绑定 500 件物品。这意味着实际上只需要 1 次调用时需要 500 次 .tooltip 调用。通过将 tooltipHandle 集中在父 ViewModel 中,代码将清除所有待处理的 .tooltip 调用。局部变量不会有同样的效果。
  • 我的意思是外部全局var tooltipHandle 和内部tooltipHandle = setTimeout(function() {
  • 我总是尽量限制范围并尽可能避免使用全局变量。
猜你喜欢
  • 2010-11-01
  • 2017-10-07
  • 2012-06-09
  • 2013-06-08
  • 2016-03-15
  • 1970-01-01
  • 2017-09-12
  • 2013-03-07
  • 1970-01-01
相关资源
最近更新 更多