Unlimited Plugins, WordPress themes, videos & courses! Unlimited asset downloads! From $16.50/m
  • Overview
  • Transcript

1.2 The Slack Clone Application

In this lesson I’ll show you how you can use Milojs to create a full-stack reactive connection. You’ll see how data flows from the client model to the server, into the database, and back out to other clients. Follow along as I work through a fully functional Slack-like chat application which uses Milojs and manages to get away with very little server code.

Code Snippet

We use WebSockets to broadcast model changes from the server. The following snippet shows how the client subscribes to server events and passes data changes on to the local Milo model.

socket.on('connect', function() {
    console.log('connected');

    //initialize the database
    socket.on('db', function (msg) {
        db.set(msg.data);
        db.on('datachanges', updateDB);
    });

    //data has changed on the server
    socket.on('datachanges', function (msg) {
        //pause listening to data changes on the model
        db.off('datachanges', updateDB);
        //post the changes to the Milo model
        db.postMessageSync('changedata', msg.data);

        _.defer(function() {
            //resume listening to changes on the model
            db.on('datachanges', updateDB);
        });
    });

});

On the server side, we listen for data changes from the client that will be saved to the database and re-broadcast with WebSockets.

io.on('connection', function (socket){
    console.log('a user connected');

    //the entire database is sent whenever a new client connects
    socket.emit('db', { data: db.get() });

    //when a client sends a datachanges event
    socket.on('datachanges', function (msg) {
        //save the changes to the database
        db.postMessageSync('changedata', msg.data);
        //and re-broadcast to all the clients
        socket.broadcast.emit('datachanges', msg);
    });
});

Related Links

1.Create a New JavaScript Framework: Full-Stack Reactivity With Milo
2 lessons, 13:34

Free Lesson
1.1
Introduction
00:45

1.2
The Slack Clone Application
12:49


1.2 The Slack Clone Application

[MUSIC] Let's take a quick look at the architecture that we're using. In the client, there is a model that manages the state of s like clone application. It looks like this, with channels, property of the model, which has a list of channels. And the messages property, which has various messages in each of those channels. When a change happens on the client, messages will go from our client model, through web sockets to a server model, which is also a Milo Model. Those changes will then be propagated to the DB, changes in the DB will be detected In the server, and get broadcast back out to the clients also using web sockets. So let's get started, if you get a chance to check out the other videos on this subject, you'll see just how powerful Milo models are, unlike something like Angular, which takes a polling approach to model changes. Milo J S uses a push technique. Milo models are very chatty and will omit messages about all the changes at all levels. If I open up this models tutorial, for example, and we go into the console, we can see this is the data contained within our user object. If I get hold of the Friends Array and push a new friend [SOUND] you can see the various changes firing that we've got hooked up to the user.friends property. So this is the change for the base friend array, and here's a change to the particulate index and new item that was added. Change messages come with lots of information about what type of operation it was, and the old and new data that this change represents. After using Milojs for a while, we considered how easy it would be to pass these messages back and forth across the server, in order to create a full stack two way data binding. So as a proof of concept, we created the slack clone. You can check out the slack clone for yourself by going to GitHub, or by running this line in the command line, git clone, and then the slack clone git address. So let's take a look at the code. We'll ignore for a second the service side component, and just look at the client side code. We have a basic HTML file, which has a couple of custom mother components such as the channels pane, where the channels are loaded in, and some other components, which are out of the box. Mother components with facets attached. So this Channel's list is going to be a list of channels and inside each channel item. We're going to have the idea of the channel as the dom data component and the title as well. Here's a button to create a new channel. This has an events faster, so that we can easily subscribe to the click event. We have user handle, where the user enters their name that's a custom component as well. And then we have the actual channel of data with its metadata and a list of message items as well. So the reason that some of these are custom components and some are not, is basically because the custom components will need some kind of custom code. So let's take a look at some of these custom components. So if we ignore the Web socket code that's passing the messages back and forth, you see that the only client side code in the index file is calling Milo binder. Milo Binder will iterate over all the elements in this H T M L instantiating components to manage the various elements to which they're attached. So let's start off by taking a look at the channel's pane. It's this component here. And as you can see, it creates a list of the channels. And has a create button that opens up a small form to create new channels. The channels pane is a standard mother component with a container facet, which means it will contain child components and it wants to be able to access them inside its scope. And it subscribes to the children bound method, which is fired on all components, when all child components inside that component have all been finished binding. So on children bound, we're gonna get access to our channels list and we're going to bind that channel's list data facet with the DB channels property. Now, DB for the front end is just a Milo model. But it basically has this data loaded into it, we have a channels property and a messages property. Channels contains information about the channels. You can see it's already been updated without JavaScript channel that we just added, and the messages has all the messages obviously linked by a channel id, as some of you may notice is that we essentially have one big model managing the entire application state, and that's facilitated by Milo js's model pods. As you can see, we get access to the whole db there, but our ChannelsPane is only interested in the channels model path of the overall model. It then links that in a two-way binding with the DOM. We're also listing to click events on the Create Channel button. And that's going to call a function call createChannel, which as you can see essentially creates a brand new dialogue and contains the rest of the form data that allows us to make new channels. I won't go into this in detail but you can see that we're generating the form for that dialogue using a form schema. This is a functionality that's part of Milo U I, which is a separate library which facilitates generating U I using Milo. Form scheme itself, contains a list of items and each item has a type, a label and a model path. This model paths very important because it allows us to specify a specific part of the form model or view model. This input component should attach to it means that later on if we move this element around and even nested more deeply into the dome, it won't change our model because this will still point to the DOT title property of the model. We also have a bit of validation here and here we have a combo list, which is loading in a list of different tags that we can use to tag our channel. Now what does it mean by the fact that this is a two way data connection to the model? What it essentially means is that any changes that happen in the dumb, will also be picked up by the mind a connection and will be propagated to the Model. The easiest way to show that connection, is if I change this span and make it content editable. The span is now content editable. If I change this here make it Welcooooooome, you can see that that change has propagated into the mother model, which has been picked up by a websocket connection, which is going over the server into the DV and back out to this other client. That's because Milo knows how to deal with DOM elements and it knows how to pick up change messages in those elements. I can even go look at the DB in the server now, and you'll see that welcome has been changed to Welcooooome as well. So before we take a look at the server, I just want to show you one more interesting thing about Milo and that is the CSS facet. As I've mentioned before, the mother minder will create deep data connections between anything that is considered to be a data source in Milo. Now, the data facet which controls dom data and access to the dom data that's a data source. A milo or model or model path is also a data source, so we can connect those together. But we also went ahead and made a CSS facet, and we made that facet follow the same API as any other data source. That means that our CSS can also be considered a data source. This means that we can have data driven CSS and CSS facet allows for a very declarative way of defining the CSS rules. So When UserHandle property changes. It's going to run through this isAuthor function ,and if the UserHandle is equal to the current users handle or name, then we're going to have a specific CSS class set and we can see that already on these messages here. If it's a message typed by myself. You see it has slightly different style. It's got bold. And a blue color for the message item. Whereas messages typed by other people, did not match that rule. So they'll come without the current user class we can see that. This is a very powerful way of managing your CSS styles and allows you to base the design of your application in your components on the state of the data of the app. Okay, so we've been playing with this for a while, let's take a look at this live reactive data connection between server and client. So on the server, you'll see that our database module is basically just creating a new Milo model around db json so this is the data going into the model and then it's listing out for change data on that model. Change data has a higher level event that's used by models to pass their changes about to other data sources. It's not generally used by users. You as a user would usually subscribe to a particular property on the model. The change data event gets fired off for everything within throttling this update db function. Which basically just overrides the db json file with a new string of five version of the whole tb. Now, this is obviously not in any way efficient or performant. But if you're writing this is a real application, it wouldn't be particularly difficult to work out exactly what subset of the model had changed. And to update just that part in the db. And of course your db wouldn't be a Json file. But as an example, it's a nice simple way to get our point across. Every time that changes the actual mother model that's going to update in the database. Then we have our main server file. Now most of this file is pretty straightforward, it's a simple express app and when you hit the root, it's going to send you the index file. That's fine. What we're doing here though, we've required socket I O and on connection to socket I O, we're going to emit the entire state of the db. Once again, you could totally work this out so that it's only emitting a part of the state depending on how your application is structured. But we're just sending along the whole db and then, we're subscribing to data changes on the socket. This is going to be a custom message that we're going to emit on the socket in the client. So when data changes happen, we're going to post a message to the db with message data. We have to specify postMessageSync because all messages by default in Milo are asynchronous. This is for performance reasons in the client and to prevent U I lock up, when lots of messages is being sent. We will then go socket broadcast emit these data changes to all the other clients. This will make sure that we only emit those changes to all the other clients rather than the one that actually sent us the message. In the client to complete the connection, all we need to do is listen for connection on socket. When we get that db message that was emitted on connection, we're going to set our db to the initial data. And then, we're going to subscribe to data changes. This subscription will be listening out for changes. And we're going to subscribe to data changes on our client model, so that we can pass all those messages, all those change messages on through the sockets to the server, whenever our local client database changes. And the socket data changes subscription is listening to those data changes coming from the server. And this, all we need to do is unsubscribe from data changes, post asynchronous data change message to our local db and then re subscribe after a defer this is just to make sure that we don't re emit those changes and end up with an infinite circular loop. When we post those data changes to our local db because it's a Milo model, it's going to emit those changes locally within our application and the changes in the db will update the DOM as it goes through these two way data connection set up using Milo minder. Here's the one binding the list of channels to the channels list in the DOM. And here's another one binding the messages in the messages db to the list of messages in the DOM as well. So there you can see, with very little code on both the server and the client, we're able to create. Create a two way reactive data binding between server and client. And despite it not even being that much code, it's even simpler when you just think about it. We have to do this little dance here around unsubscribing and resubscribing, so that we don't get a circular connection but to put it into words, all we're doing is passing molar modal changes. Over web sockets, between client and server, and back out to other clients again. Updating the database along the way. Let's alter this video. I hope of showing you how powerful Milo can be, and in particular Milo models and Milo data connections using [INAUDIBLE]. It's my intention to split apart core Milo components, so they can be used separately in applications without having to use the whole framework. If you check out the Milo js get have organization, you should be able to find some of those components that have already been split out by the time you see this video, I should hopefully finished splitting out by the messenger, which is a very useful mix in along with Milo models which could be used in any application as a powerful reactive JavaScript model. Well, that's all for me. Bye.

Back to the top