Creating a Document Sharing Site With Meteor.js
“Meteor is a set of new technologies for building top-quality web apps in a fraction of the time, whether you’re an expert developer or just getting started.” - Meteor.com
Create and deploy a real time document sharing website. The final product is at: docshare-tutorial.meteor.com.
Updated: Source code at https://github.com/skalb/docshare-tutorial
- Single page app with two sections
- Section 1
- List of documents each with edit and delete buttons
- Create new document button with name input
- Section 2
- Text area of the document currently being edited
- Install Meteor
Step 1: Getting things started
Lets create the app:
Now, start the meteor server:
You should see the default site at http://localhost:3000:
Lastly, add the other packages we are going to use
Step 2: Setting up the project
Go ahead and delete docshare-tutorial.js and empty out the contents of docshare-tutorial.html.
Meteor lets you separate client and server code in 2 different ways:
- Using the Meteor.is_client and Meteor.is_server flags
I prefer method 2 since it feels a bit cleaner to me, but feel free to instead combine everything into one file. Create docshare-tutorial.coffee at the root and client.coffee in /client folder and server.coffee in the /server folder.
Step 3: Server
Collections in Meteor are schemaless. We want our documents collection to be available to both the server and the client so we’ll add it to the root level.
Our document object will have two fields: name and text. Let’s create a sample document on startup.
1 2 3 4 5
Now, if you restart the meteor server, you’ll be able to access that document in the browser. Try this in the developer console:
You will see an object with the properties we just created. This is the only time you should need to restart the meteor server.
Step 4: Client HTML
Here’s we’ll define our head and body. The body will render two templates: documentList and documentView.
1 2 3 4 5 6 7 8
Next, create the two templates needed to display the documents: documentList and document.
1 2 3 4 5 6 7 8 9 10 11
Here we are using the built in Handlebars iterator #each to render the individual document objects. Finally, there’s a input field and create button to add a new document.
Now add the template to list the documents names each with an edit and delete button. We’ll also use a template method to determine which document is selected.
1 2 3 4 5 6 7 8 9
Lastly, let’s add the actual text field that the users can edit.
1 2 3 4 5 6 7 8 9 10
Note that this will only be rendered if a document is currently selected. Having both an #if and a #with seems redundant, but I didn’t see a better way. Based off the Handlebars documentation, I should only need the #if, but that doesn’t work.
Step 5: Client Coffeescript
First, we’ll setup a Backbone router to allow us to keep track of which document we’re viewing. This will allow us to support page refreshes and permalinking to documents.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Basically this will store the document_id into the Meteor session whenever the user navigates to a URL or form /:document_id. If you’re not familar with Backbone, don’t worry about this, or read up at http://backbonejs.org/
We are also using Meteor.startup again here but for a different purpose. On the client side it will run after DOM is loaded every time. I think it would be more clear if this method didn’t mean different things based on context.
Next, we need to define where the documentList template gets its data and handle the create new button
1 2 3 4 5 6 7 8 9 10 11 12 13 14
Notice that we’re sorting the documents by name. Each time a new document is added it will be correctly injected into the DOM. The entire list is not recreated. There is also a bit of validation to make sure the name exists.
Documents.insert (and all collection operations) are non-blocking when called client side. Meteor will go ahead and insert the data to the local client and can optionally call a callback with an object identifier or error message after the real operation finishes. This is invisible to the user, of course.
Next, define the selected property and event handlers for edit and delete:
1 2 3 4 5 6 7 8
Note that in handlers for events the this object is the actual Document object.
Next, define the selectedDocument using the id stored in the session and update the text of that document when the user presses a key.
1 2 3 4 5 6 7 8 9 10 11 12
Meteor acknowledges in their docs: “For now, the event handler gets the template data from the top level of the current template, not the template data from the template context of the element that triggered the event. This will be changing.” This is why we have to pull the id from the session.
Lastly, add the css style for the selected div:
1 2 3
Conclusion: That’s it, done! 50 lines of HTML and 50 lines of Coffeescript for a very basic Google docs clone.
To test it out open two browsers and type!