2017-02-13 3 views
0

Я хочу отсортировать список вещей по наблюдаемому полю, но не могу обернуть голову вокруг наблюдаемых, чтобы заставить это работать. Кто-нибудь знает, как это достичь?angular2 rxjs порядок (наблюдаемый) список объектов по наблюдаемому полю

Исходная ситуация - это что-то вроде следующего.

Thing[] things; 

interface Thing { 
    name: Observable<string> 
} 
<ul> 
    <li *ngFor="const thing for things"> 
    {{thing.name | async}} 
    </li> 
</ul> 

EDIT: Так как я, очевидно, не описал мою проблему правильно: поле я хочу, чтобы отсортировать список вещей на это Observable, а не простая строка. Я хочу, чтобы поле обновлялось через веб-порты, поэтому, чтобы правильно определить изменения, я должен использовать поле Observable, на котором я могу подписаться.

+0

Какова идея наличия имени в качестве наблюдаемого ? Я думаю, вы хотите оставить это свойство как обычную строку –

+0

Я хочу использовать это поле как наблюдаемое, так как это значение может измениться во время выполнения. – sclausen

+0

Phosphoros, вы не подписываетесь на 'имя' или' Thing', но на список вещей ('Observable ') –

ответ

5

Спасибо за уточняющий вопрос, Фосфор. :)

Вот как вы могли бы сделать то, что вы просили:

// Function to compare two objects by comparing their `unwrappedName` property. 
const compareFn = (a, b) => { 
    if (a.unwrappedName < b.unwrappedName) 
    return -1; 
    if (a.unwrappedName > b.unwrappedName) 
    return 1; 
    return 0; 
}; 

// Array of Thing objects wrapped in an observable. 
// NB. The `thing.name` property is itself an observable. 
const thingsObs = Observable.from([ 
    { id: 1, name: Observable.of('foo') }, 
    { id: 2, name: Observable.of('bar') }, 
    { id: 3, name: Observable.of('jazz') } 
]); 

// Now transform and subscribe to the observable. 
thingsObs 

    // Unwrap `thing.name` for each object and store it under `thing.unwrappedName`. 
    .mergeMap(thing => 
    thing.name.map(unwrappedName => Object.assign(thing, {unwrappedName: unwrappedName})) 
) 

    // Gather all things in a SINGLE array to sort them. 
    .toArray() 

    // Sort the array of things by `unwrappedName`. 
    .map(things => things.sort(compareFn)) 

    .subscribe(); 

Logging испускаемые значения консоли покажет массив объектов Thing, отсортированных по их unwrappedName собственности:

[ 
    { id: 2, name: ScalarObservable, unwrappedName: "bar" }, 
    { id: 1, name: ScalarObservable, unwrappedName: "foo" }, 
    { id: 3, name: ScalarObservable, unwrappedName: "jazz" } 
] 

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

+0

Awesome, большое спасибо! Этот пример не сработал (не вызывая ошибки!), Потому что compareFn должен быть объявлен перед использованием. – sclausen

+0

Добро пожаловать. Я реорганизую код, начинающийся с декларации 'compareFn'. – AngularChef

0

Вы можете использовать Observable.map. Например:

Observable<Thing[]> things; 
sortedThings$ = things.map(items => items.sort()) // Use your own sort function here. 

В шаблоне:

<ul> 
    <li *ngFor="let thing of sortedThings$ | async"> 
    {{thing.name}} <!--No need async pipe here. --> 
    </li> 
</ul> 
+0

К сожалению, это не помогает, так как меня интересует эта мелочная деталь, как сортировать по наблюдаемому полю. – sclausen

+0

@Phosphoros. Ваш комментарий не очень ясен. Для меня это похоже, что Туонг Ле ответил точно на вопрос, который вы задали. Будьте более конкретными, если вы считаете, что его ответ не делает этого трюка. – AngularChef

+0

@AngularFrance «Я хочу отсортировать список вещей по наблюдаемому полю [...]», разве это недостаточно ясно?Проблемой является наблюдаемое поле для сортировки. – sclausen

0

Если я вас правильно понял, вы хотите иметь объект, который выглядит следующим образом:

Thing { 
    name: string; 
} 

Вы тогда хотите имеют Наблюдаемое значение, которое имеет место на массиве Thing:

things$: Observable<Thing[]>; 

Затем вы хотите отсортировать ваши вещи в thing array за счет имущества, в данном случае name. Это может быть сделано так:

... 

let sorted$: Observable<Thing[]> = things$.map(items => items.sort(this.sortByName)) 

... 

sortByName(a,b) { 
    if (a.name < b.name) 
    return -1; 
    if (a.name > b.name) 
    return 1; 
    return 0; 
} 

... 

И, наконец, как Toung Ле показал в своем ответе, изменить шаблон, как это:

<ul> 
    <li *ngFor="let thing of sorted$ | async"> 
    {{thing.name}} <!--No need async pipe here. --> 
    </li> 
</ul> 
+0

Большое спасибо за обширный ответ, но поле имени, которое я хочу сортировать, не является строкой, а Observable , так как это поле может быть изменено в базе данных и затем будет автоматически обновляться. – sclausen

+0

@Phosphoros, хм, это все еще звучит странно для меня. Можете ли вы, возможно, обновить свой вопрос, чтобы показать нам, как данные, над которыми вы работаете, выглядят? –

Смежные вопросы