0

我已经看到了这个问题和关于这个主题的另一个问题,但它们似乎都没有解决我的问题。

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

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

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

问题的再现

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());

我不希望在案例中使用afterRenderKnockout.js 提供的回调,foreach因为这样插件必须在每次迭代时初始化,而不是最后一次。

我找到的唯一解决方案是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);       
};

有没有更好的方法呢?

4

1 回答 1

1

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

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

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

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

在您的示例中,总共添加了 6 个元素:立即添加了 3 个元素,之后添加了 3 200 毫秒。我的绑定将执行 6 次,但是,它只会应用工具提示两次:前 3 次一次,第二次 3 次一次。由于我在tooltipHandle执行函数之前清除了它setTimeout,因此它仅在第 3 项之后运行2套中的每一套都完成了装订。我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());
于 2015-07-01T21:17:35.683 回答