1

並列非同期呼び出しの状態を表示するには、どのインターフェイスまたはコンポーネントをお勧めしますか? (言語は私にとってそれほど重要ではありません。パターンだけです。同じクラス/インターフェースをjavascriptで書き直すことができます...)

REST サービスからモデル データをロードし、実際のコンテンツの前に保留中のラベルを表示し、問題が発生した場合はエラー メッセージを表示したい...これは一般的な問題であり、既に記述されたコンポーネントまたはベスト プラクティスが存在する必要があると思います、またはこのためのパターン。あなたはそのようなことを知っていますか?

スパゲッティ コードを次に示します。Backbone.syncParallel はまだ既存の関数ではありません。これには、updateForm、updated という 2 つの主な状態があります。すべてのメイン状態の前に、ページに「お待ちください!」と表示されます。ラベル、およびエラーにより、ページにエラー メッセージが表示されます。この種のコードは再利用性が高いと思うので、現在の状態を自動的に表示するコンテナーを作成できると思いますが、このコンポーネントがどのようなインターフェイスを持つべきかを判断できません...

var content = new Backbone.View({
    appendTo: "body"
});
content.render();

var role = new Role({id: id});
var userSet = new UserSet();

Backbone.syncParallel({
    models: [role, userSet],
    run: function (){
        role.fetch();  
        userSet.fetch();
    },
    listeners: {
        request: function (){
            content.$el.html("Please wait!");
        },
        error: function (){
            content.$el.html("Sorry, we could not reach the data on the server!");
        },
        sync: function (){
            var form = new RoleUpdateForm({  
                model: role,  
                userSet: userSet  
            });  
            form.on("submit", function (){
                content.$el.html("Please wait!");
                role.save({
                    error: function (){
                        content.$el.html("Sorry, we could not save your modifications, please try again!");
                        content.$el.append(new Backbone.UI.Button({
                            content: "Back to the form.",
                            onClick: function (){
                                content.$el.html(form.$el);
                            }
                        }));
                    },
                    success: function (){
                        content.$el.html("You data is saved successfully! Please wait until we redirect you to the page of the saved role!");
                        setTimeout(function (){
                            controller.read(role.id); 
                        }, 2000);
                    }
                });
            }, this);  
            form.render();
            content.$el.html(form.$el);
        }
    }
});
4

1 に答える 1

0

この問題を解決するためにカスタム ビューを作成しました。(現在ベータ版です。)

使用法: (フォームは理論上のフォーム ジェネレーターです)

var content = new SyncLabelDecorator({
    appendTo: "body",
});

content.load(function (){
    this.$el.append("normal html without asnyc calls");
});

var User = Backbone.Model.extend({
    urlRoot: "/users"
});
var UserSet = Backbone.Collection.extend({
    url: "/users",
    model: User
});
var Role = Backbone.RelationalModel.extend({
    relations: [{
        type: Backbone.HasMany,
        key: 'members',
        relatedModel: User
    }]
});

var administrator = new Role({id :1});
var users = new UserSet();

content.load({
    fetch: [role, users],
    sync: function (){
        var form = new Form({
            title: "Update role",
            model: role,
            fields: {
                id: {
                    type: "HiddenInput"
                },
                name: {
                    type: "TextInput"
                },
                members: {
                    type: "TwoListSelection",
                    alternatives: users
                }
            },
            submit: function (){
                content.load({
                    tasks: {
                        save: role
                    },
                    sync: function (){
                        this.$el.html("Role is successfully saved.");
                    }
                });
            }
        });
        this.$el.append(form.render().$el);
    }
});

コード:

var SyncLabelDecorator = Backbone.View.extend({
    options: {
        pendingMessage: "Sending request. Please wait ...",
        errorMessage: "An unexpected error occured, we could not process your request!",
        load: null
    },
    supported: ["fetch", "save", "destroy"],
    render: function () {
        if (this.options.load)
            this.load();
    },
    load: function (load) {
        if (load)
            this.options.load = load;
        this._reset();
        if (_.isFunction(this.options.load)) {
            this.$el.html("");
            this.options.load.call(this);
            return;
        }
        _(this.options.load.tasks).each(function (models, method) {
            if (_.isArray(models))
                _(models).each(function (model) {
                    this._addTask(model, method);
                }, this);
            else
                this._addTask(models, method);
        }, this);
        this._onRun();
        _(this.tasks).each(function (task) {
            var model = task.model;
            var method = task.method;
            var options = {
                beforeSend: function (xhr, options) {
                    this._onRequest(task, xhr);
                }.bind(this),
                error: function (xhr, statusText, error) {
                    this._onError(task, xhr);
                }.bind(this),
                success: function (data, statusText, xhr) {
                    this._onSync(task, xhr);
                }.bind(this)
            };
            if (model instanceof Backbone.Model) {
                if (method == "save")
                    model[method](null, options);
                else
                    model[method](options);
            }
            else {
                if (method in model)
                    model[method](options);
                else
                    model.sync(method == "fetch" ? "read" : (method == "save" ? "update" : "delete"), model, options);
            }
        }, this);
    },
    _addTask: function (model, method) {
        if (!_(this.supported).contains(method))
            throw new Error("Method " + method + " is not supported!");
        this.tasks.push({
            method: method,
            model: model
        });
    },
    _onRun: function () {
        this.$el.html(this.options.pendingMessage);
        if (this.options.load.request)
            this.options.load.request.call(this);
    },
    _onRequest: function (task, xhr) {
        task.abort = function () {
            xhr.abort();
        };
    },
    _onError: function (task, xhr) {
        this._abort();
        this.$el.html(this.options.errorMessage);
        if (this.options.load.error)
            this.options.load.error.call(this);
    },
    _onSync: function (task, xhr) {
        ++this.complete;
        if (this.complete == this.tasks.length)
            this._onEnd();
    },
    _onEnd: function () {
        this.$el.html("");
        if (this.options.load.sync)
            this.options.load.sync.call(this);
    },
    _reset: function () {
        this._abort();
        this.tasks = [];
        this.complete = 0;
    },
    _abort: function () {
        _(this.tasks).each(function (task) {
            if (task.abort)
                task.abort();
        });
    }
});
于 2013-06-13T15:01:41.057 に答える