Skip to content
View lessons Login
3d cartoon hands holding a phone

Unlock full course by purchasing a membership

Creating a Messages Service to Interact with Firestore

Creating a Messages Service to Interact with Firestore

Once again, our usual approach is to start with the “main” feature of the application. Although we will eventually have things like login and account creation, the main purpose of our application is creating and displaying messages. Let’s start there.

Create an Interface for messages

export interface Message {
author: string;
content: string;
created: string;
}

Creating the Message Service

import { Injectable, computed, inject, signal } from '@angular/core';
import { Observable, merge } from 'rxjs';
import { collection, query, orderBy, limit } from 'firebase/firestore';
import { collectionData } from 'rxfire/firestore';
import { map } from 'rxjs/operators';
import { connect } from 'ngxtension/connect';
import { Message } from '../interfaces/message';
import { FIRESTORE } from '../../app.config';
interface MessageState {
messages: Message[];
error: string | null;
}
@Injectable({
providedIn: 'root',
})
export class MessageService {
private firestore = inject(FIRESTORE);
// sources
messages$ = this.getMessages();
// state
private state = signal<MessageState>({
messages: [],
error: null,
});
// selectors
messages = computed(() => this.state().messages);
error = computed(() => this.state().error);
constructor() {
// reducers
const nextState$ = merge(
this.messages$.pipe(map((messages) => ({ messages })))
);
connect(this.state).with(nextState$);
}
private getMessages() {
const messagesCollection = query(
collection(this.firestore, 'messages'),
orderBy('created', 'desc'),
limit(50)
);
return collectionData(messagesCollection, { idField: 'id' }).pipe(
map((messages) => [...messages].reverse())
) as Observable<Message[]>;
}
}

Once again we have our basic state management setup, except this time we are using the connect function that we covered in the advanced state management module.

To quickly recap, this is essentially the same idea as our normal reducers that we have been creating:

constructor() {
// reducers
const nextState$ = merge(
this.messages$.pipe(map((messages) => ({ messages })))
);
connect(this.state).with(nextState$);
}

Except rather than subscribing and calling state.update with the source values, instead we map those values and return an object with whatever values we want to set in the state. In this case, we return { messages } because we want to update the

EXTENDED EXTENDED

Thanks for checking out the preview of this lesson!

You do not have the appropriate membership to view the full lesson. If you would like full access to this module you can view membership options (or log in if you are already have an appropriate membership).