Socket.IO runs on both client and server, with the two communicating back and forth over the HTTP connection. This requires loading the client JavaScript library into the client browser. Each page of the Notes application in which we seek to implement Socket.IO services must load the client library and have custom client code for our application.
Each page in Notes will require a different Socket.IO client implementation, since each page has different requirements. This affects how we load JavaScript code in Notes.
Initially, we simply put JavaScript code at the bottom of layout.hbs, because every page required the same set of JavaScript modules. But now we've identified the need for a different set of JavaScript on each page. Furthermore, some of the JavaScript needs to be loaded following the JavaScript currently loaded at the bottom of layout.hbs. Specifically, jQuery is loaded currently in layout.hbs, but we want to use jQuery in the Socket.IO clients to perform DOM manipulations on each page. Therefore, some template refactoring is required.
Create a file, partials/footerjs.hbs, containing:
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
<script src="/assets/vendor/jquery/jquery.min.js"></script>
<script src="/assets/vendor/popper.js/umd/popper.min.js"></script>
<script src="/assets/vendor/bootstrap/js/bootstrap.min.js"></script>
<script src="/assets/vendor/feather-icons/feather.js"></script>
<script>
feather.replace()
</script>
This had been at the bottom of views/layout.hbs. We now need to modify that file as follows:
<body>
{{> header }}
{{{body}}}
</body>
Then, at the bottom of every template (error.hbs, index.hbs, login.hbs, notedestroy.hbs, noteedit.hbs, and noteview.hbs), add this line:
{{> footerjs}}
So far, this hasn't changed what will be loaded in the pages, because footerjs contains exactly what was already at the bottom of layout.hbs. But it gives us the freedom to load Socket.IO client code after the scripts in footerjs are loaded.
In views/index.hbs add this at the bottom, after the footerjs partial:
{{> footerjs}}
<script src="/socket.io/socket.io.js"></script>
<script>
$(document).ready(function () {
var socket = io('/home');
socket.on('notetitles', function(data) {
var notelist = data.notelist;
$('#notetitles').empty();
for (var i = 0; i < notelist.length; i++) {
notedata = notelist[i];
$('#notetitles')
.append('<a class="btn btn-lg btn-block btn-outline-dark"
href="/notes/view?key='+
notedata.key +'">'+ notedata.title +'</a>');
}
});
});
</script>
The first line is where we load the Socket.IO client library. You'll notice that we never set up any Express route to handle the /socket.io URL. Instead, the Socket.IO library did that for us.
Because we've already loaded jQuery (to support Bootstrap), we can easily ensure that this code is executed once the page is fully loaded using $(document).ready.
This code first connects a socket object to the /home namespace. That namespace is being used for events related to the Notes homepage. We then listen for the notetitles events, for which some jQuery DOM manipulation erases the current list of Notes and renders a new list on the screen.
That's it. Our code in routes/index.mjs listened to various events from the Notes model, and, in response, sent a notetitles event to the browser. The browser code takes that list of note information and redraws the screen.