1

多分私は間違った軌道に乗っています...

セットアップ: 私はかなり複雑な完全なdojofiedWebアプリケーションを持っています。この質問の重要な部分はdijit.layout.BorderContainer、ナビゲーションツリーと他の領域のいくつかのアクションボタンを備えたの中央領域の長いフォームです。

私がしたいこと: ユーザーがデータを入力し、保存しなかった場合、フォームを離れるときに警告メッセージが表示されるはずです(ユーザーが離れる場合は、[新しい要素]ボタンをクリックします...)。より良いユーザーエクスペリエンスのために、「保存」、「とにかく残す」、「キャンセル」のオプションを備えたモーダルダイアログを提供したいと思いました。フォームのonBlurイベントを使用し、他のすべてのイベント(おそらく、他のウィジェットのonClick)を停止し、変更があるかどうかを確認し、変更がある場合はダイアログを表示します。それ以外の場合は、他のイベントを続行します。すべての非フォームアクティブ要素にcheckChangesメソッドを追加したくありません!

最初のテストでは、イベントを停止しようとしました...

これは動作します

<div id="formArea" dojoType="dijit.form.Form" encoding="multipart/form-data" action=""  class="ContentPane" region="center">
   <script type="dojo/connect" event="onBlur" >
      alert("I don't think so");
    </script>
 </div>

...しかしそれは醜くて私は簡単に続けることができません

これはしません

<div id="formArea" dojoType="dijit.form.Form" encoding="multipart/form-data" action=""  class="ContentPane" region="center">
   <script type="dojo/connect" event="onBlur" args="e">
      console.log("blur"); // ok
      e.preventDefault();//event.stopt(e)//return false //<--neither of these
    </script>
 </div>

問題は、フォームの外側のボタンをクリックするとonBlurトリガーされますが、ボタンのを停止できないことonClickです。onBlur私はそれがイベントオブジェクトを配信しないことを知っています-それで実際には機能しません...他の要素e.somethingをキャッチする方法はありますか?onClick

4

2 に答える 2

2

onBlurデータが保存されていない場合、フォームのボタン イベント リスナーを一時停止します。

実際の動作をご覧ください: http://jsfiddle.net/phusick/A5DHF/

いくつかのボタン イベント リスナーがあり、on.pausable(node, event, callback)代わりにon()次の方法で登録します。

var b1Handler = on.pausable(button1Node, "click", function() {
    console.log("b1.onClick");        
});

var b2Handler = on.pausable(button2Node, "click", function() {
    console.log("b2.onClick");        
});

ハンドラーを配列に収集します。

var handlersToPause = [b1Handler, b2Handler];

onBlurイベント リスナーを追加します。

on(form, "blur", function(e) {

    if (this.isDirty()) {
        // if data are not saved, pause button event listeners
        handlersToPause.forEach(function(handler) {
            handler.pause();
        });
        // display modal dialog here     
    }            
});

たとえば、イベント リスナーを追加onFocusして、ボタン イベント リスナーを再開します。

on(form, "focus", function(e) {
    handlersToPause.forEach(function(handler) {
        handler.resume();            
    });
});

イベントではなくリスナーhandler.pause()を一時停止していることに注意してください。イベントは で待機しているため、onclickの実行時間中はアクセスできません。onclickEvent queueonblur

もっと堅牢な解決策を考えますが、これは迅速であり、あなたの質問に答えます。とにかく、フォーム以外のすべてのアクティブな要素を変更する必要なく、checkChangesを呼び出すようdojo/aspectaroundアドバイスを見てください。

于 2012-06-05T12:32:51.310 に答える
1

confirm('question?')あなたのページのイベントをそのように「デッドロック」させるだけのことがわかります。

私は同様の設定をしましたが、これを回避する方法 (ユーザーがアドレスバーに URL を入力して Enter キーを押した場合を除く) は、ナビゲーション ツリーがクリックされるたびにポップアップ ダイアログが表示され、ユーザーを新しいビューに送ります。検討:

----------------------------------------
| Nav 1  |   Asset1 ( view controller )  |
| Nav 2  |   Asset2 ( hidden )           |
----------------------------------------

Nav 1 はデフォルトのオンロード ビューです。Asset 1 はロードされ、「セットアップ ページ」フォームなどを含み、変更できます。秘訣は、Asset1 と Asset2 が AbstractAsset から派生したものであり、これが単純な ContentPane 拡張であるということです。

AbstractAsset では、「機能のためにオーバーライドする必要がある」関数が呼び出されますisDirty

var Viewcontroller = declare("AbstractAsset", [dijit.ContentPane], {
       isDirty: function() { return false; }
});


declare("Asset1", [Viewcontroller], {

startup: function() {
  // sets up form
  ...
  // and references inputfields to 'this'
  this.inputfields = this.form.getChildren();

  // and saves (clones) the state of each field
  var self = this;
  this.inputfields.forEach(function(inputWidget) {
     self.states[inputWidget.id] = inputWidget.get("value");
  });
},
isDirty: function() {
  var self = this;
  var dirty = false;
  this.form.getChildren().some(input) {
     if(self.states[input.id] != input.get("value")) {
        dirty = true;
        return false; // breaks .some loop
     }
     return true;
  });
  return dirty;
}

})

次に、すべてのナビゲーション クリックは、続行するために、現在表示されているビュー コントローラーの isDirty 関数を呼び出す必要があります。ユーザーが nav-tree (dijit.Tree) 行ノードNav 2をクリックするとします。

var navigation = dojo.declare("NavigationController", [dijit.Tree], {
 currentView : null,
 onLoad: function() {
   // start Asset1 in viewNode by default
   this.currentView = new Asset1({ }, this.viewNode); 
 },
 onClick : function() {
    if(this.currentView.isDirty()) alert("I Dont Think So");
    else {
       this.loadFunction(this.model.selection.getSelected());
    }
 }

});

これは、on-unload-check を実装する一般的な考え方です。「マスター アプリケーション コントローラー」を介して onClick イベントをフックし、何が起こるかを判断する必要があります。isDirty の例については、cms ナビゲーション コントローラーとして機能するこのアプリケーションとそのpage.js:587を確認してください。

于 2012-06-05T10:45:00.577 に答える