vue-fiery

    0.0.2 • Public • Published

    vue-fiery

    Vue.js binding for Google Firebase Cloud Firestore.

    Features

    • Documents example
    • Collections (stored as array or map) example
    • Queries (stored as array or map) example
    • Real-time or once example
    • Data or computed properties example
    • Adding, updating, sync, removing, remove field example
    • Sub-collections (with cascading deletions!) example
    • Return instances of a class example
    • Add active record methods (sync, update, remove, clear, getChanges) example
    • Control over what properties are sent on save example
    • Encode & decode properties example
    • Adding the key to the document example
    • Callbacks (error, success, missing, remove) example
    • Custom binding / unbinding

    Contents

    Dependencies

    • Firebase ^5.0.0
    • Vue: ^1.0.28

    Installation

    npm

    Installation via npm : npm install vue-fiery --save

    Usage

    import Vue from 'vue'
    import VueFiery from 'vue-fiery'
    import firebase from 'firebase'
     
    require('firebase/firestore')
     
    Vue.use(VueFiery)
     
    const firebaseApp = firebase.initializeApp({ ... })
    const db = firebaseApp.firestore();
     
    var vm = new Vue({
      el: '#app',
      data() {
        return {
          todos: this.$fiery(db.collection('todos')) // live collection,
          ford: this.$fiery(db.collection('cars').doc('ford')), // live document
          role: 'admin'
        }
      },
      computed: {
        // Updated when role changes
        personsWithRole() {
          return this.$fiery(db.collection('persons'), {
            query: (q) => q.where('role', '==', this.role),
            type: Person
          })
        }
      }
    })

    Each record of the array will contain a .uid property. This helps identify what firestore database the document is stored, in what collection, and with which options

    [
        {
            ".uid": "1///1///todos/-Jtjl482BaXBCI7brMT8",
            "name": "Star vue-fiery",
            "done": true
        }
    ]

    Documents

    const db = firebaseApp.firestore();
    new Vue({
      inject: ['currentUserId'],
      data() {
        const $fiery = this.$fiery
        return {
          settings: $fiery(db.collection('settings').doc('system')),
          currentUser: $fiery(db.collection('users').doc(this.currentUserId)) // not reactive, but is updated real-time
        }
      }
    })

    Collections

    const db = firebaseApp.firestore();
    new Vue({
      data() {
        const $fiery = this.$fiery
        return {
          cars: $fiery(db.collection('cars')) // real-time array
          carMap: $fiery(db.collection('cars'), {map: true}) // real-time map: carMap[id] = car
        }
      }
    })

    Queries

    const db = firebaseApp.firestore();
    new Vue({
      inject: ['currentUserId'],
      data() {
        const $fiery = this.$fiery
        return {
          currentCars: $fiery(db.collection('cars'), { // real-time array
            query: (cars) => cars.where('created_by', '==', this.currentUserId)
          })
          currentCarMap: $fiery(db.collection('cars'), { // real-time map: currentCarMap[id] = car
            query: (cars) => cars.where('created_by', '==', this.currentUserId),
            map: true
          })
        }
      }
    })

    Real-time or once

    const db = firebaseApp.firestore();
    new Vue({
      inject: ['currentUserId'],
      data() {
        const $fiery = this.$fiery
        return {
          // real-time is default, all you need to do is specify once: true to disable it
          cars: $fiery(db.collection('cars'), {once: true}), // array populated once
          currentUser: $fiery(db.collection('users').doc(this.currentUserId), {once: true}), // current user populated once
        }
      }
    })

    Data or computed

    const db = firebaseApp.firestore();
    new Vue({
      inject: ['currentUserId'],
      data() {
        // data examples above
        return {
          limit: 25,
          status: 'unfinished'
        }
      },
      computed: {
        currentUser() {
          return this.$fiery(db.collection('users').doc(this.currentUserId)) // reactive and real-time
        },
        todos() {
          return this.$fiery(db.collection('todos'), { // reactive and real-time
            query: (todos) => todos
              .where('created_by', '==', this.currentUserId)
              .where('status', '==', this.status)
              .limit(this.limit),
     
          })
        }
      }
    })

    Adding, updating, overwriting, removing

    const db = firebaseApp.firestore();
    new Vue({
      inject: ['currentUserId'],
      data() {
        return {
          todos: this.$fiery(db.collection('todos'))
        }
      },
      computed: {
        currentUser() {
          return this.$fiery(db.collection('users').doc(this.currentUserId))
        }
      },
      methods: {
        addTodo() { // COLLECTIONS STORED IN $fires
          // once successful, this.todos will be updated
          this.$fires.todos.add({
            name: 'Like vue-fiery',
            done: true
          })
        },
        updateUser() {
          this.$fiery.update(this.currentUser)
        },
        updateUserEmailOnly() {
          this.$fiery.update(this.currentUser, ['email'])
        },
        updateAny(data) { // any document can be passed, ex: this.todos[1], this.currentUser
          this.$fiery.update(data)
        },
        overwrite(data) { // only fields present on data will exist on sync
          this.$fiery.sync(data)
        },
        remove(data) {
          this.$fiery.remove(data) // removes sub collections as well
          this.$fiery.remove(data, true) // preserves sub collections
        },
        removeName(todo) {
          this.$fiery.clear(data, 'name') // can also specify an array of props or sub collections
        }
      }
    })

    Sub-collections

    You can pass the same options to sub, nesting as deep as you want!

    const db = firebaseApp.firestore();
    new Vue({
      data() {
        return {
          // this.todos[todoIndex].children[childIndex]
          todos: this.$fiery(db.collection('todos'), {
            sub: {
              children: { // creates an array or map on each todo object: todo.children[]
                // once, map, etc
                query: (children) => children.orderBy('updated_at')
              }
            }
          })
        }
      },
      methods: {
        addChild(parent) {
          // or this.$fiery.ref(parent, 'children') for short
          this.$fiery.ref(parent).collection('children').add({
            name: 'Fork vue-fiery',
            done: false
          })
        },
        clearChildren(parent) {
          this.$fiery.clear(parent, 'children') // clear the sub collection
        }
      }
    })

    Return instances of a class

    function Todo() {
     
    }
    Todo.prototype = {
      markDone (byUser) {
        this.done = true
        this.updated_at = Date.now()
        this.updated_by = byUser.id
      }
    }
     
    const db = firebaseApp.firestore();
    new Vue({
      data() {
        return {
          // this.todos[todoIndex] instanceof Todo
          todos: this.$fiery(db.collection('todos'), {
            type: Todo,
            // OR you can specify newDocument and do custom loading (good for polymorphic data)
            newDocument: function(initialData) {
              var instance = new Todo()
              instance.callSomeMethod()
              return instance
            }
          })
        }
      }
    })

    Active Record

    // can be used with type, doesn't have to be
    function Todo() {
     
    }
    Todo.prototype = {
      markDone (byUser) {
        this.done = true
        this.updated_at = Date.now()
        this.updated_by = byUser.id
        this.$update()
      }
    }
     
    const db = firebaseApp.firestore();
    new Vue({
      data() {
        return {
          todos: this.$fiery(db.collection('todos'), {
            type: Todo,
            record: true
            // $sync, $update, $remove, $ref, $clear, $getChanges are functions added to every Todo instance
          }),
          todosCustom: this.$fiery(db.collection('todos'), {
            record: true,
            recordOptions: { // which methods do you want added to every object, and with what method names?
              sync: 'sync',
              update: 'save',
              remove: 'destroy'
              // we don't want $ref, $clear, or $getChanges
            }
          })
        }
      },
      methods: {
        updateTodoAt(index) {
          // instead of this.$fiery.update(this.todos[index])
          this.todos[index].$update()
        },
        saveTodoCustomAt(index) {
          // instead of this.$fiery.update(this.todosCustom[index])
          this.todosCustom[index].save()
        },
        done(todo) {
          todo.markDone(this.currentUser) // assuming currentUser exists
        },
        getChanges(todo) {
          todo.$getChanges(['name', 'done'], function(changes, saved, current) {
            // are there unsaved changes in name or done? (exclude array to check entire document)
          })
        }
      }
    })

    Save fields

    const db = firebaseApp.firestore();
    new Vue({
      data() {
        return {
          todos: this.$fiery(db.collection('todos'), {
            include: ['name', 'done'], // if specified, we ONLY send these fields on sync/update
            exclude: ['hidden'] // if specified here, will not be sent on sync/update
          }),
        }
      },
      methods: {
        save(todo) {
          this.$fiery.update(todo)
        },
        saveDone(todo) {
          this.$fiery.update(todo, ['done']) // only send this value if it exists
        },
        saveOverride(todo) {
          this.$fiery.update(todo, ['hidden']) // ignores exclude and include when specified
        }
      }
    })

    Encode & decode properties

    const db = firebaseApp.firestore();
    new Vue({
      data() {
        return {
          todos: this.$fiery(db.collection('todos'), {
            // convert server values to local values
            decoders: {
              status(remoteValue, remoteData) {
                return remoteValue === 1 ? 'done' : (remoteValue === 2 ? 'started' : 'not started')
              }
            },
            // convert local values to server values
            encoders: {
              status(localValue, localData) {
                return localValue === 'done' ? 1 : (localeValue === 'started' ? 2 : 0)
              }
            },
            // optionally instead of individual decoders you can specify a function
            decode(remoteData) {
              // do some decoding, maybe do something special
              return remoteData
            }
          })
        }
      }
    })

    Adding key to object

    const db = firebaseApp.firestore();
    new Vue({
      data() {
        return {
          todos: this.$fiery(db.collection('todos'), {key: 'id', exclude: ['id']}) // must be excluded manually
        }
      },
      methods: {
        log(todo) {
          // todo.id exists now
          console.log(todo)
        }
      }
    })

    Callbacks

    const db = firebaseApp.firestore();
    new Vue({
      data() {
        return {
          todos: this.$fiery(db.collection('todos'), {
            onSuccess: (todos) => {},
            onError: (message) => {},
            onRemove: () => {},
            onMissing: () => {} // occurs for documents
          })
        }
      }
    })

    LICENSE

    MIT

    Install

    npm i vue-fiery

    DownloadsWeekly Downloads

    3

    Version

    0.0.2

    License

    MIT

    Unpacked Size

    167 kB

    Total Files

    25

    Last publish

    Collaborators

    • philip.diffenderfer