0

I'm getting a small array of topics from the backend, using a resolver. I've customised the getAll() method to retrieve it from my local server. I'm getting the full array in the modified method when I log it, but when I use the entityService entities$ observable, I only get the first item of the array. What am I doing wrong?

import { Component, OnInit } from '@angular/core';
import { Topic } from 'src/app/models/topic.model';
import { FormGroup, FormControl, Validators } from '@angular/forms';
import { GroupService } from 'src/app/services/group.service';
import { Observable } from 'rxjs';
import { TopicEntityService } from './ngrx/topic-entity.service';
import { map } from 'rxjs/operators';

@Component({
    selector: 'app-home',
    templateUrl: './home.component.html',
    styleUrls: ['./home.component.sass']
})
export class HomeComponent implements OnInit {
    form: FormGroup;
    username: string;
    topics$: Observable<Topic[]>;

    constructor(private groupService: GroupService, private topicService: TopicEntityService) { }

    ngOnInit() {
        this.form = new FormGroup({
            'topic': new FormControl('', { validators: [Validators.required] })
        });
        this.topics$ = this.topicService
            .entities$
            .pipe(
                map(topics => {
                    console.log(topics);
                    return topics;
                })
            );
    }

The modified dataService method:

import { Injectable } from '@angular/core';
import { DefaultDataService, HttpUrlGenerator } from '@ngrx/data';
import { Topic } from 'src/app/models/topic.model';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';

@Injectable()
export class TopicsDataService extends DefaultDataService<Topic> {

    constructor(http: HttpClient, httpUrl: HttpUrlGenerator) {
        super('Topic', http, httpUrl);
    }
    getAll(): Observable<any> {
        return this.http.get('http://localhost:3000/api/topics')
            .pipe(
                map(res => {
                    console.log(res);
                    return res;
                })
            );
    }
}

The resolver :

import { Injectable } from '@angular/core';
import { Resolve, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { TopicEntityService } from './topic-entity.service';
import { Observable } from 'rxjs';
import { tap, filter, first } from 'rxjs/operators';


@Injectable()
export class HomeResolver implements Resolve<boolean> {

    constructor(private topicService: TopicEntityService) { }

    resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {

        return this.topicService.loaded$
            .pipe(
                tap(loaded => {
                    if (!loaded) {
                        this.topicService.getAll();
                    }
                }),
                filter(loaded => !!loaded),
                first()
            );
    }
}

I've modified the array in the backend, and it now works as intended. I'd still like to know what was wrong before. I'm assuming ngrx data expects a certain format for the data it receives?

Previous array in backend:

exports.getTopics = (req, res) => {
    try {
        const topics = [{
                name: 'Politics',
                info: 'Keep up with the latest news'
            },
            {
                name: 'Arts',
                info: 'Music, Litterature, Cinema...'
            },
            {
                name: 'Sports',
                info: 'Will there ever be another Bergkamp?'
            },
            {
                name: 'Health',
                info: 'What is going on inside you?'
            },
            {
                name: 'Crafts',
                info: 'If you make things with your hands'
            },
            {
                name: 'Home',
                info: 'Tips and tricks to improve your home'
            },
            {
                name: 'Travel',
                info: 'Where next?'
            }
        ];
        res.status(200).send(topics);

    } catch (error) {
        res.status(500).send(error);
    }

};

Modified array in backend:

exports.getTopics = (req, res) => {
    try {
        const topics = {
            1: {
                id: 1,
                name: 'Politics',
                info: 'Keep up with the latest news'
            },
            2: {
                id: 2,
                name: 'Arts',
                info: 'Music, Litterature, Cinema...'
            },
            3: {
                id: 3,
                name: 'Sports',
                info: 'Will there ever be another Bergkamp?'
            },
            4: {
                id: 4,
                name: 'Health',
                info: 'What is going on inside you?'
            },
            5: {
                id: 5,
                name: 'Crafts',
                info: 'If you make things with your hands'
            },
            6: {
                id: 6,
                name: 'Home',
                info: 'Tips and tricks to improve your home'
            },
            7: {
                id: 7,
                name: 'Travel',
                info: 'Where next?'
            }
        };
        res.status(200).send(Object.values(topics));

    } catch (error) {
        res.status(500).send(error);
    }

};
Chris
  • 31
  • 7

1 Answers1

0

In your resolver, you're using first() in the pipe. Which will return the first value emitted. Try to remove that first().

Yesub
  • 437
  • 6
  • 17
  • the first value emitted is the whole array. the first() operator makes sure that once the array is loaded, the observable completes. – Chris Oct 25 '19 at 11:27
  • From what I see from your modification, you where sending back an array, so the first() was returning the first occurence and that's it. Now, your topics is no more an array, it's an object, so the first() operator is returning the whole object. – Yesub Oct 25 '19 at 11:36
  • Yes, that seems to be the case indeed. I would have thought that the array itself was one value, but clearly that's not the case. – Chris Oct 25 '19 at 11:55
  • Although I'm still returning an array from the backend with Object.values()...so it's a bit confusing. – Chris Oct 25 '19 at 12:04
  • No. In your second version, 'topics' is not an array, it's an object. An array is something with [ ], in your second version you send something with { }, more like a javascript object. – Yesub Oct 26 '19 at 13:28
  • Object.values() returns an array. – Chris Oct 26 '19 at 18:55