Benjamin Lim
'blym'
curl https://install.meteor.com/ | shhttps://www.meteor.com/installhttps://c9.io/install
cloud
Windows
OSX / Linux
Cloud 9
git clone https://github.com/bumbleblym/meteor-cinder.githttps://github.com/bumbleblym/meteor-cinder.gitinstall
cloud
#step-0
cd meteor-cinder
meteor create app
meteorcd workspace
meteor create app
meteor --port $IP:$PORTinstall
cloud
#step-0
http://localhost:3000/install
cloud
#step-0
<head>
<title>Meteor Cinder</title>
</head>Try editing the title:
The page updates automatically!
This is called a 'hot code push'.
app.html
app.html
#step-0
<body>
<h1>Welcome to Meteor!</h1>
{{> hello}}
</body>
<template name="hello">
<button>Click Me</button>
<p>You've pressed the button {{counter}} times.</p>
</template>{{> hello}} and {{counter}} are Spacebars expressions that tell Meteor what to insert.
app.html
#step-0
{{> hello}}
'Include a template named "hello" here'
<template name="hello">
<button>Click Me</button>
<p>You've pressed the button {{counter}} times.</p>
</template>Meteor parses code within <template> tags and creates named template objects.
<body>
<h1>Hello, Meteor!</h1>
{{> hello}}
{{> hello}}
</body>app.html
app.html
Try adding another {{> hello}} template inclusion tag:
#step-0
{{> hello}}
Try moving the template section to a new file:
<template name="hello">
<button>Click Me</button>
<p>You've pressed the button {{counter}} times.</p>
</template>hello.html
To be organized:
#step-0
{{counter}}
'Look up the property or template helper named "counter"'
Template.hello.helpers({
counter: function () {
return Session.get('counter');
}
});app.js
#step-0
helpers
Template.hello.helpers({
counter: function () {
return Session.get('counter');
}
});app.js
Template.hello.events({
'click button': function () {
// increment the counter when button is clicked
Session.set('counter', Session.get('counter') + 1);
}
});app.js
events
Event map object that specifies how events should be handled
#step-0
Session.setDefault('counter', 0);
Session.get('counter');
Session.set('counter', Session.get('counter') + 1);app.js
#step-0
if (Meteor.isClient) {
...
if (Meteor.isServer) {app.js
In short:
#step-0
How do I stop the application?
How do I go to step #?
I want to save my changes:
CTRL + CI don't want to save my changes:
git stash -u
git checkout -t origin/step-#git add .
git commit -m "Description of my changes"
git checkout -t origin/step-##step-1
How do I add Bootstrap?
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/...">meteor add twbs:bootstrapAtmosphere is a catalog where you can find more Meteor packages.
What other packages are there?
How do we display different pages?
#step-1
...
meteor-platform
autopublish
insecure
twbs:bootstrap...
meteor-platform
autopublish
insecure
twbs:bootstrap
iron:router.meteor/packages
.meteor/packages
Add the Iron Router package:
Specify the default layout template:
Router.configure({
layoutTemplate: 'layout'
});lib/router.js
#step-1
We'll use the Dashboard component:
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="">
<meta name="author" content="">
<title>Cinder</title>
</head>Add the head tag (not a template!):
Copy dashboard.css to client/templates/common/dashboard.css
client/templates/common/head/head.html
#step-1
<template name="layout">
<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container-fluid">
<div class="navbar-header">
...
</template>Create the layout template:
Don't forget the <template> tags!
client/templates/common/layout/layout.html
#step-1
<template name="layout">
{{> navbar}}
<div class="container-fluid">
<div class="row">
<div class="col-sm-3 col-md-2 sidebar">
...Extract the navbar template:
client/templates/common/layout/layout.html
<template name="navbar">
<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container-fluid">
<div class="navbar-header">
...
</template>client/templates/common/navbar/navbar.html
#step-1
<template name="layout">
{{> navbar}}
<div class="container-fluid">
<div class="row">
{{> sidebar}}
...Do the same for the sidebar:
client/templates/common/layout/layout.html
<template name="sidebar">
<div class="col-sm-3 col-md-2 sidebar">
<ul class="nav nav-sidebar">
...
</template>client/templates/common/sidebar/sidebar.html
#step-2
<template name="layout">
{{> navbar}}
<div class="container-fluid">
<div class="row">
{{> sidebar}}
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
{{> yield}}
</div>
</div>
</div>
</template>Add a {{> yield}} helper:
client/templates/common/layout/layout.html
{{> yield}} is a placeholder for content to be inserted, depending on the route.
#step-2
...
Router.route('/', {
name: 'home'
});Create a route:
lib/router.js
'For the path "/", create a route named "home" and yield the template named "home".'
For more options, refer to the guide.
#step-2
<template name="home">
<div class="page-header">
<h1>Cinder <small>Any gripe can change your life.</small></h1>
</div>
</template>Create the home template:
client/templates/views/home/home.html
templates directory structure
#step-3
Time to add more packages!
meteor add accounts-password
meteor add useraccounts:bootstrapUser Accounts is a package that provides commonly used accounts related templates e.g. sign in button
Let's update our navbar:
#step-3
...
<a class="navbar-brand" href="{{pathFor route='home'}}">Cinder</a>
</div>
<div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav navbar-right">
<li>{{> atNavButton}}</li>
</ul>
</div>
...client/templates/common/navbar/navbar.html
Add some padding:
#navbar > ul > li:last-child {
padding-right: 15px;
}client/templates/common/navbar/navbar.css
Update navbar:
#step-3
AccountsTemplates.configureRoute('signIn');
AccountsTemplates.configureRoute('signUp');lib/useraccounts.js
Configure routes:
More routes for resetting/changing passwords can be found here
#step-3
Add username field:
...
var pwd = AccountsTemplates.removeField('password');
AccountsTemplates.removeField('email');
AccountsTemplates.addFields([{
_id: "username",
type: "text",
displayName: "username",
required: true,
minLength: 5,
},
pwd
]);lib/useraccounts.js
#step-3
Add username to navbar:
...
<ul class="nav navbar-nav navbar-right">
{{#if loggingIn}}
<li><p class="navbar-text">Signing in...</p></li>
{{else}}
{{#if currentUser}}
<li><p class="navbar-text">{{currentUser.username}}</p></li>
{{/if}}
{{/if}}
<li>{{> atNavButton}}</li>
</ul>
...client/templates/common/navbar/navbar.html
{{#if}} and {{else}} are block tags. There's also {{#unless}}. {{#each}} and {{#with}} are used to set data context; we'll see them soon.
#step-3
Additional styling:
#navbar > ul > li:last-child {
padding-left: 15px;
padding-right: 15px;
}client/templates/common/navbar/navbar.css
#step-4
meteor add anti:fakeUse Fake to generate text for prototyping:
Template.sidebar.helpers({
channels: function() {
var channels = [];
_(10).times(function() {
channels.push({
name: Fake.word().toLowerCase()
});
});
return channels;
}
});client/templates/common/sidebar/sidebar.js
Create a helper to generate 'channels':
Underscore.js is also a great way to learn JavaScript.
#step-4
Use our channels helper:
<template name="sidebar">
<div class="col-sm-3 col-md-2 sidebar">
<ul class="nav nav-sidebar">
{{#each channels}}
<li><a href="#"># {{name}}</a></li>
{{/each}}
</ul>
</div>
</template>client/templates/common/sidebar/sidebar.html
...
channels.push({
name: Fake.word().toLowerCase()
});
...client/templates/common/sidebar/sidebar.js
#step-4
Add channel route:
...
Router.route('/channel/:name', {
name: 'channel'
});lib/router.js
'../channel/cinder/messages/YC6haHD6g5pZE2JGA?q1=s1&q2=s2#hash'
Router.route('/channel/:name/messages/:messageId', function () {
var channel = this.params.name; // 'cinder'
var messageId = this.params.messageId; // 'YC6haHD6g5pZE2JGA'
var query = this.params.query; // { q1: s1, q2: s2 }
var hash = this.params.hash; // 'hash'
});#step-4
Accessing route parameters:
Within the RouteController:
Outside:
#step-4
Add channel links:
<template name="sidebar">
<div class="col-sm-3 col-md-2 sidebar">
<ul class="nav nav-sidebar">
{{#each channels}}
<li><a href="{{pathFor route='channel'}}"># {{name}}</a></li>
{{/each}}
</ul>
</div>
</template>client/templates/common/sidebar/sidebar.html
#step-4
Create channel template:
Add channelName helper:
Template.channel.helpers({
channelName: function() {
return this.params.name;
}
});<template name="channel">
<div class="page-header">
<h1>{{channelName}}</h1>
</div>
</template>client/templates/views/channel/channel.html
client/templates/views/channel/channel.js
Template.channel.helpers({
channelName: function() {
return Router.current().params.name;
}
});client/templates/views/channel/channel.js
#step-5
We need to store persistent data
Channels = new Mongo.Collection('channels');Create a new Mongo Collection in lib/collections/channels.js:
Check out the different methods here
#step-5
<template name="channelForm">
<form>
<div class="input-group">
<input type="text" class="form-control" placeholder="channel name"
name="channelName">
<span class="input-group-btn">
<button class="btn btn-default" type="submit">+</button>
</span>
</div>
</form>
</template>Create channel template:
client/templates/common/sidebar/channelForm/channelForm.html
Include the template in the sidebar:
<template name="sidebar">
<div class="col-sm-3 col-md-2 sidebar">
<ul class="nav nav-sidebar">
{{#each channels}}
<li><a href="{{pathFor route='channel'}}"># {{name}}</a></li>
{{/each}}
</ul>
{{> channelForm}}
</div>
</template>client/templates/common/sidebar/sidebar.html
#step-5
Template.channelForm.events({
'submit form': function(event, instance) {
event.preventDefault();
var input = event.target.channelName;
var name = input.value.trim().split(' ')[0];
input.value = '';
if (name !== '') {
var channel = Channels.findOne({
name: name
});
if (typeof channel === 'undefined') {
Channels.insert({
name: name
});
}
}
}
});Insert channel on submit:
client/templates/common/sidebar/channelForm/channelForm.js
#step-5
Template.sidebar.helpers({
channels: function() {
return Channels.find();
}
});Change helper to return channels:
client/templates/common/sidebar/sidebar.js
Template.channel.helpers({
channel: function() {
return Channels.findOne({
name: Router.current().params.name
});
}
});Change helper to return channel:
client/templates/common/channel/channel.js
<template name="channel">
<div class="page-header">
<h1>{{channel.name}}</h1>
</div>
</template>client/templates/common/channel/channel.html
#step-5
How do I erase the local database?
meteor --help
meteor resetmeteor add msavin:mongolAdd the Mongol package!!!
Jetsetter is another package for inspecting Session variables. These packages are 'debug only'; they are not bundled for production.
#step-6
Messages = new Mongo.Collection('messages');Create a new collection in lib/collections/messages.js:
Add message templates:
<template name="channel">
<div class="page-header">
<h1>{{channel.name}}</h1>
</div>
{{> messages}}
{{> messageForm}}
</template>client/templates/views/channel/channel.html
#step-6
<template name="messages">
<ul class="list-unstyled">
{{#each messages}}
<li>{{> message}}</li>
{{/each}}
</ul>
</template>client/templates/views/channel/messages/messages.html
<template name="messageForm">
<form>
<div class="input-group">
<input type="text" class="form-control" placeholder="message">
<span class="input-group-btn">
<button class="btn btn-default" type="submit">+</button>
</span>
</div>
</form>
</template>client/templates/views/channel/messageForm/messageForm.html
<template name="message">
</template>client/templates/views/channel/messages/message/message.html
#step-6
Insert message on submit:
Template.messageForm.events({
'submit form': function(event, instance) {
event.preventDefault();
var input = event.target.content;
var content = input.value.trim();
input.value = '';
if (content !== '') {
Messages.insert({
userId: Meteor.userId(),
channel: Router.current().params.name,
content: content,
createdAt: new Date()
});
}
}
});client/templates/views/channel/messageForm/messageForm.html
#step-6
Add helper for messages:
Template.messages.helpers({
messages: function() {
return Messages.find({
channel: Router.current().params.name
});
}
});client/templates/views/channel/messages/messages.js
Add message fields:
<template name="message">
<div class="message">
<span class="username">
{{username}}
</span>
<span class="created-at">
{{createdAt}}
</span>
<p class="content">{{content}}</p>
</div>
</template>client/templates/views/channel/messages/message/message.html
#step-6
Add helper for username:
Template.message.helpers({
username: function() {
return Meteor.users.findOne(this.userId, {
username: true
}).username;
}
});client/templates/views/channel/messages/message/message.js
Bold username:
div.message > span.username {
font-weight: bold;
}client/templates/views/channel/messages/message/message.css
#step-6
Use Moment.js to format date:
<template name="message">
<div class="message">
<span class="username">
{{username}}
</span>
<span class="datetime">
{{datetime}}
</span>
<p class="content">{{content}}</p>
</div>
</template>client/templates/views/channel/messages/message/message.html
meteor add momentjs:moment...
datetime: function() {
return moment(this.createdAt).format('MMMM Do, h:mm A');
}client/templates/views/channel/messages/message/message.js
Site will be hosted at http://myappname.meteor.com/
meteor deploy myappname// Server
Meteor.publish('channels', function() {
return Channels.find({
userIds: {
$in: [this.userId]
}
});
});
// Client
Meteor.subscribe('channels');Meteor
MongoDB
JavaScript
Miscellaneous
#NOC #OnePiece #playstation
#life