David Williams IV
David Williams IV

Reputation: 51

How do you detach an onSnapshot listener from Firebase Firestore

I've browsed for the last few hours but have been entirely unable to successfully detach an onSnapshot listener. Currently my HTML is:

  <nav>
    <butt onclick="navButt(`Chat`)" class="navItem">Chat</butt>
    <butt onclick="navButt(`Staff`)" class="navItem">Staff</butt>
    <butt onclick="navButt(`Logout`)" class="navItem">Signout</butt>
  </nav>

  <module id="Chat" class="mod">
    <h3>Chat</h3>
  </module>

  <module id="Staff" class="mod active">
    <h3>Users</h3>
    <ul id="usersList">
      <li><span>User 1 Name</span><span>User 1 email</span></li> //Planned output of data, using console logging for testing, though.
    </ul>
  </module>

And my Javascript is:

function staff(){
FS.collection('users').where('company','==',`${userToken.claims.company}`).onSnapshot(snap=>{
        let userList = []
        snap.forEach(function(doc){
            userList.push(doc.data().email);
        })
        console.log('Users: ' + userList)
    })
}

function navButt (butt) {
let unsubscribe = FS.collection('users').where('company','==',`${userToken.claims.company}`).onSnapshot(function(){}) //placed inside so the auth token can be populated first
//I've also tried FS.collection('users').onSnapshot(function(){}) //but this results in a permission error since users can only read other user docs of the same company
    switch (butt) {
        case 'Logout':
            FA.signOut();
            break;
        case 'Chat':
            changeMod(butt);
            unsubscribe(); //This is where I've tried all the things
            break;
        case 'Staff':
            changeMod(butt)
            staff();
            break;
        default:
            console.log('No tied function')
            break;
    }
}

//Change Module
function changeMod (target) {
    document.querySelectorAll('.mod').forEach((modules)=>{modules.classList.remove('active')})
    document.querySelector(`#${target}`).classList.add('active')}

If some kind soul could look at my onSnapshot function above and show me what the detaching code should look like, that would be greatly appreciated, thank you!

Upvotes: 1

Views: 480

Answers (1)

David Williams IV
David Williams IV

Reputation: 51

I finally figured out and understand capturing and calling the unsubscribe. Only started learning Javascript a month ago, so for those in the same shoes, here's my fix:

        case 'Chat':
        changeMod(butt);
        try {unsubscribe()} catch {} //Since it won't exist on the first click, wrap in a try{}
        var unsubscribe = FS.collection('users').where('company','==',`${userToken.claims.company}`).onSnapshot(snap=>{ //Use a var so it can be initialized and declared repeatedly, but also the first time. Alternatively, use a let globally set to '' (nothing) and just "unsubscribe = "
            let userList = []
            snap.forEach(function(doc){
                userList.push(doc.data().email);
            })
            console.log('Users: ' + userList)
        }) //What got me was that capturing the onSnapshot in a variable IS creating the snapshot listener, it's a two in one action. Mind blown.
        break;

    case 'Staff':
        changeMod(butt)
        try {unsubscribe()} catch {} //Once it's been captured it will be "true" because it exists, and can be called to unsubscribe the last one before being set to the new one.
        var unsubscribe = FS.collection('users').where('company','==',`${userToken.claims.company}`).onSnapshot(snap=>{
            let userList = []
            snap.forEach(function(doc){
                userList.push(doc.data().email);
            })
            console.log('Users: ' + userList)
        })
        break;

When reading anything on it I just always interpreted the capturing of unsubscribe to be it's own, independent action.

Upvotes: 2

Related Questions