ngxs-labs / firestore-plugin

Firestore plugin for NGXS
https://ngxs-firebase-plugin.netlify.com/
MIT License
20 stars 14 forks source link

Unable to use ngxs-labs/storage in conjunction with ngxs-labs/firestore-plugin + Timestamp? #24

Closed jaytonic closed 3 years ago

jaytonic commented 3 years ago

Hi,

I've a firestore collection, 2 fields of each document are "Timestamps" of firestore.

So I've my model:

export interface Trip {
  id: string;
  owner: string;
  name: string;
  startDate: Timestamp ;
  endDate: Timestamp;
}

the firestore configuration configuration:

@Injectable({
  providedIn: 'root',
})
export class TripsFirestore extends NgxsFirestore<Trip> {
  protected path = 'trips';

}

and my state:

export interface TripsStateModel {
  trips: Trip[];
  activeTrip: string | null;
}
@State<TripsStateModel>({
  name: 'trips',
  defaults: {
    trips: [],
    activeTrip: null,
  },
})
@Injectable()
export class TripsState implements NgxsOnInit, OnDestroy {
  @Selector()
  static getTrips(state: TripsStateModel) {
    return state.trips;
  }

  @Selector()
  static activeTrip(state: TripsStateModel) {
    return state.trips.filter((t) => t.id === state.activeTrip)[0];
  }
  constructor(
    private tripsFirestore: TripsFirestore,
    private ngxsFirestoreConnect: NgxsFirestoreConnect
  ) {}

  ngOnDestroy(): void {}

  ngxsOnInit(ctx?: StateContext<any>) {
    this.ngxsFirestoreConnect.connect(LoadTripsAction, {
      to: (action) => {
        const uid = firebase.auth().currentUser.uid;
        return this.tripsFirestore.collection$((ref) => ref.where('owner', '==', uid));
      },
    });
  }

  @Action(StreamEmitted(LoadTripsAction))
  getAllEmitted(ctx: StateContext<TripsStateModel>, { action, payload }: Emitted<LoadTripsAction, Trip[]>) {
    console.log(payload[0].startDate);
    ctx.patchState({ trips: payload });
  }

  @Action(StreamEmitted(CreateTripAction))
  createTrip(ctx: StateContext<TripsStateModel>, { action, payload }: Emitted<CreateTripAction, Trip>) {
    const state = ctx.getState();
    ctx.patchState({ trips: [payload, ...state.trips] });
  }

  @Action(SetActiveTrip)
  setActiveTrip(ctx: StateContext<TripsStateModel>, action: SetActiveTrip) {
    ctx.patchState({ activeTrip: action.tripId });
  }
}

If I use it without the storage-plugin, it works fine.

If I use it with the storage-plugin, it works fine the first time, but then when I reload the page, in the components where I'm using the ToDate() method of the Timestamp to display it nicely with the date pipe, I get this error: ERROR TypeError: trip_r1.startDate.toDate is not a function

I'm not sure where I should put this issue since it only happens with firestore Timestamp field.

Am I doing something wrong?

joaqcid commented 3 years ago

hi @jgrossrieder , sorry for the late response

i think the storage plugin doesn't serialize classes, which is the case of the firestore.Timestamp, that's why when you reload the page, you get the error, @markwhitfeld can you confirm this is the case?

it might be tricky to use the storage plugin with the Timestamp

jaytonic commented 3 years ago

I'm open to changing my model to something else, but I'm not sure how to transform one to the other in the firebase plugin?

joaqcid commented 3 years ago

well you can transform the timestamp value to a number, using the firestore.converter and that should work, but i dont think its a good idea.

the other thing you can do is filter out the TripsState from the Storage plugin, or you can remove Storage plugin and use the firebase enablePersistence

jaytonic commented 3 years ago

Why do you think it's a bad idea?

The thing is that I need those data persisted, so I cannot just filter out TripState.

What would be the downside of using firebase persistance and not the one of NGXS ?

joaqcid commented 3 years ago

i think it's a bad idea because you would save a date as a number in the database, and you will lose the data helper methods that come with the Timestamp type, also you will need to remember to make the conversions

so, using firebase persistance will enable offline capabilities for firestore queries, meaning you would get results even if you dont have internet,

ngxs plugin, serializes the complete state, and reloads it on every refresh, i guess if you just use firebase persistances, you will lose data on other states that dont use firebase when you reload

jaytonic commented 3 years ago

Okay, that seems a fair workaround then! Thank you for your support!