web-dev-qa-db-ja.com

AJAXコールバックでのカスタムイベントのトリガー

私はJavaScriptにかなり慣れていませんが、苛立たしいことの1つは、AJAXコールバックがさまざまな機能でパックされており、すべてを分離して整理することを困難にしていることです。

私はプログラミングに非常に慣れていないので、MVCをもう少し学習すると役立つと感じていますが、今のところ、カスタムイベントを使用すると、コードをよりクリーンに保ち、いくつかの問題を防ぐのに役立つようです。これが私が話していることです:

function myAjaxFunctionThatGetsTestData(){
    $.post('ajax/test.html', function(data) {
        $(document).trigger('testDataLoaded',data);
    });
}

function myOtherFunctionThatsDependentUponAjax(){
    getSomeTestData(); //start process of retrieving the data from ajax
    //then let me know when data has been retrieved
    $(document).one('testDataLoaded', function(data){
        alert (data);
    }
}

function getSomeTestData(){
    //maybe data was already retrieved by a different module, so check first
    if (data){
        $(document).trigger('testDataLoaded',data); 
    }
    else{
        myAjaxFunctionThatGetsTestData(); 
    }
}

ドキュメントをトリガーしても大丈夫かどうかもわかりません...

このように見えるパターンはありますか?これの潜在的な問題は何ですか?

7
Sabrina Gelbart

これはEvent Busと呼ばれ、各AJAXポスト(またはそのための他のアクション)が不要な場合にコードを分離する非常に便利な方法です問題)結果として何が起きなければならないかを明示的に述べなければならない。

// We've consolidated this functionality in an event manager, which gives us more power
// to log and recover from errors in event handlers.
EventManager.subscribe('ContentAdded', function(e) {
    // color every other row whenever content is added to the DOM.
    $('table.grid>tbody>tr:nth-child(even)', e.Content).addClass('even-row');
});

このイベントをコード内のどこにでも発行できることに注意してください。これらの場所のいずれもこのコードを意識する必要はありません。また、パブリッシングコードと密接に結合していなくても、他のどこでもイベントを処理できます。

私が取り組んでいる(ASP.NET MVC)プロジェクトでは、これは非常に効果的なアプローチであり、他の種類のAJAX呼び出しをほとんど排除しました。イベントを取得しました。のほとんどのAJAX=リンクが単一のグローバルコールバックハンドラーを使用してサーバーから返されたイベントを単純に公開するポイントまでの-駆動型フレームワーク。特定のイベントが発生したときに通知を受けることに関心のあるモジュールイベントは、これらのイベントをグローバルにサブスクライブできます。

次のようなコードを使用してリンクを作成します。

@Html.EventAction("Create Task", "CreateTask")

...私のフレームワークは次のようにHTMLとしてレンダリングできます:

<a href="/.../CreateTask" data-ajax="true" data-ajax-success="EventHandlers.Success">
    Create Task
</a>

ユーザーがこのリンクをクリックすると、AJAXリクエストを実行して次のようなアクションを実行します。

public ActionResult CreateTask()
{
    if(!UserCanCreateTasks())
        return Events.ErrorResult("You don't have rights to create tasks.");

    Events.OpenModalDialog("Create Task", "TaskEditView", new TaskEditViewModel());
    return Events.Result();
}

これにより、ダイアログのレンダリングされたコンテンツを含むModalDialogOpenedEventを含むJSONオブジェクトが生成されます。

EventHandlers.Successメソッドは、返されるすべてのイベントを単純にパブリッシュし、次のようなハンドラーを間接的に呼び出します。

EventManager.subscribe('ModalDialogOpenedEvent', function(e) {
    createDialog(e.Title, e.Contents);
});

そのため、制御ロジックは実際にコントローラー内にとどまることができ、特定の機能のために記述する必要があるカスタムJavaScriptの量を劇的に削減しました。 UIのボタンの種類ごとにカスタムハンドラーコードを記述する必要がなくなり、サーバーが予期しない応答を返したときに何が起こるかを心配する必要がなくなりました。

たとえば、ユーザーのセッションがタイムアウトになった場合、アクションコードは呼び出されません。サーバーはAJAXリクエストをログインハンドラーにすぐにリダイレクトします。ログインハンドラーを作成しましたイベント駆動型AJAXリクエスト内にあるかどうかを検出し、ログインダイアログを開く原因となるイベントを返すのに十分なほど賢くなります。ユーザーが作成しようとしたリクエストは、サーバーは、ログインが成功したことを示すイベントを返し、その後、自動的に再試行されます。システム内のすべてのAJAXリクエストを処理する準備ができている必要がある場合、これがどれだけの追加コードを必要とするか想像できます。この種のコーナーケースですが、イベントベースのシステムでは、それは簡単です。

3

私があなたの質問を誤解していなかったら、あなたはこのようなことをしています(jQueryで):

// Bind to some arbitrary event name
$("body").bind("arbitrary", function(evt){
  alert("o/");
});

// Create a random event
var e = jQuery.Event("arbitrary");

// Fire the event
$("body").trigger(e);

...大丈夫かどうか尋ねます。これは、たとえば Rails で使用される一般的な手法です。また、jQueryはこれらのイベントに、使用するプロパティの Nice set プロパティを提供します。 「ドキュメント」へのバインドに問題はありません。

質問に答えてみますここで起こっていることはあなたのAJAXメソッドはデータを非同期に取得するように設定されているため、データ変数を使用しようとすると、AJAX呼び出しがバックグラウンドで実行されています。行う必要があるのは、非同期ではなく同期になるようにajax呼び出しを設定することです。そのため、コードはAJAX呼び出しが完了する前に完了するまで待機します。

fireFoxのFirebugプラグインを使用してJavaScriptコードをデバッグすると、AJAXの動作と、jQueryライブラリの使用に関連する他の多くのことを理解するのに役立ちます。

このメソッドを更新します。

function myAjaxFunctionThatGetsTestData(){
   $.post('ajax/test.html', function(data) {
    $(document).trigger('testDataLoaded',data);
   });
}

に:

function myAjaxFunctionThatGetsTestData(){
   $.ajax({
    type: "POST",
    dataType: "html",
    url: "ajax/test.html",
    data: "",
    async: false, //by default all AJAX calls are set to true
    contentType:  "text/html",
    success: function(data){
     //successful call to server side and back
     //add data to you _data global variable
     //or do your data check here
     _data = data;
    },
    error: function(jqXHR, textStatus, errorThrown){
     //display error message, ajax call failed
     alert(textStatus);
    }
   });
}
1
zulucoda

理想的には、関連するものにイベントハンドラーをアタッチする必要があります。より大きなアプリケーションでは、ディスパッチャオブジェクトまたはJavaScriptオブジェクト間の通信を処理するオブジェクトにすることができます。

より単純なケースでは、特定のUI要素をバインドするように、単にそれをそれらにバインドすることができます。そのようにして、それを設定またはトリガーしたときに、それに関連する要素がわかっています。または、UI要素がウィジェットの一部である場合はルート要素。

それ以外の場合、ドキュメント要素自体を使用することに問題はないと思います。たぶん、関数をトリガーするか、完全なイベントオブジェクトを発行するかによって、代わりにtriggerHandler()を使用する方が良いでしょう。

0
GillesC

これはおそらくjqueryであり、残念ながら、コードの記述方法をよりphp風に変更します。

通常、mootoolsを使用するときは、呼び出しとハンドラーをオブジェクトにパックします。例えば。

function edit_handler(a,b,c)
{

    var that = this; //priv member
    this.onProcess = function(data) {}; //public member
    this.onOk = function() {};
    this.onFailure = function() {};

    function process(data) // priv method
    {
        that.onProcess();
        //do processing
    }

    this.run = function (param) //public method
    {
        AJAX.call => onSuccess => process(ret) ; onFail => that.onFailure();
    }

}

var edit_amount = new edit_handler(1,2,3);
edit_amount.onFailure = function() {alert("Update failed");}
form field=> on edit => edit_amount.process(value);

私のポイント-オブジェクトとプライベートメソッド/プロパティを使用します。多くの機能を作ることは常に混乱を引き起こしています。

0
Slawek

これは、あなたがやろうとしていることの簡単なバージョンです。そして従うのははるかに簡単です:

function myAjaxFunction(){
    $.post('ajax/test.html', function(data) {
        myOtherFunctionThatsDependentUponAjax(data);
    });
}

function myOtherFunctionThatsDependentUponAjax(){
    alert(data);
}

これも可能ですが、JQueryのイディオムについては不明です。

function myAjaxFunction(){
    $.post('ajax/test.html', myOtherFunctionThatsDependentUponAjax);
}

function myOtherFunctionThatsDependentUponAjax(){
    alert(data);
}
0
Izkata