EmberJS Computed.sort — сортировка по связанному свойству модели

У меня есть простые отношения модели belongsTo:

контракт.js:

export default DS.Model.extend({
    object               : DS.belongsTo('object'),
    ....
})

объект.js:

export default DS.Model.extend({
    street              : DS.attr('string'),
    zip                 : DS.attr('string'),
    city                : DS.attr('string'),
    ...
})

В моем контроллере для объекта, который содержит много contracts, я хотел бы отсортировать по названию улицы связанного object, но почему-то это

export default Ember.Controller.extend({

    sortOrder: ['object.street'],
    sortedObjects: Ember.computed.sort('model.contracts', 'sortOrder')

    ...
});

не работает.

Использование пользовательской функции компаратора а-ля

function(a, b){
    if (a.street > b.street) {
      return 1;
    } else if (a.street < b.street) {
      return -1;
    }
}

Я узнал, что a и b это Promises, но как-то не вижу, как их отсортировать по вложенному атрибуту (улице объекта)

Редактировать

Чтобы немного уточнить код:

contracts : Ember.computed.alias('model.contracts'),
street: Ember.computed.alias('realty.street'),

sortOrder: ['realty.street'],
sortedOwnedRealties: Ember.computed.sort('[email protected]', function (a, b) {
    console.log(Ember.get(a, 'id'));
    console.log(Ember.get(a, 'street'));

    //return 1;
})

Эта функция выводит на консоль undefined для street, но правильный id.

Я переименовал object в realty для ясности.


person Julian Rubisch    schedule 05.10.2016    source источник


Ответы (1)


Вероятно, это PromiseObject, то есть оба, Ember.Object и Promise. Есть несколько вещей, которые вы делаете, что может быть не очень хорошей идеей:

Первое object является зарезервированным ключевым словом. Не рекомендуется иметь модель или связь с именем object, даже если это может сработать.

Во-вторых, ваше вычисляемое свойство имеет неправильный ключ зависимости. На самом деле вам нужно что-то вроде '[email protected]' вместо 'modelcontracts', однако это не будет работать, потому что '@each.a.b' не поддерживается. Решение состоит в том, чтобы создать псевдоним улицы в контракте:

street: Ember.computed.alias('object.street'),

И тогда вы можете использовать это как ключ зависимости: [email protected].

Затем в вашей пользовательской функции компаратора вы получаете доступ к a.street с помощью записи через точку. Это не будет работать и ненадежно для объектов Ember. Всегда используйте .get() для доступа к свойствам:

import Ember form 'ember';
const {get} = Ember;


function(a, b){
  if(get(a, 'street') > get(b, 'street')) {...}
}

Однако также обратите внимание, что без computed.alias, о котором я упоминал выше, это не get(a, 'street'), а get(a, 'object.street').


Проблема, почему ваш код не работает, вероятно, заключается в том, что object загружается асинхронно, и поэтому во время оценки вашего CP улица еще не загружена. Добавление правильного ключа зависимости, вероятно, исправит это.

person Lux    schedule 05.10.2016
comment
Извините, свойство object появилось из-за того, что я слишком сильно упростил код. Конечно, он не называется object. И у меня была еще одна опечатка в model.contracts. Я чувствую, что становлюсь ближе, но не совсем - см. редактирование выше. - person Julian Rubisch; 05.10.2016
comment
Вы должны добавить street: Ember.computed.alias('realty.street') к contract.js рядом с realty:DS.belongsTo('realty'), а не туда, где у вас есть CP сортировки. - person Lux; 06.10.2016
comment
Спасибо! Используя более простую версию, я даже сузил ее до: sortOrder: ['street'], sortedOwnedRealties: Ember.computed.sort('contracts', 'sortOrder') - person Julian Rubisch; 07.10.2016