0

I am trying to define a ref in vuefire to firebase path that depends on the current User. Is it possible to bring the "user" object to the "top level" and access it from outside the "on.AuthSateChanged(user => .... }" ?

firebase-config.js

 import * as firebase from "firebase";

var config = {
    apiKey: "XXXXXX",
    authDomain: "XXXXXX.firebaseapp.com",
    databaseURL: "https://XXXXXX.firebaseio.com",
    projectId: "XXXXXX",
    storageBucket: "XXXXXX.appspot.com",
    messagingSenderId: "XXXXXX"
};
firebase.initializeApp(config)
export default !firebase.apps.length ? firebase.initializeApp(config) : firebase;


firebase.auth().onAuthStateChanged((user) => {
    if (user) {
        let userRef = firebase.database().ref('users').child(user.uid);
        let buildingsRef = userRef.child('buildings');
    }
  })();
console.log(buildingsRef); //returning undefined=    

export const db = firebase.database(); 
export const usersRef = db.ref('users');
export const buildingsRef = db.ref('users'+ "/" +buildingsRef)
// I will deal with this later
// export const deptsRef = db.ref('depts');
// export const roomsRef = db.ref('rooms'); 

app.vue

<template>
  <div id="app" class="section">   
    <main>
      <router-view id="main" ></router-view>
    </main>
  </div>
</template>

<script>
import firebase from './firebase-config';
import { buildingsRef } from './firebase-config';
import { deptsRef } from './firebase-config'; 

export default {
  name: 'app',
  data () {
    return {
    }
  },
}
</script>

buildingadd.vue (component)

<template>
  <div class="building">
    <div id="title">
      <h1>{{ initialmsg }}</h1>
    </div>  
    <form id="form" class="form-inline" v-on:submit.prevent="addBuilding">
      <div class="form-group">     
        <p><span> Name: </span><input class="input typename" type="text" placeholder="type name" v-model="newBuilding.name"></p>
      </div>
      <div class="form-group">            
        <p><input type="text" id="buildingAddress" class="form-control" placeholder="Address" v-model="newBuilding.address"></p>
      </div>
      <div class="form-group">            
        <p><textarea id="buildingComments" class="form-control text" cols="40" rows ="6" placeholder="Comments (optional)" v-model="newBuilding.comments"></textarea></p>
      </div>               
      <!-- <button id="addButton" class="button">Add New Space</button> -->
      <router-link  to="/buildings"><button @click="addBuilding" :disabled="!formIsValid">Save</button></router-link>
    </form>
    <!-- <button type="submit" id="updateButton" class="button is-primary"  @click.prevent="updateSpace(newSpace), show = !show" >UPDATE </button>  -->
  </div>
</template>

<script>
import firebase from '../firebase-config';
import { buildingsRef } from '../firebase-config';
import { usersRef } from '../firebase-config';

export default {
  firebase() { 
    return {
    buildings:  buildingsRef,
    users: usersRef,
    }
  },
  name: 'buildingsadd',
  data () {
    return {
      initialmsg: "Add building's details:",
      newBuilding: {
        name: '',
        address: '',
        comments: '',
        ownerID: '',
      }
    }
  },
  methods: {
    setUser() {
        this.$store.dispatch('setUser');
      },
    addBuilding: function () {
      let userId = firebase.auth().currentUser.uid;
      let buildingKey = buildingsRef.push().key
      this.newBuilding.ownerID = userId;
      buildingsRef.child(buildingKey).set(this.newBuilding);
      usersRef.child(userId).child('isAdmin').child(buildingKey).set(true);
    },    
  },
  computed: {
    formIsValid() {
      return this.newBuilding.name !== '';
    },    
  },
}

Alternatively an answer to this question would also solve my specific problem. How to constrain read/write rules to the users that create the nodes while keeping this structure?

I would really appreciate your help. thanks!

  • The data is loaded from Firebase asynchronously. By the time you log the `userRef` the code inside `onAuthStateChanged` hasn't run yet. The solution is to move all code that requires the `userRef` into the callback that sets it. See https://stackoverflow.com/a/33204705, https://stackoverflow.com/a/39472821, https://stackoverflow.com/a/42141541 and more linked from there. – Frank van Puffelen Apr 08 '18 at 14:05
  • Hi Frank! But in Vue/Vuefire the database refs should be loaded when the app initiates and I am doing that on a firebase-config.js file. Almost all components of the app depend on those refs to write/read and it would be insane to move all the code to a firebase-config file... This is my last resort to solve this problem: https://stackoverflow.com/questions/49654136/what-is-the-best-practice-to-write-the-rules-of-firebase-in-a-situation-like-thi?noredirect=1#comment86354831_49654136 – Joao Alves Marrucho Apr 08 '18 at 14:18
  • https://stackoverflow.com/questions/49676833/is-it-possible-to-define-a-variable-on-the-firebase-database-references-path/49678124#49678124 – Joao Alves Marrucho Apr 08 '18 at 14:18
  • I have recently raised the issue with the Vuefire team: https://github.com/vuejs/vuefire/issues/178 – Joao Alves Marrucho Apr 08 '18 at 14:22
  • The code in your question has nothing to do with VueJS as far as I can see. If VueJS is related, make sure to show how in the code in your question. – Frank van Puffelen Apr 08 '18 at 15:39
  • ok! i have added some more vue.js code. would it be useful if I added the vue routing and state management snippets or is this enough? – Joao Alves Marrucho Apr 08 '18 at 15:55
  • @JoaoAlvesMarrucho remember you don't literally have to move all your code. You could wrap it in a function then just call that function (1 line of code) from within the `.onAuthStateChanged`. ...just an idea. – Ronnie Royston Apr 08 '18 at 17:01
  • @RonRoyston. You are right but I believe the bigger problem remains. Firebase-config.js file is the one starting the firebase-app, and because .onAuthStateChanged() is async the user will not be defined when the path is exported from that file... right? – Joao Alves Marrucho Apr 09 '18 at 12:26

1 Answers1

0

Simply adding it to the window object will do.

window.userRef = userRef;

e.g.

firebase.auth().onAuthStateChanged(user => {
  if (user) {
    let userRef = firebase.database().ref('users').child(user.uid);
    window.userRef = userRef;
    let buildingsRef = userRef.child('buildings');
    // userRef returns the user uid 
  }
});

console.log(userRef); // no longer undefined only if this is called after `onAuthStateChanged` response. Thanks @EmileBergeron 
Jacob Goh
  • 19,800
  • 5
  • 53
  • 73
  • Vue.js/vuefire uses a Virtual DOM. Wouldn't that render this useless? – Joao Alves Marrucho Apr 08 '18 at 14:20
  • 1
    @JoaoAlvesMarrucho hmm.. what does Virtual DOM have do to with this? may i know what are you trying to do ? – Jacob Goh Apr 08 '18 at 14:22
  • It will still be undefined since `onAuthStateChanged` is async. – Emile Bergeron Apr 08 '18 at 14:26
  • 1
    @EmileBergeron you 're right! it will only be available after the asynchronous response – Jacob Goh Apr 08 '18 at 14:27
  • this is the last resort to solve this: https://stackoverflow.com/questions/49718494/is-it-possible-to-bring-the-user-object-to-the-top-level-and-access-it-from/49718650?noredirect=1#comment86450559_49718650 https://stackoverflow.com/questions/49676833/is-it-possible-to-define-a-variable-on-the-firebase-database-references-path/49678124#49678124 – Joao Alves Marrucho Apr 08 '18 at 14:29