Uncategorized

Introduction

React Hooks are one of those things I decided I would look at later. I’ve read and heard great things about it, so I later is now. I had a component with a form that I thought could be refactored using hooks, so I started with that. Always easier to begin with small steps.

Before

Nothing fancy, we use the material-ui framework to create a Dialog component. Then we have three TextFields ( text inputs ) inside of it:

export default class AddItemPopup extends React.Component {

    constructor(props){
        super(props)
        this.state = {
            name: '',
            quantity: 0,
            unitCost: 0
        }
    }

    handleInputChange = e => {
        const {name, value} = e.target
        this.setState({
            [name]: value
        })
    }

    addItem = () => {
        const {name, quantity, unitCost} = this.state

        if(!name || !quantity || !unitCost) return

        this.props.saveItem(this.state)
    }

    render(){

        const {open, closePopup} = this.props
        const {name, quantity, unitCost} = this.state
        return(
            <Dialog 
                open={open}
                onClose={closePopup}>
                <DialogTitle>Add new item</DialogTitle>
                <DialogContent>
                    <TextField 
                        name='name'
                        label='Item name/Description'
                        onChange={this.handleInputChange}
                        value={name}/>
                    <TextField 
                        name='quantity'
                        label='Quantity'
                        onChange={this.handleInputChange}
                        value={quantity}/>
                    <TextField 
                        name='unitCost'
                        label='Unit Cost'
                        onChange={this.handleInputChange}
                        value={unitCost}/>
                </DialogContent>
                <DialogActions>
                    <Button onClick={closePopup} color="secondary" variant="contained">
                        Cancel
                    </Button>
                    <Button onClick={this.addItem} color="primary" variant="contained">
                            Save
                    </Button>
                </DialogActions>
            </Dialog>
        )
    }
}
            

I saved you the imports at the top of the file, but you got the idea. A class component with a form and a state to keep track of the form inputs’ values. Now, let’s rewrite this component by using the useState hook.

// Import the hook first
import React, {useState} from 'react'

const AddItemPopup = ({
    open, 
    closePopup,
    saveItem
}) => {

    const handleInputChange = e => {
        const {name, value} = e.target
        setValues({...values, [name]: value})
    }

    const addItem = () => {
        const {name, quantity, unitCost} = values

        if(!name || !quantity || !unitCost) return

        saveItem(values)
    }
        // Declare our state variable called values
        // Initialize with our default values

    const [values, setValues] = useState({name: '', quantity: 0, unitCost: 0})
    return(
        <Dialog 
        open={open}
        onClose={closePopup}>
        <DialogTitle>Add new item</DialogTitle>
            <DialogContent>
                <TextField 
                    name='name'
                    label='Item name/Description'
                    onChange={handleInputChange}
                    value={values.name}/>
                <TextField 
                    name='quantity'
                    label='Quantity'
                    onChange={handleInputChange}
                    value={values.quantity}/>
                <TextField 
                    name='unitCost'
                    label='Unit Cost'
                    onChange={handleInputChange}
                    value={values.unitCost}/>
            </DialogContent>
            <DialogActions>
                <Button onClick={closePopup} color="secondary" variant="contained">
                    Cancel
                </Button>
                <Button onClick={addItem} color="primary" variant="contained">
                        Save
                </Button>
            </DialogActions>
        </Dialog>
    )
}

export default AddItemPopup

BOOM! Our component became a function now. What did we do:

  • useState returns two things: the current state ( here as values ) and a function that lets you update it ( here as setValues )
  • useState takes one argument: the initial state.
  • The onChange handler function now uses this setValues function to modify the internal state of the component. As you can see, the values variable is accessible everywhere is the component.

Note: We could have used three different hooks to update each input separately, whatever you think might be more readable to you 😉

Read more

Introduction

You may have heard about closures. You most certainly already use them even if you don’t fully know what they are. Closures require you to know:

Three facts:

Fact One: In Javascript, you can refer to variables defined outside of the current function.

function makeCookies(){
    const secretIngredient = "coconut oil"
    function bake(chocolate){
        return secretIngredient + " and " + chocolate
    }

    return bake("white chocolate")
}

makeCookies() // coconut oil and white chocolate

Here, we can see that the inner function bake can access the variable secretIngredient, even though it was defined in the outer makeCookies function.

Fact Two: Functions can refer to variables defined in outer functions even after those outer functions returned!

Because functions are first-class objects, you can store functions inside variables and call them later on. I’ve talked about higher-order functions in a [https://dev.to/damcosset/higher-order-functions-in-javascript-4j8b](previous article)

function cookiesMaker(){
    const secretIngredient = "coconut oil"
    function bake(chocolate){
        return secretIngredient + " and " + chocolate + " chocolate."
    }

    return bake
}

const func = cookiesMaker() // Storing the function in a variable

Here, cookiesMaker is called and we store the result of that function inside a variable. If you print out the func variable right now, you would see the bake function.

The bake function uses a variable declared outside of the bake function (secretIngredient). The bake function can still remember that variable even if cookiesMaker has already returned.

func("black") // coconut oil and black chocolate.
func("white") // coconut oil and white chocolate.

How is this possible? Well, in Javascript, function values do not just store the code required to execute when they are called. They also store any references to variables they need to execute. Functions like the bake function, who refer to variables declared in their containing scopes are known as closures.

The bake function here keeps track of two variables declared in its containing scope: secretIngredient and chocolate.

When we call bake afterwards, it still remembers those two variables because there were stored in the closure.

A closure can refer to any variable or parameter in its scope. Check this out:

function cookiesBaker(cook){
    return function addSecretIngredient(secretIngredient){
        return function bakeCookie(chocolate){
            return `${cook} cooked a ${secretIngredient} ${chocolate} chocolate cookie.`
        }
    }
}

In this example, the inner function bakeCookie refers to a parameter from the outer cookiesBaker function (cook), a parameter from the outer addSecretIngredient function (secretIngredient) and a parameter from its own scope (chocolate).

const cook = cookiesBaker("Damien")

const secret = cook("peanut butter")

const result = secret("white")
// Damien cooked a peanut butter white chocolate cookie.

Here, we are taking one more step.

We return the inner function addSecretIngredient and store that in a variable. Then, we call that stored function, the result ( bakeCookie ) is stored inside another variable. Finally, we call that function. The final results, as you can see, remembers all the variables stored inside the closure.

We can also use this to make more general-purpose functions.

Let’s say we want to create a function for all cookies baked by Johnny:

const bakedByJohnny = cookiesBaker("Johnny")

bakedByJohnny("coconut oil")("black") // Johnny cooked a coconut oil black chocolate cookie.

bakedByJohnny("")("milk") // Johnny cooked a  milk chocolate cookie.

Notice that instead of declaring a variable and storing the intermediate function inside it. I can call the inner function immediately because bakedByJohnny(“coconut oil”) is returning a function!

Ok, another little example. Let’s create a function for all cookies baked by Sarah with peanut butter:

const bakedBySarahPeanutButter = cookiesBaker("Sarah")("peanut butter")

bakedBySarahPeanutButter("white")
//Sarah cooked a peanut butter white chocolate cookie.

bakedBySarahPeanutButter("black")
// Sarah cooked a peanut butter black chocolate cookie.

bakedBySarahPeanutButter("milk")
// Sarah cooked a peanut butter milk chocolate cookie.

Even though the two functions we created come from the same function definition, they are two distinct objects and both store different variables.

Note: The functions can be anonymous, like so:

let cookiesBaker = function(cook){
    return function(secretIngredient){
        return function(chocolate){
            return `${cook} cooked a ${secretIngredient} ${chocolate} chocolate cookie.`
        }
    }

This code would give the exact same results than before!

Fact Three: Closures can not only remember the variable in their containing scope, they can also update it.

Consider the following example:

const secretIngredient = function(){
    let ingredient = undefined
    return {
        changeIngredient: newIngredient => { ingredient = newIngredient },
        showIngredient: () => ingredient,
        type: () => typeof ingredient
    }
}

This function returns 3 closures. Each method in the object returned refer to a variable defined in the containing scope.

Now, let’s prove that closures can not only read outer variables, they can also update them:

let i = secretIngredient()

i.showIngredient() // undefined
i.type() // undefined

i.changeIngredient("coconut oil")

i.showIngredient() // coconut oil
i.type() // string

Tadaaaaa!

Conclusion

Closures are one of those things that you most likely use very often. You probably didn’t even know about it! Check your code and try to identify closures, get comfortable with them, and use their full powers!

Read more

Introduction

In Javascript, functions are values ( first-class citizens ). This means that they can be assigned to a variable and/or passed as a value.

let random = function(){
    return Math.random()
}

let giveMeRandom = random // assigning random to a variable

This single piece of knowledge allows us to write functional programming in this language. In functional programming, we heavily use higher-order functions.

Higher-order functions?

Higher-order functions are functions that take other functions as arguments or return functions as their results.

Taking an other function as an argument is often referred as a callback function, because it is called back by the higher-order function. This is a concept that Javascript uses a lot.

For example, the map function on arrays is a higher order function. The map function takes a function as an argument.

const double = n => n * 2

[1, 2, 3, 4].map(double) // [ 2, 4, 6, 8 ]

Or, with an anonymous function:

[1, 2, 3, 4].map(function(n){
    return n * 2
}) // [ 2, 4, 6, 8 ]

The map function is one of the many higher-order functions built into the language. sort, reduce, filter, forEach are other examples of higher-order functions built into the language.

Higher-order functions allows you to write simpler and more elegant code. Let’s look at what the code above would look like without such an abstraction. Let’s replace the map function by a loop:

let array = [1, 2, 3, 4]
let newArray = []

for(let i = 0; n < array.length; i++) {
    newArray[i] = array[i] * 2
}

newArray // [ 2, 4, 6, 8 ]

The power of composition

One of the great advantages of using higher order functions when we can is composition.

We can create smaller functions that only take care of one piece of logic. Then, we compose more complex functions by using different smaller functions.

This technique reduces bugs and makes our code easier to read and understand.

By learning to use higher-order functions, you can start writing better code.

Example

Lets try with an example. Assume we have a list of grades from a classroom. Our classroom has 5 girls, 5 boys and each of them has a grade between 0 and 20.

var grades = [
    {name: 'John', grade: 8, sex: 'M'},
    {name: 'Sarah', grade: 12, sex: 'F'},
    {name: 'Bob', grade: 16, sex: 'M'},
    {name: 'Johnny', grade: 2, sex: 'M'},
    {name: 'Ethan', grade: 4, sex: 'M'},
    {name: 'Paula', grade: 18, sex: 'F'},
    {name: 'Donald', grade: 5, sex: 'M'},
    {name: 'Jennifer', grade: 13, sex: 'F'},
    {name: 'Courtney', grade: 15, sex: 'F'},
    {name: 'Jane', grade: 9, sex: 'F'}
]

I want to know a few things about this:

  • The average grade of this classroom
  • The average grade of the boys
  • The average grade of the girls
  • The higher note among the boys
  • The higher note among the girls

We will try to use higher-order functions to get a program that is simple and easy to read. Let’s start by writing simple functions that can work together:

let isBoy = student => student.sex === 'M'

let isGirl = student => student.sex === 'F'

let getBoys = grades => (
    grades.filter(isBoy)
)

let getGirls = grades => (
    grades.filter(isGirl)
)

let average = grades => (
    grades.reduce((acc, curr) => (
        acc + curr.grade
    ), 0) / grades.length
)

let maxGrade = grades => (
    Math.max(...grades.map(student => student.grade))
)

let minGrade = grades => (
    Math.min(...grades.map(student => student.grade))
)

I wrote 7 functions, and each of them has one job, and one job only.

isBoy and isGirl are responsible for checking if one student is a boy or a girl.

getBoys and getGirls are responsible for getting all the boys or girls from the classroom.

maxGrade and minGrade are responsible for getting the greatest and lowest grade in some data.

Finally, average is responsible to calculate the average grade of some data.

Notice that the average function doesn’t know anything about the type of data it’s suppose to process yet. That’s the beauty of composition. We can re-use our code in different places. I can just plug this function with others.

Now, we have what we need to write higher-order functions:

let classroomAverage = average(grades) // 10.2
let boysAverage = average(getBoys(grades)) // 7
let girlsAverage = average(getGirls(grades)) // 13.4
let highestGrade = maxGrade(grades) // 18
let lowestGrade = minGrade(grades) // 2
let highestBoysGrade = maxGrade(getBoys(grades)) // 16
let lowestBoysGrade = minGrade(getBoys(grades)) // 2
let highestGirlsGrade = maxGrade(getGirls(grades)) // 18
let lowestGirlsGrade = minGrade(getGirls(grades)) // 9

Notice that the outer functions, average for example, always take as an input the output from the inner functions. Therefore, the only condition to composition is to make sure that the output and input match.

And because each function is responsible for only one thing, it makes our code that much easier to debug and to test.

Composition rules!

Read more

Introduction

The #100DaysOfCode is a challenge that aims at making coding a habit. The concept is very simple. Every day, you spend at least an hour doing non-work related programming. The challenge also insists on building projects, and not spending your time doing only tutorials or following courses. You must put what you learned in practice doing real projects. The projects are totally up to you of course, depending on your current skills and/or needs.

You can find more information about the #100DaysOfCode on Alexander Kallaway’s blog post.

The most important thing, in my opinion, is not the habit in itself, though it is very important. The crucial thing to me is being accountable. Hundreds of people are taking this challenge. You have the knowledge that you are not alone. You are also committing to tweet your progress and encourage at least two people each day. There is a level of accountability and connectivity with other people that just make the whole thing so much more appealing to me, and therefore, I feel confident I will be able to do it.

What to build?

That is the bit question that I had. I finished the FreeCodeCamp curriculum, all three certificates. So, I won’t be re-building any of those projects. In my opinion, in order to succeed, the projects I will choose must follow a few rules:

  • Must not take too much time to realise (the goal is to create several projects in that timeframe of 100 days)
  • Must be challenging, but not impossible. I’m not the best developer out there, so I need to choose projects I an actually do. In the mean time, the goal is to push myself, I must choose something outside of my comfort zone.
  • Must be something I would like to do. There are billions of different things I can code, but not every single one will be appealing to me. This is outside of work. **Having fun **is the number one thing I’ll be worried about.

Every single project I will choose to do will have to follow those three rules.

The brainstorm (!!!)

I spent a little bit of time thinking about this, and I cam up with this, so far:

  • War (Card Game)
  • Make a Diary application
  • Make an app using the NASA’s API
  • Belote (French Card Game)
  • A real-time application (socket.io)
  • Something with Bots ?

Here are 6 different projects that I came up with. As you can see, it is still very vague. I only researched the first one a bit deeper (War). In the holidays, I played a lot of card games with my family. That was amazing and this is why I put two cards game in there. The socket.io application is kinda related to my work, but I always enjoyed working with real-time technologies. The rest are just the scratch your own itch type of application.

Will I be able to do all of this in 100 days? Doesn’t matter. The goal is to build an habit of coding every day. The goal is to make sure that you are use to be outside your comfort zone and learn every day.

In each of theses applications I want to build, there are things I don’t have much experience with. The animations that will be required in the cards games for example, never used that before.

So, this is it! I’m personally starting tomorrow (January 3rd). I look forward to see any of you on this path.

As always, feel free to comment and share.
Have a nice day!

Read more

Introduction

I recently started to work with a company as a freelancer. As I got access to the source code, I had the chance to look around at what technologies were used and the particular syntax that the software was written into. The software uses Socket.io for most of the communication client-server. But, as I was looking at the packages used and the code, one of those packages was socketio-file-upload. With this blog post, I’ll try out this package in order to understand better what it is supposed to do. Let’s jump into it!

What is it?

Here is the description we can read from the github link I gave you in the introduction.

This module provides functionality to upload files from a browser to a Node.JS server that runs Socket.IO. Throughout the process, if their browser supports WebSockets, the user will not submit a single HTTP request. Supports Socket.IO 0.9 and 1.0.

The intended audience are single-page web apps, but other types of Node.JS projects may benefit from this library.

Since version 0.4, this module also supports monitoring file upload progress.

Simply put, you can upload files from the client to the server using sockets. I upload a file, without using AJAX or any HTTP requests and it will be saved by the server, in a directory of my choice. Let’s see that!

Begin by create a new directory, and run npm init

Accept all the defaults and then run:

npm install --save socketio-file-upload express pug socket.io

We will connect the router of the socketio-file-upload to express later.

Let’s create a file called server.js

server.js

const express = require('express');
const app = express();
const httpServer = require('http').Server(app);
const path = require('path');
const siofu = require('socketio-file-upload');
const socketServer = require('socket.io')(httpServer);

app.set('view engine', 'pug');
app.set('views', path.join(__dirname, '/public/views'));
app.use(express.static(path.join(__dirname, '/public')));
app.use(siofu.router);

app.get('/', (req, res) => {
    res.render('index');
});

socketServer.on('connection', socket => {
    console.log('Socket connected');
    socket.emit('data', 'Hello World');
    const uploader = new siofu();
    uploader.dir = path.join(__dirname, '/files');
    uploader.listen(socket);
});

httpServer.listen(3000);

Ok, let me explain a little but this code. Most of it is setting a socket.io server with express and and http server. If you don’t know how to do this, I wrote a blog post on getting started with socket.io.

After all this setup, you can direct your attention to the socketServer connection. You can see that we instantiate a new SocketIo-file-upload instance(named uploader). Then, we tell this instance where we want the file to be upload. In this case, I want my files to go to the /files directory. Finally, this instance needs to listen to the socket that just connected.

Note: Socketio-file-upload will NOT create the directory for you if it doesn’t exist. It will throw an error instead.

That is all we need for the back-end. Let’s code our front-end now. We will use several methods from the socketio-file-upload package. First, in your public/views directory, create a file called index.pug :

index/pug

h1 Hello Index
input(type='file')#fileUpload
button#file_button ClickHere
script(src='/socket.io/socket.io.js')
script(src='/siofu/client.js')
script(src='../js/main.js') 

Nothing crazy here, a file input and a button to play around with a method we’ll see in our js file. Then, we link to our 3 different scripts. One for the socket.io library, one for the socketio-file-upload library (both are in our node_modules directory) and one for our custom script called main.js. Let’s see our custom main.js:

//Connection to the socket library
const socket = io();

//This is some classic socket.io event listening
socket.on('data', data => {
    console.log(data);
});

//Here is our socketio-file-upload code
const uploader = new SocketIOFileUpload(socket);

uploader.listenOnInput(document.getElementById('fileUpload'));

uploader.addEventListener('start', (event)=> {
    event.file.meta.extension = 'csv';
});

document.getElementById('file_button').addEventListener('click', uploader.prompt, false);

Ok, here is how we do things. We create a new SocketIOFileUpload instance, with our socket as a parameter. We can use the listenOnInput method on our input file. As you can see, we pass the DOM element that we want to listen to. When we will choose a file, we will trigger this event.

When we do that, we will go back to our server.js file. Our socketio-file-upload instance on the back-end will receive this file (remember that it listens to our socket). Once it receives this file, it will store it in the directory that we specified.

I added some custom code on the start event of the instance. You can write on the event.file object for example. Here, I decided to add extension : 'csv' to the meta object. You can imagine that the possibilities are infinite when it comes to playing with the object.

Lastly, you might have seen on the index.pug that I added a button. The last two lines on main.js adds an event listener to a click event on this button. I use the instance.prompt method (instance being here uploader). This will trigger the opening of the same window you would have on a input file.

That’s it! Those are just a few methods available on the socketio-file-upload package. To learn more, you can visit the very good github socketio-file-upload page. You can peak at the documentation to learn more.

Note: you may wonder what is the difference between this package and the socket.io streams package. The stream package will be user to read files. We create a stream to read the contents of the file. With this package, we do not read it, we store it in our files directory (in our case). We could of course read the file with a socket stream and then upload it. Or upload it, then read it with a stream. Both those packages could be very complementary in my opinion.

Feel free to share and comment!
Have a nice day!

Read more

Introduction

Yesterday, I received my Pavlok. If you are not familiar with it, Pavlok is a device that is focused on changing your habits with the help of electrical stimulus. The most effective way to use it is to zap yourself when you are doing a bad habit. For example, every time I bit my nails, ZAP!

The Pavlok system tries to break the cue-routine-reward path by making the reward not as pleasant. If your habit is rewarded by an electric shock, your brain will associate this habit with pain or discomfort. Because we are creatures of pleasure, we will most likely stop doing this habit.

But, as a part of the Internet of Things trend, Pavlok also allows you to customise its use and add some tweaks. For example, there is a Chrome extension available. If I spend too much time on Twitter, I will get zapped. I also linked my Pavlok with RescueTime. This way, I get notified when I’m being productive (vibrating), when I could do better (beeping) and when I’m being baaaaaad (ZAAAAP !).

Ok, so this is great. But the even cooler part is this: Pavlok has a developer API that allows us to interact with our devices through code. This is what this post is about: getting started with the Pavlok developer API.

Getting started

We will use Node.JS to achieve this. First things first, we need to register our application, the same way we would do with Twitter in order to use its API. To do this, visit this page. Enter the name of your app and for the callback URL, just enter http://localhost:3000/auth/pavlok/result .

Great, now our app is registered. You will get a Client ID and a Client Secret. We will need them in our app.

Create a file, let’s call it test.js.

First, run npm init. Select the defaults and then run npm install --save pavlok-beta-api-login

Let’s write our code!

const pavlok = require('pavlok-beta-api-login');
const ClientID = "YOUR_CLIENT_ID";
const Secret = "YOUR_SECRET_ID";

// Init your device
pavlok.init(ClientID, Secret, {
        verbose: true,
        port: 3000
});

//login
pavlok.login( (result, code) => {
    if(result){
        console.log('Code is', code);
    }
});

// Your device will beep
pavlok.beep();

//Your device will vibrate
pavlok.vibrate();

//This is a pattern
// (Beep & Vibrate) * 3
pavlok.pattern({
"pattern": ['beep', 'vibrate'],
"count": 3
});

And that is all we need!
Run node test.js and your device will respond to the stimuli. You Pavlok application will also receive notifications with the name of your app! Awesome!!

Note that the code will be different if you host your application. On local, this code will be fine. But if you need to host it, you’ll need to change a few things. You can check the npm pavlok wiki page to get more information on how to do this.
You can get more information about the device on the Pavlok website and more information on the Developer API can be found on the Pavlok Developer API

I’ll post more informations as I keep playing with it. But this is enough to get you started. Have fun!

Feel free to comment and share!
Have a nice day!

Read more

Introduction

In this article, we will see very simply how to use namespaces with socket.io. Namespaces allow us to group sockets based the page the user visits. In our example, we will use three different groups. One group will contain the sockets in the index page ‘/’, another in the ‘/products’ page and another one in the ‘/contact’ page.

First things first, create a directory that will hold our project. Then, run npm init. Accept the defaults and then install our needed dependencies with :

npm install --save express socket.io 

Ok, now create 4 files, server.js, index.html, products.html, contact.html.

Let’s start with our server.js:

const express = require('express');
const http = require('http');

const app = express();
const server = http.Server(app);
const ioServer = require('socket.io')(server);

//Namespaces Socket.io
const indexUsers = ioServer.of('/');
const productsUsers = ioServer.of('/products');
const contactUsers = ioServer.of('/contact');

// Express file rendering
app.get('/', (req,res)=> {
    res.sendFile(__dirname + '/index.html');
});

app.get('/products', (req,res)=> {
    res.sendFile(__dirname + '/products.html');
});

app.get('/contact', (req,res)=> {
    res.sendFile(__dirname + '/contact.html');
});

// socket.io logic

//Index page sockets
indexUsers.on('connection', socket => {
    socket.emit('connectionMessage', 'Welcome to the index page');
});

//Products page sockets
productsUsers.on('connection', socket => {
    socket.emit('connectionMessage', 'Welcome to the products page');
});

//Contact page sockets
contactUsers.on('connection', socket=> {
    socket.emit('connectionMessage', 'Welcome to the contact page');
});

server.listen(3000);

Quick explanation: We begin by initialising our socket.io server like usual. We use express to server our three html files. Nothing crazy so far. But notice that we define three variables with the of() method on our ioServer. This tells socket.io that depending on the connection made in the front-end, we will group sockets differently. We are then able to use the emit event (or the on event) on those namespaces like any other socket. Let’s see how our three html files will look.

They all look very similar, but I wanted to make sure that everything was clear.

index.html

<!DOCTYPE html>
<html>
    <head>
        <title>Index Page</title>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/1.7.1/socket.io.js"></script>
    </head>
    <body>
        <h1>Welcome to the Index Page</h1>
        <h3 id="message"></h3>
        <script>
            const socket = io('/');

            socket.on('connectionMessage', message => {
                document.getElementById('message').innerHTML = message;
            });
        </script>
    </body>
</html> 

products.html

<!DOCTYPE html>
<html>
    <head>
        <title>Products Page</title>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/1.7.1/socket.io.js"></script>
    </head>
    <body>
        <h1>Welcome to the Products Page</h1>
        <h3 id="message"></h3>
        <script>
        const socket = io('/products');

        socket.on('connectionMessage', message => {
            document.getElementById('message').innerHTML = message;
        });
        </script>
    </body>
</html>

contact.html

<!DOCTYPE html>
<html>
    <head>
        <title>Contact Page</title>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/1.7.1/socket.io.js"></script>
    </head>
    <body>
        <h1>Welcome to the Contact Page</h1>
        <h3 id="message"></h3>
        <script>
            const socket = io('/contact');

            socket.on('connectionMessage', message => {
                document.getElementById('message').innerHTML = message;
            });
        </script>
    </body>
</html>

Alright, the structure of those files is exactly the same. Standard html, with a script for the socket.io CDN. Then, two headers, a h1 that tells us on which page we are on, and an h3 with the id of message. In our script, the socket reacts to the connectionMessage event by putting the message in our h3.

Can you spot the difference between those files?
The definition of our socket is different. The argument in our io() function is what creates the namespace. In combination with the variables definition we did in server.js, we created separated groups of sockets that can emit and respond to socket events independently from one another. Pretty cool huh?

And that’s it! This is a very simple beginning, just to make you understand how this thing works. Of course, this opens a lot of different possibilities. Go ahead and experiment!

As always, feel free to comment or share.

Have a nice day!

Read more