为什么小部件的事件在视图完全呈现之前触发?

Why widgets' events triggered before view completely rendered?

假设我们有这样的视图:

<script id="my-view" type="text/x-kendo-template">
    <div>
            <input data-text-field="name"
                   data-value-field="id"
                   data-role="dropdownlist"
                   data-bind="source:wellDataSource,events:{change:onWellChange,dataBound:onWellDataBound}" />
            <div data-role="tabstrip" data-bind="visible:isAnyWellExist">
            <ul class="bd-doc-navigation-tabstrip" data-freezable="false">
                <li class="k-state-active">Home</li>
                <li>Products</li>
                <li>About</li>
                <li>...</li>
            </ul>
    </div>
</script>

JS:

var _view = new kendo.View("my-view", { model: _viewModel});
_view.render("#container");

当我渲染视图时,我希望渲染所有三个小部件,然后触发它们的事件,但是当 dropdownlist 渲染完成时,它是 databindingdatabound 事件在 tabstripgrid 呈现之前触发。所以我无法访问这些事件中的 tabstripgrid 小部件。

为什么会这样?是否有任何解决方案或解决方法来确保事件在完全呈现视图后发生?

每个小部件单独加载且彼此并行,因此很可能一个小部件已完全数据绑定,而另一个小部件尚不存在。事件不会等到页面完全加载。

根据您的实施方式,解决方法可能是将访问标签条和网格的代码移动到:

$(document).ready(function() {
   ...
});

要强制 Kendo 数据源同步运行,您可以尝试使用 async: false 配置数据源传输:

var datasource = new kendo.data.DataSource({
    transport: {
        read: {
            async: false,
            url: function (data) {
                return "/Home/Product";
            },
            dataType: "json"
        },
    },
});

我找到了一种检查是否所有小部件都已绑定的方法。参见 here

示例:

<script>
    $(document).ready(function() {
        var promises = [];

        var change = function() {
            this.deferred.resolve();   
        }

        var categories = $("#categories").kendoDropDownList({
            dataTextField: "CategoryName",
            dataValueField: "CategoryID",
            dataSource: {
                type: "odata",
                serverFiltering: true,
                transport: {
                read: "http://demos.kendoui.com/service/Northwind.svc/Categories"
            },
            requestStart: function() {
                this.deferred = $.Deferred();
                promises.push(this.deferred.promise());
            }
          }
        }).data("kendoDropDownList");

        var products = $("#products").kendoDropDownList({
            dataTextField: "ProductName",
            dataValueField: "ProductID",
            dataSource: {
                type: "odata",
                serverFiltering: true,
                transport: {
                    read: "http://demos.kendoui.com/service/Northwind.svc/Products"
                },
                requestStart: function() {
                    this.deferred = $.Deferred();
                    promises.push(this.deferred.promise());
                }
            }
        }).data("kendoDropDownList");

        categories.dataSource.bind("change", change);
        products.dataSource.bind("change", change);

        $.when.apply(null, promises)
            .done(function() {
                console.log("done");
                console.log(categories.value());
                console.log(products.value());
        });
    });
</script>

Kendo DropDownList 有一个 DataSource,仅供参考,事件 DataBindingDataBound 在从服务器收集数据时自动触发。

因此,要阻止它这样做,您必须阻止 DropDownList 的数据初始化。您可以将 DropDownList AutoBind 属性 更改为 false,这样它就不会在初始化阶段向服务器发出请求。页面完全呈现后,您可以触发它的 DataSource 来调用 read 方法。

你的代码应该是这样的

<input data-text-field="name"
       data-value-field="id"
       data-role="dropdownlist"
       data-bind="source:wellDataSource,events: change:onWellChange,dataBound:onWellDataBound}"
       data-auto-bind="false" />

$(document).ready(function() {
     $("#dropdown").data().kendoDropDownList.dataSource.read();
});

Kendo DropDownList AutoBind Documentation