Search code examples
javascripthtmlfirebase-realtime-databaseonsen-ui

HTML object "list" is not updating after switching between sites


What am I trying to achieve:

  • I am creating simple Firebase project with HTML and Javascript where the purpose of app is to create lists of data that is shared across users with specific “families”.

Where is the problem:

  • When I log in and my app goes to the “main.html” site everything loads fine and I can see actual items being downloaded from firebase into HTML object with ID “list”. Then when I click log out button – again everything is fine.
  • The problem occurs when I log back in (after the first logout with the button). I get transferred to the site “main.html” but the list does not update … I can see in console that I successfully downloaded data from Firebase. The only problem is that HTML is not updated.

If you could point me somewhere where I could find answers or point the problem out, I would really appreciate it! Already tried to search on internet for “HTML list is not updating” and similar searches but could not find anything.

I have also tried switching "let" for "var" on line 25. Didn't notice any diffrence.

“main.html” and console after FIRST login:

App 1 Console 1

“main.html” and console after SECOND login (as you can see in console data is successfully downloaded from Firebase – but HTML isn’t updated):

App 2 Console 2

Minimal reproducible code:

<!DOCTYPE html>
<html>
    <head>

    <!-- The core Firebase JS SDK is always required and must be listed first -->
    <script src="https://www.gstatic.com/firebasejs/7.14.2/firebase-app.js"></script>

    <script src="https://www.gstatic.com/firebasejs/7.14.2/firebase-auth.js"></script>
    <script src="https://www.gstatic.com/firebasejs/7.14.3/firebase-database.js"></script>

    <meta charset="UTF-8">
    <link rel="stylesheet" href="https://unpkg.com/onsenui/css/onsenui.css">
    <link rel="stylesheet" href="https://unpkg.com/onsenui/css/onsen-css-components.min.css">
    <script src="https://unpkg.com/onsenui/js/onsenui.min.js"></script>
    <script src="https://unpkg.com/jquery/dist/jquery.min.js"></script>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <script>
    // Your web app's Firebase configuration
    var firebaseConfig = {
      //MY FIREBASE CONFIG DATA
    };
    //Other vars.
    var currentPage = "register.html";
    let myListener;
    var email, family, password;

    // Initialize Firebase
    firebase.initializeApp(firebaseConfig);
    var auth = firebase.auth();
    var db = firebase.database();

    function login(){
        firebase.auth().signInWithEmailAndPassword(email, password).then(function(user){
                // user signed in
                goToPage('main.html'); 

                firebase.database().ref('/users/' + auth.currentUser.uid).once('value').then(function(snapshot) {
                    family = snapshot.val().family;
                    addDataListener();
                });

            }).catch(function(error) {

                // Handle Errors here.
                var errorCode = error.code;
                console.log(errorCode);

                if (errorCode){
                    ons.notification.alert('Error!');
            }
        });
    }

    function logout(){
        goToPage('login.html'); 

        firebase.auth().signOut().then(function() {
            console.log("I just log out");
            }, function(error) {
             console.log("Some error: ", error);
        });    
    }

    function addDataListener(){
        console.log("Listener is set up!");

        myListener = firebase.database().ref('families/' + family).on('value', function(snapshot) {
            if (currentPage !== "main.html") return;
            console.log(snapshot.val());

            var list = document.getElementById('list'); 

            //Empty list
            while (list.hasChildNodes()) {  
                list.removeChild(list.firstChild);
            }

            //Read all items in firebase and add them to the list
            Object.keys(snapshot.val()).forEach(function(k){
                console.log(k + ' - ' + snapshot.val()[k]);

                var onsItem = document.createElement('ons-list-item');    
                onsItem.innerHTML = snapshot.val()[k]; 
                onsItem.setAttribute('id', k);
                list.appendChild(onsItem);  
            });

        });
    }

    function goToPage(newPage){
        currentPage = newPage;

        var myNavigator = document.getElementById('myNavigator');
        myNavigator.pushPage(newPage);   
    }
    </script>



    </head>

    <body>
    <ons-navigator swipeable id="myNavigator" page="login.html"></ons-navigator>


    <template id="login.html">
    <ons-page id="login">
    <!--Page name-->
        <ons-toolbar>
          <div class="center">Login page</div>
        </ons-toolbar>

    <!--Inputs-->    
    <ons-list>       
        <ons-list-item tappable>
            <div class="center">
            Email: 
                <ons-input id="email_login" type="email" onchange = "email = this.value"></ons-input>
            </div> 
        </ons-list-item>   

        <ons-list-item tappable>
            <div class="center">
            Password: 
                <ons-input id="password_login" type="password" onchange = "password = this.value"></ons-input>
            </div> 
        </ons-list-item>
    </ons-list>

    <!--Buttons -->  
        <p style="text-align: center"> <ons-button modifier="material" id="login" onclick="login();">Login</ons-button> </p>

    </ons-page>
    </template>

    <template id="main.html">
    <ons-page id="main">
    <!-- Page name -->
        <ons-toolbar>
          <div class="center">Main page</div>
        </ons-toolbar>

    <!--List-->
        <ons-list id="list"></ons-list>

    <!--Buttons -->  
        <p style="text-align: center"> <ons-button modifier="material" id="logout" onclick="logout();">Log out</ons-button> </p>

    </ons-page>
    </template>
    </body>
</html>

Solution

  • I played with the code a bit and did 2 minor changes.

    The thing was addDataListener() did not run after myNavigator.pushPage

    Additionally myNavigator.replacePage literally added pages/section to the DOM instead of replacing them. That caused #list element to render on the old page instead of the new one ( id should be unique ) so I replaced that with myNavigator.replacePage

    Seems to work now

    goToPage('main.html')
              .then(_ => {
                firebase.database().ref('/users/' + auth.currentUser.uid).once('value').then(function(snapshot) {
                  family = snapshot.val().family;
                  addDataListener();
                });
              })
    
     function goToPage(newPage) {
          currentPage = newPage;
    
          var myNavigator = document.getElementById('myNavigator');
          return myNavigator.replacePage(newPage);
        }
    

    var currentPage = "register.html";
    let myListener;
    var email, family, password;
    
    const mockFirebase = {
      initializeApp: () => {},
      auth() {
        return {
          currentUser: {
            uid: 1
          },
          signInWithEmailAndPassword: () => Promise.resolve({}),
          signOut: () => Promise.resolve()
        }
      },
      database() {
        return {
          ref(path) {
            let value = {
              family: 'One'
            }
            if (path.includes("families")) {
              value = ['One', 'Two', 'Three']
            }
    
            return {
              once: () => Promise.resolve({
                val: () => value
              }),
              on: (prop, callback) => callback({
                val: () => value
              })
            }
          }
        }
      },
    }
    
    window.firebaseConfig = {}
    window.firebase = mockFirebase;
    
    firebase.initializeApp(firebaseConfig);
    var auth = firebase.auth();
    var db = firebase.database();
    
    function login() {
      firebase.auth().signInWithEmailAndPassword(email, password).then(function(user) {
    
        goToPage('main.html')
          .then(_ => {
            firebase.database().ref('/users/' + auth.currentUser.uid).once('value').then(function(snapshot) {
              family = snapshot.val().family;
              addDataListener();
            });
          })
    
      }).catch(function(error) {
    
        var errorCode = error.code;
        console.log(errorCode);
    
        if (errorCode) {
          ons.notification.alert('Error!');
        }
      });
    }
    
    function logout() {
      goToPage('login.html');
    
      firebase.auth().signOut().then(function() {
        console.log("I just log out");
      }, function(error) {
        console.log("Some error: ", error);
      });
    }
    
    function addDataListener() {
      console.log("Listener is set up!");
    
      myListener = firebase.database().ref('families/' + family).on('value', function(snapshot) {
        if (currentPage !== "main.html") return;
        console.log(snapshot.val());
    
        var list = document.getElementById('list');
    
        while (list.firstChild) {
          list.removeChild(list.firstChild);
        }
        Object.keys(snapshot.val()).forEach(function(k) {
          console.log(k + ' - ' + snapshot.val()[k]);
    
          var onsItem = document.createElement('ons-list-item');
          onsItem.innerHTML = snapshot.val()[k];
          onsItem.setAttribute('id', k);
          list.appendChild(onsItem);
        });
    
      });
    }
    
    function goToPage(newPage) {
      currentPage = newPage;
    
      var myNavigator = document.getElementById('myNavigator');
      return myNavigator.replacePage(newPage);
    }
    <!DOCTYPE html>
    <html>
    
    <head>
      <script src="https://www.gstatic.com/firebasejs/7.14.2/firebase-app.js"></script>
      <script src="https://www.gstatic.com/firebasejs/7.14.2/firebase-auth.js"></script>
      <script src="https://www.gstatic.com/firebasejs/7.14.3/firebase-database.js"></script>
      <meta charset="UTF-8">
      <link rel="stylesheet" href="https://unpkg.com/onsenui/css/onsenui.css">
      <link rel="stylesheet" href="https://unpkg.com/onsenui/css/onsen-css-components.min.css">
      <script src="https://unpkg.com/onsenui/js/onsenui.min.js"></script>
      <script src="https://unpkg.com/jquery/dist/jquery.min.js"></script>
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
    </head>
    
    <body>
      <ons-navigator swipeable id="myNavigator" page="login.html"></ons-navigator>
    
    
      <template id="login.html">
        <ons-page id="login">
        <!--Page name-->
            <ons-toolbar>
              <div class="center">Login page</div>
            </ons-toolbar>
    
        <!--Inputs-->    
        <ons-list>       
            <ons-list-item tappable>
                <div class="center">
                Email: 
                    <ons-input id="email_login" type="email" onchange = "email = this.value"></ons-input>
                </div> 
            </ons-list-item>   
    
            <ons-list-item tappable>
                <div class="center">
                Password: 
                    <ons-input id="password_login" type="password" onchange = "password = this.value"></ons-input>
                </div> 
            </ons-list-item>
        </ons-list>
            <p style="text-align: center"> <ons-button modifier="material" id="login" onclick="login();">Login</ons-button> </p>
        </ons-page>
        </template>
      <template id="main.html">
        <ons-page id="main">
            <ons-toolbar>
              <div class="center">Main page</div>
            </ons-toolbar>
            <ons-list id="list"></ons-list>
            <p style="text-align: center"> <ons-button modifier="material" id="logout" onclick="logout();">Log out</ons-button> </p>
    
        </ons-page>
        </template>
    </body>
    
    </html>