0

複数のエントリ ビューを含むネストされたエントリ ビューを使用して、to do ビューで構成される to do リストを実装しようとしています。各エントリは削除できるため、コンテナ ビューから削除できます。

私のRailsアプリに接続すると、これはほとんど機能します。削除ボタンがクリックされると (またはコンソールで App.ToDoEntry.find(x).deleteRecord() がトリガーされると)、インスタンスは isDirty=true に設定されますが、エントリは引き続きビューに表示されます。

何が起こっているのかをテストするために、Fixtures を使用して別の jsfiddle を作成し、それを単独で動作させることができるかどうかを確認しました。そうすることで、Ember データのフィクスチャのバグにも遭遇した可能性があると思います。

まず、これが私が取り組んできた Rails + Ember アプリです。

レール

class ToDo < ActiveRecord::Base
  has_many :to_do_entries, dependent: :destroy  
  attr_accessible :is_deleted, :is_staging, :is_template, :title
  validates_presence_of :title
end

class ToDoSerializer < ActiveModel::Serializer
  attributes :id,
             :title

  has_many :to_do_entries, embed: :objects
end

class ToDoEntry < ActiveRecord::Base  
  belongs_to :to_do
  attr_accessible :completed_at, :is_deleted, :priority, :title
  validates_presence_of :to_do, :title
end

class ToDoEntrySerializer < ActiveModel::Serializer
  attributes :id,
             :to_do_id,
             :title,
             :priority
end

残り火

/*---------------*/
/* Application   */
/*---------------*/

PLURAL_MAPPINGS = {"to_do_entry": "to_do_entries"};

App = Em.Application.create({
  rootElement: '#content',
  store: DS.Store.create({
    adapter:  DS.RESTAdapter.create({ plurals: PLURAL_MAPPINGS }),
    revision: 4
  })
});

/*---------------*/
/* Controllers   */
/*---------------*/

App.TodoController = Ember.ObjectController.extend({
  destroy: function() {
    this.transaction = App.store.transaction();
    this.transaction.add(this.get('content'));
    if (window.confirm("Are you sure you want to delete?")) { 
      this.get('content').deleteRecord();
      this.transaction.commit();
      App.router.transitionTo('todo');
    }
    else{
      this.transaction.rollback();
      this.transaction = null;
    }
  }
});

App.Todo_entriesController = Ember.ArrayController.extend();

App.Todo_entryController = Ember.ObjectController.extend({
  destroy: function() {
    this.transaction = App.store.transaction();
    this.transaction.add(this.get('content'));
    if (window.confirm("Are you sure you want to delete?")) { 
      this.get('content').deleteRecord();
      this.transaction.commit();
      App.router.transitionTo('todo');
    }
    else{
      this.transaction.rollback();
      this.transaction = null;
    }
  }
});

/*--------*/
/* Models */
/*--------*/

App.ToDo = DS.Model.extend({
  title: DS.attr('string'),
  group: DS.belongsTo('App.Group'),
  to_do_entries: DS.hasMany('App.ToDoEntry', { embedded: true })
});

App.ToDoEntry = DS.Model.extend({
  title: DS.attr('string'),
  to_do_id: DS.attr('number'),
  priority: DS.attr('number'),
  todo: DS.belongsTo('App.ToDo')
});

/*-------*/
/* Views */
/*-------*/ 

App.TodoView = Ember.View.extend({
  templateName: 'app/templates/todo'
});

App.Todo_entriesView = Ember.View.extend({
  templateName: 'app/templates/todo_entries'
});

App.Todo_entryView = Ember.View.extend({
  templateName: 'app/templates/todo_entry',
  destroyEntry: function() {
    console.log('Todo_entryView - destroyEntry');
    this.get('controller').destroy();
  },
  init: function(){
    this._super();
    this.set(
      'controller',
      App.Todo_entryController.create({ content: this.get('content') })
    );
  }  
});  

/*-----------*/
/* Templates */
/*-----------*/ 

todo.hbs

<article>
  <h1>{{title}}</h1>  
  <div class="widget_links">
    <a {{action destroy target="view"}}>Delete</a>
  </div>
  {{outlet}}
</article>

todo_entries.hbs

{{#if isLoading}}
  <p>Loading...</p>
{{else}}
  <ul class="list">
  {{collection contentBinding="content" itemViewClass="App.Todo_entryView"}}
  </ul>
{{/if}}

todo_entry.hbs

<li>
{{#if isLoading}}
  Loading...
{{else}}
  {{view.content.id}}) {{view.content.title}} Priority: {{view.content.priority}}
  <a {{action destroyEntry href="true" target="view"}}>Delete</a>
{{/if}}
</li>

/*--------*/
/* Router */
/*--------*/

App.Router = Ember.Router.extend({
  enableLogging: true,
  location: 'hash',
  root: Ember.Route.extend({
    index: Ember.Route.extend({
      route: '/',
      connectOutlets: function(router) {
        var todo = App.ToDo.find(21);
        router.get('applicationController').connectOutlet('todo', todo);
        var todoController = router.get('todoController');
        todoController.connectOutlet('todo_entries', todoController.get("to_do_entries"));
      }
    })
  })
}); 

App.initialize();

前述のように、これはほぼ機能しますが、イライラすることにビューからエントリが削除されないようです。ここで明らかに間違ったことをしていますか、それともバグですか?

備品のバグ?

次に、フィクスチャを使用して動作するバージョンを作成しました。ただし、App.ToDo.find() (つまり、findAll) が要求されない限り、フィクスチャ データは読み込まれないようです。

以下に 2 つの例を示します。

実行するのは 1 つで、削除に失敗します。

http://jsfiddle.net/danielrosewarne/vDGhe/1/

1 つ目は、関連付けられたエントリを使用して、単一の to do を読み込みます。「削除」をクリックすると、警告が正しく表示され、オブジェクトが無効になります。ただし、エントリはビューに残ります。

コンソールをオンにして表示すると、isDirty 状態が true に設定されていることがわかります。

やることが複数あり、すべて問題ありません

http://jsfiddle.net/danielrosewarne/LeLyy/1/

2 つ目は、すべての To Do レコードをインデックス ビューに一覧表示することで、思われるデータを事前に読み込みます。to do をクリックしてエントリを表示すると、期待どおりに削除が機能します。(ちなみに、これは、例 1 のコンソールで App.ToDo.find() を実行するだけでも機能します。)

これは Ember データのバグのように感じます。私は正しいのでしょうか、それとも何か間違っているのでしょうか?

ありがとう、

ダン

4

1 に答える 1

0

transaction.commit() は非同期ですが、ルート内の別の状態にすぐに移行しています。トランザクションが完了する前にビューが更新されています。これが問題だと思います。あるいは、少なくとも 1 つの問題だと思います。非同期操作に関しては、Ember は非常に注意が必要です。これを試して:

App.Todo_entryController = Ember.ObjectController.extend({
  destroy: function() {
    this.transaction = App.store.transaction();
    this.transaction.add(this.get('content'));
    if (window.confirm("Are you sure you want to delete?")) { 
      this.get('content').deleteRecord();
      this.get('content').one('didDelete', function() {
        App.router.transitionTo('todo');
      });
      this.transaction.commit();
    }
    else{
      this.transaction.rollback();
      this.transaction.delete();
    }
  }
});

また、この機能全体は、状態が変化するため、コントローラーではなくルーターにある必要があります。ルーターに差し込むと状態変化を埋めてしまいます。

乾杯。

于 2012-12-22T01:38:55.173 に答える