隐藏模板中的已删除记录

时间:2018-08-23 12:00:08

标签: ember.js websocket ember-data

我试图找出是否有更好的方法可以从模板中隐藏已删除的记录,并将其从计算的属性中删除。我的ember应用正在监听Web套接字,如果另一个用户删除了一条记录,则有一个处理程序将从存储中删除该记录:

_handleDelete({id, type: modelName}) {
  const record = get(this, 'store').peekRecord(modelName, id);

  if (record) {
    get(this, 'store').deleteRecord(record);
  }
}

我当前正在做的是定义一个计算属性,该属性会过滤掉isDeleted为true的所有记录,并将其用于其他集合:

allItems: computed.filter('items.@each.isDeleted', function(item) {
  return !get(item, 'isDeleted');
}),

然后我正在使用此计算属性来构建其他计算属性:

materialCosts: computed.filterBy('allItems', 'proposalCostType', 'material'),

这很好,但是我遇到的问题是我不是从这个开始的,所以我的许多模板都直接引用hasMany关系(items),而不是过滤后的集合({ {1}})。这是一个巨大的应用程序,因此我必须更新大量模板才能使其正常运行,而且我认为这样做并不省时。

我从不希望已删除的记录显示在模板中,也不希望任何计算出的属性能够引用它们,因此,理想情况下,我将能够执行allItems关系自动过滤的操作删除记录,并在删除记录时进行更新。

我正在使用Ember Data 2.14,所以也许有更新的版本可以做到这一点? 更新-还尝试在2.18上查看它是否是我使用的版本。

修改

我尝试了@Gennady Dogaev在下面建议的卸载记录而不是删除记录的方法,但是ember给我的错误是正在监视集合的计算属性。例如,这个:

items

...给我一个错误,无法在未定义的对象上调用approvableItems: computed('items.[]', function() { return get(this, 'items').filterBy('isApprovable'); }),

4 个答案:

答案 0 :(得分:3)

如果其他用户删除了记录,则从存储中unload条记录会更正确。之后,模板将停止呈现它,就像它从未在商店中一样。

在这种情况下,我不建议使用deleteRecord,因为它会弄脏余烬存储中的数据。您应该在调用record.save()之后再调用deleteRecord,但是在描述的情况下,它将向API发送http请求,我认为您不希望这样做。


在某些情况下,您可能会遇到js隐秘错误:

  1. 如果您尝试将具有相同ID的新记录推送到存储中
  2. 如果用户尝试重新访问尝试加载已删除/已卸载记录的路由。这可以通过在浏览器中使用后退/前进按钮来实现

如果在这些情况下遇到一些错误,请尝试使用以下方法卸载记录:

/**
 * This function unloads record from store and clears some private internals to avoid errors when UI tries to read
 * unloaded record from store
 *
 * @see https://discuss.emberjs.com/t/reusing-ids-for-soft-deleted-records/13715/6
 * @param store
 * @param model
 * @param id
 */
export default function(store, model, id) {
  let record, recordId, modelName;
  if (typeof model === 'object' && typeof model.get === 'function') {
    record = model;
    recordId = model.get('id') || id;
    modelName = model.constructor.modelName;
  } else {
    recordId = id;
    modelName = model;
    record = store.peekRecord(modelName, recordId);
  }
  if (record && !record.isDeleted) {
    store.unloadRecord(record);
  }
  if (recordId) {
    delete store.get('_identityMap')._map[modelName]._idToModel[recordId];
  }
}

我不知道是否仍需要最新版本,但不久前我需要此代码。

答案 1 :(得分:1)

您可以创建模板帮助程序,并像{{#each items}}一样包装{{#each (only-active items)}}

答案 2 :(得分:1)

您可以尝试结合内置帮助器unlessisDeleted属性,直接在视图上排除已删除的记录:

https://www.emberjs.com/api/ember-data/3.3/classes/DS.Model上了解有关isDeleted的更多信息

app / routes / todos / index.js

import Ember from 'ember';

export default Ember.Route.extend(AuthenticatedRouteMixin, {
  model(params) {
    return Ember.RSVP.hash({
      todos: this.store.findAll('todos')
    });
  }
});

app / controllers / todos / index.js

export default Controller.extend({
  actions: {
    deleteMe(todo) {
      todo.deleteRecord();
      console.log('deleting todo ' + todo.id); // Just to see if the action works
    }
  }
});

app / templates / todos / index.hbs

{{#each model.todos as |todo|}}
  {{#unless todo.isDeleted}}
    <li>{{todo.title}} - <a {{action 'deleteMe' todo}}>delete me</a></li>
  {{/unless}}
{{/each}}

屏幕截图

unless with IsDeleted

您可以从https://github.com/hernanvicente/todos-placeholder

克隆我的示例代码

答案 3 :(得分:1)

一个简单的解决方案是做这样的事情。在您的template.hbs上执行一个

循环
  {{#each model as |todo|}}
    <li>{{todo.title}} - <a {{action 'removeRecord' todo}}>delete me</a></li>
  {{/each}}

如果您不希望在删除记录后立即显示记录,则只需执行以下操作。顺便说一句,下面是ember-cli 1.13

removeRecord(todo) {
  todo.destroyRecord().then(() => {
    this.send('reloadModel');
  });
}

reloadModel用于在删除记录后重新加载记录。但是,如果您的后端在发送删除记录的请求后确实删除了该记录,则一旦向您的API请求removeRecord,它就会删除您的数据。希望对您有帮助。