mesqueeb / vuex-easy-firestore

Easy coupling of firestore and a vuex module. 2-way sync with 0 boilerplate!
https://mesqueeb.github.io/vuex-easy-firestore
MIT License
234 stars 28 forks source link

Vue CLI basic example, demo app needed #98

Open januszj opened 5 years ago

januszj commented 5 years ago

First let me thank you for this interesting library. This is what I would need to start my simple project. But it would be great help if you could add simple demo app based on Vue CLI template. Especially for someone that starts with Vue and Firestore for first time, would be much easier to see what's going where in the code.

mesqueeb commented 5 years ago

@januszj This is exactly right. I'm actually planning a short demo app with video explanation. I already started the simple design for it. I think i'll release it in a week or two.

Vuex Easy Firestore was made with ♥ by Luca Ban.
If this library helped you in any way you can support me by buying me a cup of coffee.

pitw commented 5 years ago

This would be a great help for getting into vuex-easy-firestore. Please also include an example into demo app with firestore auth / querying user specific documents.

mesqueeb commented 5 years ago

Ok. I dont have enough hard drive real estate and my computer can’t currently handle filming my screen and webcam all at once it seems lol.

It’ll take a bit longer before i get the video out because i wanna get it right.

Please do in the mean time ask anything. Even simple questions are ok. I will do my best to help. Feel free to open issues.

Vuex Easy Firestore was made with ♥ by Luca Ban.
If this library helped you in any way you can support me by buying me a cup of coffee.

CelticParser commented 5 years ago

Hey, thnx for all the hard work! But for now, how about just supplying the demo app under a /demo directory or somewhere else(?). It be a great help - esp. a lot of us who are not getting how to even start with this (eg the config). Also, I thought Firestore has now fully implemented enablePersistence() across all devices - including Web??

Dinibewerbig commented 5 years ago

Wow, 2 month later and still no demo app. :-(

Dinibewerbig commented 5 years ago

Thanks! It's just to get an idea how to connect to firestore. Thanks a lot :-)

bpkennedy commented 5 years ago

Not sure if it's kosher to post on his behalf but I have an app that's public which demonstrates using and auth: https://gitlab.com/bpkennedy/kenshi-journal

preginald commented 5 years ago

Not sure if it's kosher to post on his behalf but I have an app that's public which demonstrates using and auth: https://gitlab.com/bpkennedy/kenshi-journal

Hey @bpkennedy I took a look at your code and was lost as I couldn't find any reference to dispatch('myModule/openDBChannel')

I want to do is return all documents inside a collection called contests. I've already created the store module called contest.js that contains the following:

const contests = {
  firestorePath: 'contests',
  firestoreRefType: 'collection', // or 'doc'
  moduleName: 'contestsData',
  statePropName: 'contests',
  namespaced: true, // automatically added

  // this object is your store module (will be added as '/myModule')
  // you can also add state/getters/mutations/actions
  state: {},
  getters: {},
  mutations: {},
  actions: {}
};

export default contests;

In my case where would the dispatch('_myModule_/openDBChannel') go?

Cheers

preginald commented 5 years ago

Hey @bpkennedy and everyone, I've managed to get it working. I referred to the sample app here https://github.com/mesqueeb/vuex-easy-firestore-sample-app

mesqueeb commented 5 years ago

@preginald Sorry for the late response.

dispatch('_myModule_/openDBChannel') can go anywhere you want. If you want to "retrieve your doc(s)" you can dispatch this.

Examples:

preginald commented 5 years ago

@preginald Sorry for the late response.

Thanks for responding @mesqueeb

This is an example of how I managed to get all docs in a collection

firebase.js

import * as Firebase from 'firebase/app';
import 'firebase/firestore';

const config = {
  apiKey: 'Abracadabra-alakazam',
  authDomain: 'mosportive-8f059.firebaseapp.com',
  databaseURL: 'https://mosportive-8f059.firebaseio.com',
  projectId: 'mosportive-8f059',
  storageBucket: 'mosportive-8f059.appspot.com',
  messagingSenderId: '007'
};

function initFirebase() {
  Firebase.initializeApp(config);
  return new Promise((resolve, reject) => {
    Firebase.firestore()
      .enablePersistence()
      .then(resolve)
      .catch(err => {
        if (err.code === 'failed-precondition') {
          reject(err);
          // Multiple tabs open, persistence can only be
          // enabled in one tab at a a time.
        } else if (err.code === 'unimplemented') {
          reject(err);
          // The current browser does not support all of
          // the features required to enable persistence
        }
      });
  });
}

export { Firebase, initFirebase };

store/index.js

import Vue from 'vue';
import Vuex from 'vuex';
import createEasyFirestore from 'vuex-easy-firestore';

Vue.use(Vuex);

import { Firebase, initFirebase } from '@/helpers/firebase.js';

import contests from './contests';
import events from './events';

const easyFirestore = createEasyFirestore([contests, events], {
  logging: true,
  FirebaseDependency: Firebase
});

// include as PLUGIN in your vuex store:
const storeData = {
  // ... your store
  plugins: [easyFirestore]
};
const store = new Vuex.Store(storeData);

// initFirebase
initFirebase().catch(error => {
  // take user to a page stating an error occurred
  // (might be a connection error, or the app is open in another tab)
  alert(error);
});

export default store;

contest.js

const contests = {
  firestorePath: 'contests',
  firestoreRefType: 'collection', // or 'doc'
  moduleName: 'contests',
  statePropName: 'data',
  namespaced: true, // automatically added

  // this object is your store module (will be added as '/myModule')
  // you can also add state/getters/mutations/actions
  state: {},
  getters: {},
  mutations: {},
  actions: {}
};

export default contests;

Contests.vue

<template>
  <v-container>
    <v-layout>
      <v-flex>
          <h1>Contests</h1>
          <ul>
            <li v-for="contest in $store.state.contests.data" :key="contest.id">{{ contest.name }}</li>
          </ul>
      </v-flex>
    </v-layout>
  </v-container>
</template>

<script>
export default {
  mounted() {
    this.$store.dispatch("contests/openDBChannel");
  }
  // ...
}
</script>
mesqueeb commented 5 years ago

@preginald edited your post to add syntax highlighting.

Please remember to write "js" or "html" or "vue" behind the three dashes to add syntax highlighting eg → ```js

Sitarman commented 5 years ago

Hello Guys, Great to see a few pointers thanks @preginald and of course @mesqueeb I did not realise you add to append 'this.$store' to dispatch('example'/openDBChannel). Any chance of a few more simple examples like this? For example sending data to firestore and being able to retrieve the data in any other view would get me started. Cheers Guys

pitw commented 5 years ago

@Sitarman You can get the data in any other view directly from the store:

computed: {
  products() {
   return Object.values(this.$store.state.productsModule.data)
  },
  clients() {
    return Object.values(this.$store.state.clientsModule.data)
   },
},
preginald commented 5 years ago

I'm so glad that @Sitarman asked that question. Thank you @pitw for responding. I've just finished completely removing all code related to vuex-easy-firestore because I found gaps in knowledge.

I've got decades of experience as a backend dev but it's been a steep learning curve learning Vue framework and Vuex/state management, I often stop myself from asking questions because they seem very simple in nature.

Eg. I couldn't figure out how to return a single product where("series_id"), "==", "this.$route.params.id")

I know how to achieve this with vanilla js or with vuefire in minutes but it becomes frustrating when something that should take seconds takes hours.

For now I'll clone my project and use vuex-easy-firestore and slowly build it as gain more knowledge.

Thanks for your patience and hardwork everyone.

mesqueeb commented 5 years ago

@preginald You can always open issues to ask me how to do something! 😉

Advice for new comers

I would anyone who's new to Vuex or to Firebase's JS SDK to first get some experience with it, see how you can manually implement (1) retrieving docs, (2) placing them inside a vuex module and (3) saving changes back to vuex & firestore simultaneously.

Manually writing all this logic is what I kept doing in all my apps, that's why I decided to turn it into a library. 😁 However, I can see that for newer devs (at least new to vuex / firebase js sdk) it can be daunting to understand what makes this library great.

As for your question:

I couldn't figure out how to return a single product

It depends on your implementation really.

method 1: fetchById

If you have several products in a single Firestore "collection" and you need to load them just one by one as the user opens the page with the product (and document) id, you could use the fetchById action I made.

dispatch('products/fetchById', routeId)

BTW this is documented under "read data" > "fetching docs". See the section called "Fetching in 'collection' mode".

method 2: fetchAndAdd

If however, the product ID is not the same as the document ID in Firestore, like your "series_id" then you'll have to use this instead:

dispatch('products/fetchAndAdd', {where: [['series_id', '==', routeId]]})

In this case, Firebase will throw an error that you need to set up an index, and it will show you a link to do so.

method 3: "doc" mode

You could also use "doc" mode with a pathVariable for the product ID, but that's not possible in your case with a separate "series_id". Also I'd advise against this because "doc" mode is more suited for a single document like "user settings" etc.

Let me know if there's anything I can help you with!

--
Vuex Easy Firestore was made with ♥ by Luca Ban.
If this library helped you in any way you can support me by buying me a cup of coffee.

bpkennedy commented 5 years ago

I'd also add that, in my opinion, using this library with Vuex/Firestore feels pretty close to using an ORM, as far as underlying complexity it is trying to make magical for you (take "magical" for what you will).

It is not quite as complex as Ember's ember-data ORM, and it's got an friendlier API. Also, it's a bit niche in that there isn't a whole lot of ORM tooling for nosql.

Although there were a couple things I worked through, my experience was definitely more pleasure than pain. If I was making another app that had no API (I.e went straight to firestore with http), I'd definitely use this again.

Sitarman commented 5 years ago

Thanks @preginald for your post and the link to the demo sample app the fog began to lift after that and thanks to @pitw for 'return Object.values(this.$store.state.productsModule.data)'... so that is how it is done!!! and @bpkennedy for your insight ,had a look at your Kenshi-journal app awesome piece of work and a master class for when I eventually come to terms with vuex and @mesqueeb your library is great I'm just not up to speed with vuex and cannot do it justice just yet but really appreciate your hard work . I'll have a good go this evening putting something together from what I have learnt so far.

mesqueeb commented 4 years ago

After about two years of open source, I finally got accepted for Github Sponsors!

💜 github.com/sponsors/mesqueeb 💜

A little about me:

If anyone was helped with vuex-easy-firestore, I'd greatly appreciate any support!

BTW, donations get's paid DOUBLE by GitHub! (they're alchemists... 🦾)

Going forward 👨🏼‍💻