Instructions for building this Meteor CRUD app, a basic app for teaching Meteor basics.
- Run
git clone [email protected]:andersr/meteor_crudfrom your terminal, followed bycd meteor_crud - Open the current directory in a text editor (eg using
edit .) - (If you were creating this app from scratch, you would simply have typed
meteor create appin this directory.) - Cd into the "app" directory and run
meteorfrom the command line. - Open a browser window and enter the URL: http://localhost:3000
- Leave this window open while building the app. Meteor will auto-refresh as you make changes.
- Why have your app in an "app" sub-directory? Making your app a sub-directory of your working directory allows for making external files, such as config files, build files, etc, be part of your repo without being mixed in with actual app files.
- Delete the default files: app.html, app.js, app.css (
eg using rm app*) - Add client, lib, and server directories:
mkdir client lib server(Files in 'client' will only run on the client, files in 'server' will only run on the server, while files in 'lib' will be loaded first and run on both the server and client.) - Learn more about recommended Meteor file structure: http://meteortips.com/first-meteor-tutorial/structure/
- Run
git checkout step1-file-structurefor the finalized version of this step.
- Add a meteor bootstrap package:
meteor add twbs:bootstrap(Optional: add a Sass package, which we'll use later:meteor add fourseven:scss) - In client/templates/, add an index page with
<head>and<body>blocks only, containing some basic markup for layout. This will be the core app page.
<head>
<title>Meteor CRUD</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<nav class="navbar">
<div class="container">
<div class="navbar-header">
<h2 class="navbar-brand">Meteor CRUD</h2>
</div>
</div>
</nav>
<div class="container">
(Main page content goes here)
</div>
</body>- (Optional) Add a scss.json file to the root directory with:
{ "enableAutoprefixer": true} - Run ```git checkout step2-basic-setup`` for the finalized version of this step.
- In /lib/collections, add an items.js file with a 'items' Mongo collection:
Items = new Mongo.Collection('items');- Open your browser console (eg using Option + Cmd + J) and insert some items into your new collection:
Items.insert({title:"My first item", createdAt: Date()});(If all goes well, Mongo should return the id of the newly created item. - In /client/templates/itemsList, add a itemList.js file containing a itemsList helper, which will reactively find all items in the 'items' collection:
Template.itemsList.helpers({
allItems: function () {
return Items.find();
}
});- Add the following view template files (we need to break out each individual item instance into a "singleItem" template to support editing of an item in a later step):
/client/templates/itemsList/itemsList.html:
<template name="itemsList">
<ul class="list-group">
{{#each allItems}}
{{> singleItem}}
{{/each}}
</ul>
</template>/client/templates/singleItem/singleItem.html:
<template name="singleItem">
<li class="list-group-item">
{{title}}
</li>
</template>- Invoke your "itemsList" template in the main index file to display its contents in your app:
/client/templates/index.html
...
<div class="container">
{{> itemsList}}
</div>
...- Run
git checkout step3-items-listfor the finalized version of this step.
- Add the following form:
/client/templates/addItem/addItem.html
<template name="addItem">
<li class="list-group-item">
<form class="add-item-form">
<input type="text" class="item-title form-control" placeholder="Add item...">
</form>
</li>
</template>- Insert the form into the itemsList template:
...
<ul class="list-group">
{{> addItem}}
{{#each allItems}}
...- Add an event handler for the addItems form:
Template.addItem.events({
"submit .add-item-form": function(event, template){
event.preventDefault();
var itemTitle = template.find('.add-item-form .item-title').value;
Items.insert({
title: itemTitle,
createdAt: Date()
});
$('.add-item-form')[0].reset();
}
});- You should now be able to add items using the form. The itemsList will update reactively as new items are added.
- Update the sorting of the items list to be reverse chronological, so that newest items appear on top:
/client/template/itemsList/itemsList.js
...
return Items.find({}, {sort: {createdAt: -1}});
...- Run
git checkout step4-add-itemsfor the finalized version of this step.
- We'll implement this feature as a component so that it can be re-used in multiple contexts.
- We'll need to be able to reference collections dynamically to do this. Install this package to support that:
meteor add dburles:mongo-collection-instances - Create a deleteBtn component:
/client/templates/components/deleteBtn/deleteBtn.html
<template name="deleteBtn">
<button type="button" class="btn btn-default btn-xs delete"><span class="glyphicon glyphicon-trash" aria-hidden="true"></span></button>
</template>- Add an event handler for deleteBtn:
/client/templates/components/deleteBtn/deleteBtn.js
Template.deleteBtn.events({
'click .delete': function () {
var collection = this.collection;
var id = this.currentItem._id;
var confirmDelete = confirm("Really delete this?");
if (confirmDelete) {
Mongo.Collection.get(collection).remove({ _id: id });
};
}
});- Invoke the deleteBtn component in the singleItem template and pass in the necessary instance arguments:
/client/templates/singleItem/singleItem.html
...
{{title}} <span class="pull-right">{{> deleteBtn currentItem=this collection="items"}}</span>
...- Run
git checkout step5-delete-itemsfor the finalized version of this step.
-
This feature will be implemented by reactively toggling each item between an edit and view state.
-
JS variables are not reactive by default. Install this package to gain access to Reactive Variables:
meteor add reactive-var -
Update the singleItem template to include a form that displays conditionally:
<template name="singleItem">
{{#if editing}}
<li class="list-group-item">
<form class="update-item two-col-row">
<input type="text" class="form-control item-title main-content" placeholder="Update..." value="{{title}}">
<span class="secondary-content"><button type="button" class="btn btn-default btn-xs cancel-edit">Cancel</button></span>
</form>
</li>
{{else}}
<li class="list-group-item edit-item clickable">
{{title}} <span class="pull-right">{{> deleteBtn currentItem=this collection="items"}}</span>
</li>
{{/if}}
</template>- Set up reactive variables associated with this template.
- Add event listeners for switching to edit mode and saving changes.
- Add some css to provide ui feedback that line items are editable.
- Run
git checkout step6-edit-itemsfor the finalized version of this step.
- Run
git checkout step7-pub-subfor the finalized version of this step. - Remove the packages autopublish and insecure:
meteor remove autopublish insecure - You'll notice that items are no longer displaying. This is because you need to explicitly publish this content from the server and subscribe to it from the client.
- Add calls for publishing 'items' from the server and subscribing to them from the client.
- Move db operations out of your templates into Meteor.methods with some basic pattern validation.
- In the templates, replace direct db calls with calls to the Meteor methods.
This is such a great tutorial!