1

我正在使用 RPNiemeyer kendo-knockout 库。我有一个网格。当用户单击一行网格时,会显示一个弹出窗口。当您关闭窗口并以同样的方式再次打开它时,应用程序会随着关闭动画冻结。我尽我所能在小提琴中重现这个场景。当您关闭弹出窗口并再次单击该行时,没有任何反应并重新加载浏览器。我坚信我的应用程序中正在发生类似的事情。

html:

<div data-viewId="languageList" >
    <div id="languageList" data-bind="with: viewModel">
        <div id="languageListGrid" data-bind="kendoGrid: { data: languageViewModels, columns: [ 
                { 
                    template: '<a href=\'\' data-bind=\'click: function() { onLanguageSelected(&quot;#=Language#&quot;) }\'>#=Language#</a>', 
                    field: 'Language', 
                    title: 'Language',
                    width: 50
                }

                ], 
            scrollable: false, sortable: true, pageable: false }" style="height: 380px">

        </div>
    </div>
</div>

<div data-viewid="languageDetails">
    <div id="languageDetails" data-bind="with: viewModel" class="hidden">
        <form id="languageDetailsForm" action="" style="font-family: Trebuchet MS, Verdana, Helvetica, Sans-Serif;">
        <div data-bind="kendoWindow: {isOpen: isOpen, title:'Language', width: 400, height: 200, modal: true }" >
            test
            <button id="cancelLanguage" class="k-button" data-bind="click: cancelLanguage">Cancel</button>
        </div>
       </form>
    </div>
</div>​

javascript:

$(function () {

    var elementIsBoundNew = function (element) {
        return !!ko.dataFor(element);
    }

    var applyBindings = function (viewModel, elementId) {
        var element = $('div[data-viewId="' + elementId + '"]')[0];
        if (!elementIsBoundNew(element)) {
            var parentViewModel = { viewModel: viewModel };
            ko.applyBindings(parentViewModel, element);
        }
    };

    var FranchiseDetailsViewModel = function () {
        var 
            self = this,
            initialize = function () {
                self.languagesInfoViewModel(new LanguageListViewModel(self));
                applyBindings(self.languagesInfoViewModel, "languageList");
            };

        FranchiseDetailsViewModel.prototype.languagesInfoViewModel = ko.observable();
        initialize();
    };

    var LanguageListViewModel = function (franchise) {
        var 
            self = this,
            initialize = function () {
                var languageViewModel = new LanguageDetailsViewModel(franchise);
                self.languageViewModels.push(languageViewModel);
            };
        LanguageListViewModel.prototype.languageViewModels = ko.observableArray([]);
        LanguageListViewModel.prototype.selectedLanguageViewModel = ko.observable();

        LanguageListViewModel.prototype.onLanguageSelected = function (selectedLanguage) {
  // when you uncomment this line everyting works fine
  //var language = new LanguageDetailsViewModel();  
            self.selectedLanguageViewModel(self.languageViewModels()[0]);

            applyBindings(self.selectedLanguageViewModel, "languageDetails");

            self.selectedLanguageViewModel().openPopUp();
        };
        initialize();
    };

    var LanguageDetailsViewModel = function () {
        var 
            self = this,
            closePopUp = function () {
                self.isOpen(false);
            };

        self.Language = ko.observable("English");

        LanguageDetailsViewModel.prototype.isOpen = ko.observable(false);

        LanguageDetailsViewModel.prototype.openPopUp = function () {
            self.isOpen(true);
        };

        LanguageDetailsViewModel.prototype.cancelLanguage = function () {
            closePopUp();
        };

    };

    var initialize = new FranchiseDetailsViewModel();
});​

奇怪的是,如果我将这行代码添加到我的 onLanguageSelected 方法中,一切都可以正常工作:

var language = new LanguageDetailsViewModel();

小提琴:

http://jsfiddle.net/bZF9k/26/

任何有关工作示例的帮助将不胜感激。谢谢!

根据 RPNiemeyer 的帖子更新:

我已经添加了这些代码行以使用此处Kendo-Knockout 中的技术:调用一个方法从模板中更改 viewmodel 属性,并在网格内进行数据绑定,破坏绑定

 ko.bindingHandlers.preventBinding = {
      init: function() {
          return { controlsDescendantBindings: true };
      }        
    };

    ko.bindingHandlers.kendoGrid.options.dataBound = function(data) {
      var body = this.element.find("tbody")[0];

      if (body) {
         ko.applyBindings(ko.dataFor(body), body);   
      }
    };

这正是我的应用程序中正在发生的事情。当我打开弹出窗口时,将其关闭,然后再次打开它,它没有正确关闭。请看我更新的小提琴:

http://jsfiddle.net/bZF9k/29/

我错过了什么?再次感谢您的反馈!

4

2 回答 2

1

这是淘汰赛剑道中的一个错误。

destroy不调用窗口的方法。这是因为 knockout-kendo 检测到一个小部件在从 dom 中移除时需要被销毁。但是,kendoWindow将元素移动到 dom 的末尾。当 knockout.js 在更新期间清除或删除元素时,它不会删除该元素,因为该元素已被移动。

这可以通过修改 knockout-kendo 来解决,以便在创建它的元素所在的位置留下一个代理元素kendoWindow,并在处理代理元素时destroyingkendoWindow小部件。对淘汰赛剑道 0.7.0 的以下更改实现了这一点:

--- knockout-kendo-0.7.0.js 
+++ knockout-kendo-0.7.0.js
@@ -62,14 +62,19 @@
                   return { controlsDescendantBindings: true };
               }
         };

         //build the core logic for the init function
         binding.setup = function(element, options, context) {
-            var widget, $element = $(element);
+            var widget, $element = $(element), $disposeProxy;

+            // Create proxy in original location to capture when the element would have been disposed
+            if (widgetConfig.destroyByProxy) {
+                $disposeProxy = $('<div style="display: none" />').insertAfter($element);
+            }
+            
             //step 2: setup templates
             self.setupTemplates(widgetConfig.templates, options, element, context);

             //step 3: initialize widget
             widget = self.getWidget(widgetConfig, options, $element);

@@ -78,12 +83,17 @@

             //step 5: set up computed observables to update the widget when observable model values change
             self.watchValues(widget, options, widgetConfig, element);

             //step 6: handle disposal, if there is a destroy method on the widget
             if(widget.destroy) {
+                if ($disposeProxy) {
+                    ko.utils.domNodeDisposal.addDisposeCallback($disposeProxy[0], function() {
+                        widget.destroy();
+                    });
+                }
                 ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
                     widget.destroy();
                 });
             }
         };

@@ -768,13 +778,16 @@
         }
     },
     watch: {
         content: CONTENT,
         title: TITLE,
         isOpen: [OPEN, CLOSE]
-    }
+    },
+    // The dom element that contains the window isn't going to be disposed when the template containing it is rendered again.
+    // This is because the window's dom element is placed at the end of the document structure by kendoWindow
+    destroyByProxy: true
 });

 createBinding({
     name: "kendoChart",
     watch: {
         data: function(value) {
于 2013-12-09T19:07:20.197 回答
1

看起来窗户关闭后没有正确清理。这通常不是问题(并且是可取的),但如果重新渲染网格,则会kendoWindow初始化一个不知道已经存在窗口的新网格。

在淘汰赛剑道代码中可能会处理这个问题。窗口的destroy方法已经被调用,所以我需要看看为什么它实际上没有删除窗口元素。

目前的解决方法是为关闭窗口时配置一个全局处理程序,例如:

  ko.bindingHandlers.kendoWindow.options.close = function() {
      $('.k-window, .k-overlay').remove();
  };

示例:http: //jsfiddle.net/rniemeyer/dcYRM/

于 2013-01-07T15:46:40.393 回答