14

ほとんどのガイドが示すように、モデルが変更されたときに再描画にバインドする単純なビューがあります。

this.model.bind('change', this.render, this);

このビューには、入力ボックスと送信ボタンのあるフォームがあります。モデルの関連アイテムを変更するために、入力ボックスの「変更」イベントにバインドしています。(これは手動で行うことも、ModelBinder プロジェクトを使用して行うこともできます。どちらの方法でも同じように機能します。)

ユーザーはフォーム入力ボックスの値を変更し、送信ボタンをクリックします。モデルが更新され、ビューとフォームが再レンダリングされます。送信ボタンのクリック イベントが押しつぶされます。

Backbone の events プロパティを使用しています。

events : {
    'submit form' : 'save'
},

クリックされた DOM 要素が存在しなくなったため、イベントが無視されていることはわかっています。render() 内に小さな setTimeout を配置して、HTML がスワップ アウトされないようにし、期待どおりに動作するようにすることができますが、これには待機が必要です。

私はこれに苦労する最初の人になることはできません.フォームの「変更」イベントをキャプチャし、モデルを更新し、キークリックまたはキープレス情報を失うことなくビューを再描画する標準的な方法は何ですか?

同様に、複数のフォーム項目がある場合、フォームが再描画されるときに内容を変更した後、ユーザーは項目間でタブを移動できません。

更新 1 ~ 3 日後

まだ良い解決策を見つけようとしています。私が試したこと:

  • ビューのコンテンツをページ上の別の領域に移動または複製します。クリック イベントはまだ受信されません。
  • 標準のビュー イベント オブジェクトの代わりに $(document).on または $(document).live でクリック イベントを登録する
  • フォーム全体 (入力とボタン) が再描画されずにまとまるように、フォームを分離します。親要素 (フォームの値に依存する) を再描画し、既に描画されたフォームを再挿入します。これにより、要素をタブで移動できないという関連する問題が修正されますが、クリック イベントは修正されません。
  • Firefox 4 では希望どおりに動作しますが、ie9 や chrome では動作しません。*

更新 2 - サンプルコード付き

コメントの 1 つは、いくつかのコードを要求しました。コードを 1 ページに大幅に簡略化し、以下に含めました。実際のアプリケーションはもっと複雑です。以下のような単純なコードを使用すると、変更時にページの一部を手動で再レンダリングすることができます。実際のアプリケーションでは、dustjs テンプレートを使用しています。フォームを再レンダリングしなくても、フォームを含む要素を再レンダリングすると、送信をクリックする際に問題が発生します。複雑なページやモデル、フォームなど、バックボーン アプリケーションに典型的な「パターン」を期待しています。

ほとんどの「デモ」アプリやバックボーンを使用しているサイトでさえ、実際にはユーザーから多くの入力を収集していないプレゼンテーションに重点を置いたアプリのようです。バックボーンに基づいた優れたデータ収集に焦点を当てたアプリケーション/デモを知っていれば、それは役に立ちます。

コード:

<!doctype html>
<html lang="en">
<head>
    <script src="libs/jquery.js"></script>
    <script src="libs/underscore.js"></script>
    <script src="libs/backbone.js"></script>
</head>
<body>
<div id="container"></div>
<script type="text/template" id="edit_user_template">
    <h3>Edit User <%=id%> : <%=name%></h3>
    <form>
        Name: <input type="text" name="name" value="<%=name%>"><br/>
        Email: <input type="text" name="email" value="<%=email%>"><br/>
        <input type="submit">
    </form>
</script>
<script>
    var UserModel = Backbone.Model.extend({});
    var model = new UserModel({id: '1', name:'Joe', email:'a@a.com'});
    var UserView = Backbone.View.extend({
        events : {
            'submit form' : 'save',
            'change input' : 'inputChange'
        },
        initialize: function(){
            this.model.bind('change', this.render, this);
        },
        render: function(){
            var template = _.template($('#edit_user_template').html(), this.model.toJSON());
            this.$el.html(template);
        },
        inputChange : function(evt){
            var target = $(evt.currentTarget);
            this.model.set(target.attr('name'), target.val());
        },
        save : function(event){
            console.log('saving');
            event.preventDefault();
            //this.model.save();
        }
    });
    var view = new UserView({model: model, el: '#container'});
    view.render();
</script>
</body>
</html>
4

5 に答える 5

1

私が正しく理解している場合、あなたがする必要があるのは、ビューを2つの小さなビューに分割することです。1つは変更時に再レンダリングされ、もう1つはフォーム自体を表示します。

場合によっては、3番目のビューでこれら2つをバインドすることも必要ない場合もあります。

サイドコメント:

MVCデザインパターンを使用すると、再帰的になる傾向があります。そうだと思います。フォーム内のデータをモデル、再レンダリングビューをMVCの「ビュー」部分、フォームビューを「コントローラー」と考えてください。

于 2012-09-05T18:29:41.077 に答える
1

あなたは背骨のパターンを求めます。パターンは、モデルを使用してフォーム情報を保持し(実行しているように)、モデルが変更されるたびにすべてを再レンダリングするのではなく、ページ上の特定の要素を更新することです。ModelBinderは、これらすべてを実行するための優れた方法を提供します(https://github.com/theironcook/Backbone.ModelBinder)。

もう存在しないフォームを送信できないことを回避する方法を見つけるつもりはないと思います。あなたは別の方法であなたが望むことを達成する必要があります。

于 2012-08-29T17:36:26.493 に答える
0

この問題には、次の 2 つの解決策が考えられます。

  1. submit イベント自体ではなく、submit 入力をクリックするようにバインドします。

    events: { 'click input[type=submit]' : 'save' }

    これは、html を完全に置き換えても存続するはずです。

  2. レンダリング後に手動でイベントを再デリゲートします。これは通常、サブビューを持つビューを再レンダリングする場合に必要ですが、ここでも適用されます。

    this.delegateEvents()

于 2012-08-28T20:26:11.743 に答える
0

あなたがやろうとしていることをよく理解していません。コードを見て、knockoutjs のバインディング モデルをシミュレートしたいことがわかりました。これは素晴らしいことです。

とにかく、同じモデルで動作する 2 つのビューに分割すると、同様の «効果» を得ることができます。1 つはモデルを更新し、もう 1 つは変更と自動更新を監視します。

コードは次のとおりです。

<!doctype html>
<html lang="en">
<head>
    <script src="libs/jquery.min.js"></script>
    <script src="libs/underscore.min.js"></script>
    <script src="libs/backbone.min.js"></script>
</head>
<body>
    <div id="header"></div>
    <div id="container"></div>
<script type="text/template" id="user_template">
    <h3>Edit User <%=id%> : <%=name%></h3>
</script>
<script type="text/template" id="edit_user_template">
    <form>
        Name: <input type="text" name="name" value="<%=name%>"><br/>
        Email: <input type="text" name="email" value="<%=email%>"><br/>
        <input type="submit">
    </form>
</script>
<script>
    var UserModel = Backbone.Model.extend({});
    var model = new UserModel({id: '1', name:'Joe', email:'a@a.com'});

    var UserView = Backbone.View.extend({
        initialize: function(){
            this.model.on("change", this.render, this);
        },
        render: function(){
            var template = _.template($('#user_template').html(), this.model.toJSON());
            this.$el.html(template);
            return this;
        },
    });

    var FormView = Backbone.View.extend({
        events : {
            'submit form' : 'save',
            'keyup input' : 'inputChange'
        },
        render: function(){
            var template = _.template($('#edit_user_template').html(), this.model.toJSON());
            this.$el.html(template);
            return this;
        },
        inputChange : function(evt){
            console.log('change');
            var target = $(evt.currentTarget);
            this.model.set(target.attr('name'), target.val());
        },
        save : function(event){
            console.log('saving');
            event.preventDefault();
            //this.model.save();
        }
    });

    var user = new UserView({model: model, el: '#header'});
    user.render();

    var form = new FormView({model: model, el: '#container'});
    form.render();
</script>
</body>
</html>
于 2012-08-27T18:05:08.503 に答える
0

あなたの問題を解決するためにバックボーンに完全に依存するかどうかはわかりません。これは、バックボーンを使用して独自のコードを入力できる状況の 1 つだと思います。テンプレートを少し変更し、モデルの変更を聞いてから、ビューを再レンダリングする必要があるか、単に更新する必要があるかを判断できます。モデルがリセットされない限り、フォームパーツを再レンダリングしようとは思わない

<!doctype html>
<html lang="en">
<head>
<script src="libs/jquery.min.js"></script>
<script src="libs/underscore.min.js"></script>
<script src="libs/backbone.min.js"></script>
</head>
<body>
<div id="container"></div>
<script type="text/template" id="edit_user_template">
    <h3>Edit User <span class="f-id"><%=id%></span> : <span class="f-name"><%=name%></span></h3>
    <form>
        Name: <input type="text" name="name" value="<%=name%>"><br/>
        Email: <input type="text" name="email" value="<%=email%>"><br/>
        <input type="submit">
    </form>
</script>
<script>
    var UserModel = Backbone.Model.extend({});
    var model = new UserModel({id: '1', name:'Joe', email:'a@a.com'});
    var UserView = Backbone.View.extend({
        events : {
            'submit form' : 'save',
            'change input' : 'inputChange'
        },
        initialize: function(){
            //you could have the change event trigger updates instead of re-rendering the form
            //this.model.bind('change', this.update, this);
        },
        render: function(){
            var template = _.template($('#edit_user_template').html(), this.model.toJSON());
            this.$el.html(template);
        },
        inputChange : function(evt){
            var target = $(evt.currentTarget);
            this.model.set(target.attr('name'), target.val());
        },
        update:function(){
            // you could trigger other things here if you need other views to know what is going on.
            $(".f-id").text(this.model.get("id"));
            $(".f-name").text(this.model.get("name"));          
        },
        save : function(event){
            console.log('saving');
            this.update();
            event.preventDefault();
        }
    });
    var view = new UserView({model: model, el: '#container'});
    view.render();
</script>
</body>
</html>
于 2012-08-30T19:22:06.897 に答える