1

RPNiemeyer剣道ノックアウトライブラリを使用しています。グリッドがあります。ユーザーがグリッドの行をクリックすると、ポップアップウィンドウが表示されます。ウィンドウを閉じて、同じ方法で再度開くと、アプリケーションが閉じたアニメーションでフリーズします。このシナリオをフィドルで再現するために、できる限りのことを試みました。ポップアップウィンドウを閉じて行をもう一度クリックすると、何も起こらず、ブラウザがリロードされます。私のアプリケーションでも同様のことが起こっていると強く信じています。

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

閉じた後、ウィンドウが適切にクリーンアップされていないようです。これは通常問題ではありません(そして望ましいです)が、グリッドが再レンダリングされるkendoWindowと、ウィンドウがすでにそこにあることを知らない新しいものが初期化されます。

これはノックアウト剣道コードで処理できる可能性があります。ウィンドウのdestroyメソッドはすでに呼び出されているので、実際にウィンドウ要素が削除されない理由を調べる必要があります。

今のところ回避策は、次のようにウィンドウが閉じられたときのグローバルハンドラーを構成することです。

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

こちらのサンプル:http://jsfiddle.net/rniemeyer/dcYRM/

于 2013-01-07T15:46:40.393 に答える
1

これはノックアウト剣道のバグです。

destroyウィンドウのメソッドは呼び出されません。これは、ノックアウト剣道が、ウィジェットがdomから削除されたときに、ウィジェットを破棄する必要があることを検出しているためです。ただし、kendoWindow要素をdomの最後に移動します。更新中にknockout.jsが要素をクリアまたは削除しても、要素は移動されているため、要素は削除されません。

これは、ノックアウト剣道を変更して、プロキシ要素を作成した要素があった場所にプロキシ要素を残し、プロキシ要素が破棄されたときにウィジェットkendoWindowを使用destroyすることで修正できます。kendoWindowノックアウト剣道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 に答える