No More Posting New Topics!

If you have a question or an issue, please start a thread in our Github Discussions Forum.
This forum is closed for new threads/ topics.

Navigation

    Quasar Framework

    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search

    How to notify users about content change in a Quasar SPA app

    Help
    4
    26
    2848
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • M
      Mickey58 last edited by Mickey58

      I have a Quasar based web app (SPA). I would like to notify users about new content available, preferably by a Quasar QNotify message coming up in the browser (for all logged in users). It appears that the Quasar docs web site itself offers that kind of a mechanism, but I’m not sure how it can be implemented for my SPA.

      My Node backend code is the source of wisdom about new content. I see different possible mechanisms to achieve this - push notifications, service workers, browser notfications. I know these mechanisms are not Quasar functions, but I need to select the right mechanism and get it working together with my Quasar app.

      In https://quasar.dev/quasar-cli/developing-pwa/handling-service-worker#Interacting-with-Service-Worker there is documentation how to interact from a Quasar app with a service worker, but it seems to be specific to PWAs, while my Quasar app is SPA.

      Are there any pointers or examples how to achieve this?

      Update: Somebody else posted this question on Stackoverflow a while ago, but no answer:
      https://stackoverflow.com/questions/61546909/using-a-service-worker-in-a-quasar-spa

      1 Reply Last reply Reply Quote 0
      • F
        FrankM last edited by

        Basically, with service workers you can receive push messages without your app/website having focus on the user’s device (i.e. being in the background or even not running at all in case of native apps)

        For a simple “content updated” message this is too much imo. For a simple web app you could simply do a setInterval checking the backend regularly for updates or set up a websocket connection.

        1 Reply Last reply Reply Quote 0
        • dobbel
          dobbel last edited by

          If you want browser notifications, the way of doing it is to convert your SPA to PWA. It’s not that hard, really. And then use the Notification web Api.

          https://developer.mozilla.org/en-US/docs/Web/API/Notifications_API/Using_the_Notifications_API

          https://dzone.com/articles/how-to-add-real-web-push-notifications-to-your-web

          Another way is to use a socket connection to to send a messages from your Nodejs Server to your client (SPA).

          https://alligator.io/vuejs/vue-socketio/

          1 Reply Last reply Reply Quote 0
          • M
            Mickey58 last edited by

            @FrankM, @dobbel - thanks for sharing your adivse.

            The potential conversion from SPA to PWA, though @dobbel said it isn’t that hard, sounds like a big overall change to my app. Probably not justified if only for the sake of this small enhancement.

            But honestly I don’t undestand the impacts and pros and cons of PWA vs. SPA.

            I’m a bit scared that I have to do a lot of regression testing and potential changes to my build and deployment process (locally and on Heroku Cloud) for PWA.

            dobbel 1 Reply Last reply Reply Quote 0
            • dobbel
              dobbel @Mickey58 last edited by

              @Mickey58 It’s not hard because Quasar makes it easy. From the server’s point of view( Heroku) I don’t think it’s any different compared to a normal website . The bigger challenge I think would be to use the Notifications Web Api. ( I have no experience in that).

              Anyways the socket connection would relativity easy to implement because you use nodejs.

              1 Reply Last reply Reply Quote 0
              • F
                FrankM last edited by FrankM

                Actually, you can use all techniques (service workers, websockets) in both PWAs and SPAs, it’s more a question of backend design imo.

                In my app I have a comment system. I notify users when a new comment has been posted in a thread a user has posted to or is currently viewing
                Here’s what I do:

                • when new comment is posted, i generate a notification for every user that has subscribed to the thread in the backend

                • push a message over websocket to all users that a new comment has been posted

                • when a user is currently using the app (has focus), websocket push is received by the active browser instance

                • generate a native browser event from the websocket message (new CustomEvent)

                • set up a listener for the custom event on the route where the comment thread is displayed

                • if the user is actually browsing the thread in question, just update it with the new comment

                • if not (i.e. is somewhere else in the app) and has subscribed to thread, display a QNotification or generic browser notification. Or display a counter in your navigation/toolbar, depends on you app

                • if the user reads the new comment (set up a scroll observer / intersection, Quasar has nice features for this), inform the backend about this and delete the notification on the backend if user has a subscription to thread

                • setup cronjob on backend for notifications not “seen” by the user (like every 5 minutes)

                • send a push message over firebase to subscribers

                • service worker in my app listens to firebase messages and generates a push message

                • when user reacts to push and navigates to the thread, this is handled by QIntersection and backend is informed that the user has “seen” the comment (like before)

                • after 30 minutes, send out E-Mail notification from backend

                This is probably overengineered for a simple “content updated” thing

                The basic approach is: notify active user via websocket, inactive user via push, offline users via E-Mail. Don’t do it all at once, this is super annyoing. Keep track in your backend about notifications actually being read

                Implement “priorities”. For example, I dont’t send push messages via firebase when someone has not actively subscribed to a thread. But I do of course update the UI when the user is browsing the thread currently

                dobbel 1 Reply Last reply Reply Quote 2
                • F
                  FrankM last edited by

                  A nice thing is that you can implement event listeners on specific routes/components and a more generic event handling on app/main layout level to act as fallback in case the handler on the specific route did not trigger because the user is on another route. Just make sure you setup listeners onMounted() or onCreate() and remove them before the component is destroyed

                  1 Reply Last reply Reply Quote 0
                  • dobbel
                    dobbel @FrankM last edited by dobbel

                    @FrankM that’s a very neat system( a bit jelly)!

                    Do you only send Firebase push messages to the client? Or do also (first) send your ‘own’ websocket push messages to active clients?

                    I am wondering if you have a example how to create a generic browser message ( from the websocket message)?

                    Any code samples from your awesome notification system is of course very appreciated!

                    F 1 Reply Last reply Reply Quote 0
                    • M
                      Mickey58 last edited by Mickey58

                      Wow, I’m impressed by @FrankM’'s “layered” notification approach. Gives me a lot of food for thought.

                      My app is less “collaborative” though, so I’ll implement at least initially a simpler mechanism.

                      Currently I’m looking at this tutorial: https://thecodebarbarian.com/sending-web-push-notifications-from-node-js.html

                      I’ll probably try to put the server part of that code into my backend server.

                      I’m not sure yet about the client part of that code. Maybe I can integrate that into my static Express web server for Quasar? Or does it belong into the Quasar my-layout.vue main code (mounted or created part)? The other tutorial @dobbel pointed to, says it is normally put into the index.js file of the frontend code…you see that my understanding of it is still too limited.

                      [Update: In my prototype mentioned further below, I put the client part (registration & subscription) into created() of my-layout.vue]

                      Then I still have to figure out where to place and find the service worker code itself (which is in a separate worker.js file in the tutorial) within my Quasar frontend code structure.

                      1 Reply Last reply Reply Quote 0
                      • F
                        FrankM @dobbel last edited by

                        @dobbel I send websocket messages first to “connected” users and firebase pushs to users not active for 5 minutes or so. For simple UI updates I only use websockets only (like updating counters and stuff)

                        On the client, I subscribe to the websocket messages (I use vue-wamp) and upon receiving, I fire a native browser event that can be handled by regular event listeners. This is set up in a “created” hook on app level or main layout, i.e. components that are always active when the app has been initialized and has focus.

                        $wamp is globally exported to my components by a Quasar boot file

                        this.$wamp.subscribe('myChannel', function (payload, args, event) {
                                     const data = payload[0]; //custom data sent from the backend via websocket
                                     var ev = new CustomEvent(data.identifier, { 
                                        detail: data, //pass the backend payload to the custom event also
                                        bubbles: true,
                                        cancelable: true
                                     });
                                     const handled = !document.dispatchEvent(ev) //fire event
                                     if (handled) { 
                                        //event has been handled/consumed by another (child) component in the app
                                     } else {
                                        //handle event on app level if needed, e.g. fallback to generic browser notification
                                     }
                                  }
                        

                        In a component, I create event-handler like:

                        created() {
                           document.addEventListener("my-event-identifier", this.eventHandler, false)
                        },
                        beforeDestroy() {
                           document.removeEventListener("my-event-identifier", this.eventHandler, false)
                        },
                        methods: {
                           eventHandler(event) {
                              console.log(event.detail)
                              //do stuff with event
                           }
                        }
                        
                        dobbel 1 Reply Last reply Reply Quote 0
                        • M
                          Mickey58 last edited by Mickey58

                          @FrankM, @dobbel - can you take a quick look at my last append? I’m still struggling a bit with the basics of web push notications, unsure where the client code pieces belong in a Quasar app (still SPA at this point).

                          1 Reply Last reply Reply Quote 0
                          • dobbel
                            dobbel @FrankM last edited by

                            @FrankM Thanks for the samples! It helps a lot to understand.

                            Looking at you samples I wonder where and how the Firebase push events are handled?

                            F 1 Reply Last reply Reply Quote 0
                            • F
                              FrankM @dobbel last edited by FrankM

                              @dobbel

                              To listen to firebase messages you would setup somthing like:

                              firebase.js boot file

                              import * as firebase from "firebase/app"
                              import "firebase/messaging"
                              
                              firebase.initializeApp({
                                  apiKey: process.env.FIREBASEKEY,
                                  authDomain: "my-app.firebaseapp.com",
                                  projectId: "my-app",
                                  messagingSenderId: "123456780",
                                  appId: "myappid"
                              })
                              
                              
                              export default ({Vue}) => {
                                  Vue.prototype.$messaging = firebase.messaging()
                                  Vue.prototype.$messaging.usePublicVapidKey(myPublicVapid)
                              }
                              

                              In created hook on app level/main layout component:

                              this.$messaging.onMessage((msg) => { //listen to firebase
                              const ev = new CustomEvent(msg.data.identifier, { //msg.data is backend defined payload
                                              detail: msg.data, 
                                              bubbles: true,
                                              cancelable: true
                                           });
                                           const handled = !document.dispatchEvent(ev) //fire event
                                           if (handled) { 
                                              //event has been handled/consumed by another (child) component in the app
                                           } else {
                                              //handle event on app level if needed, e.g. fallback to generic browser notification
                                           }
                              })
                              
                              1 Reply Last reply Reply Quote 0
                              • M
                                Mickey58 last edited by Mickey58

                                @FrankM, @dobbel - I have been prototpying push notifications for my existing SPA app.

                                It has been a bit tedious to set everything up, but I got it working. It consists of 3 pieces:

                                • Registering a service worker and subscribing to push notifications - currently this resides in the created() part of my Quasar main layout (my-layout.vue)
                                • Service worker - I placed this temporarily in the /statics folder of my frontend code. This piece of code receives the push notifcations and does showNotification()
                                • Backend code: This piece of code is still experimental, it fires a push notification using the NPM web-push package

                                I got the overall mechanics working.

                                I’m a bit disappointed to learn that it is only for a single user. In order to notify all or selected groups of users, the subscription details would have to be stored for every user in my backend database. In order to notify all users, I would have to iterate through these details and create a push notification for every user.

                                This web push mechanism is pretty complicated for what it delivers.

                                I will probably experiment next with web sockets,

                                metalsadman dobbel 2 Replies Last reply Reply Quote 0
                                • metalsadman
                                  metalsadman @Mickey58 last edited by metalsadman

                                  @Mickey58 it’s complicated, but once you nail it, you can use the paradigm on several apps that needs it, i think go over @FrankM breakdown above, it’s quite extensive. it’s a sought out feature in most apps, good luck.

                                  1 Reply Last reply Reply Quote 0
                                  • dobbel
                                    dobbel @Mickey58 last edited by dobbel

                                    @Mickey58 With sockets can send the same push message to every client that is currently connected to you nodejs server.

                                    @FrankM Thanks again for the extensive samples, it gives great insight how to setup push notifications.

                                    next step implement native push notifications for mobile devices statusbar build with cordova or capacitor…

                                    1 Reply Last reply Reply Quote 0
                                    • M
                                      Mickey58 last edited by Mickey58

                                      @dobbel - yes, I had overlooked initially that these push notifications are from server to individual clients. If you want them for all clients, it is on you to to loop through all subscriptions and send push messages to every single client.

                                      I think @FrankM 's solution is the most powerful one, but probably even more complicated than my prototype for push notifications (which needs web-push package on the server).

                                      I hope web sockets can do what I need.

                                      @metalsadman - do you happen to know how Quasar has implemented the notifications that new content is available on the Quasar docs site?

                                      dobbel 1 Reply Last reply Reply Quote 0
                                      • dobbel
                                        dobbel @Mickey58 last edited by dobbel

                                        @Mickey58 The source code of the quasar doc app ( pwa + ssr) is in github if you want to know…

                                        It’s a Pwa update notification that will notifiy the user that the content has changed on server and asks in a dialog if you want to refresh now or later.( you don’t need to ask , you can also just refresh)

                                        1 Reply Last reply Reply Quote 0
                                        • M
                                          Mickey58 last edited by Mickey58

                                          @dobbel, yes, I see an app.use for a service worker in the code at https://github.com/smolinari/quasar-docs/blob/master/src-ssr/index.js, but couldn’t find the service-worker.js itself yet.

                                          dobbel 1 Reply Last reply Reply Quote 0
                                          • dobbel
                                            dobbel @Mickey58 last edited by dobbel

                                            @Mickey58 I think it’s generated by Workbox.

                                            https://quasar.dev/quasar-cli/developing-pwa/configuring-pwa

                                            https://github.com/smolinari/quasar-docs/blob/master/quasar.conf.js

                                            1 Reply Last reply Reply Quote 0
                                            • First post
                                              Last post