在foreout结束之后在knockout.js中的射击动作

时间:2015-07-01 15:01:19

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

我看过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());

我宁愿不使用Knockout.js为afterRender个案提供的foreach回调,因为这样插件必须在每次迭代时初始化,而不是在最后一次。< / p>

我找到的唯一解决方案是在应用工具提示插件之前应用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);       
};

有没有更好的方法呢?

1 个答案:

答案 0 :(得分:1)

这是一个选项,以一种可能更适合的不同方式混合您已经知道的一些内容。

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

我首先在viewmodel中添加了一个名为tooltipHandle的变量。此变量将是用于应用工具提示的任何setTimeout调用的引用(或指针)。

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

在您的示例中,总共添加了6个元素:3个立即,3个200毫秒。我的绑定将执行6次,但是,它只会应用两次工具提示:一次用于前三次,一次用于第二次3.因为我在清除tooltipHandle之前才能执行setTimeout函数,它仅在2组中的每一组完成绑定的第3项之后运行。我在console.log函数中添加了setTimeout调用,以便您在上一个示例中看到它只被调用了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());