7. TOOL
• 어떤 걸로 코드를 만드실 건
가요?
• ATOM (무료 추천!)
• Sublime text (인기!)
• Webstorm (유료 최고!)
8. JAVASCRIPT 구조
CLIENT
if (Meteor.isClient) {
}
SERVER
if (Meteor.isServer) {
Meteor.startup(function() {
// code to run on server at startup
});
}
사용자
브라우저에서
실행합니다.
서버에서
실행합니다.
40. CONNECT DB
• lib/collection.js 에 추가
Posts = new Mongo.Collection('posts');
• client/server 양쪽에 적용
• 기존 posts.js 수정
Template.posts.helpers({
"posts": function() {
return Posts.find();
}
});
41. CONNECT DB
• Browser Console에서 테스트
• Posts.insert({
author: {
name: "Master",
profile_image: "http://lorempixel.com/64/64/cats/"
},
message: "집사야 내 밥은 어딨냐?"
});
• Posts.find().fetch();
• 화면과 결과값을 확인
68. PUBLISH WITH PAGEID
• 조건을 주고 필요한 것들만 가져옵니다.
(http://docs.meteor.com/#/full/selectors)
• server/publish.js 수정
Meteor.publish('getPage', function(pageId) {
return Posts.find({pageId: pageId});
});
69. SUBSCRIBE WITH PAGEID
• client/main.js 수정
Template.main.helpers({
'page': function() {
return Session.get('pageId') || 'popular';
}
});
• client/posts.js 수정
Template.posts.onCreated(function() {
this.subscribe('getPage', Session.get('pageId'));
});
pageId가 없으면
popular를 기본으로
pageId로 가입
75. WARNING!
• Flow-router는 third-party package입니다.
작성자가 꼭 업데이트를 보증하지 않습니다.
• 어떤 Router를 사용할지는 선택할 수 있습니다.
• Single Page Application에서 Routing(URL 경로)가
꼭 필수이진 않습니다.
78. ACCOUNTS PACKAGE
• meteor add accounts-password
• http://docs.meteor.com/#/full/accounts_api
• Meteor.user() - 현재 접속중인 사용자
• Meteor.userId() - 접속 중인 사용자 ID
• Meteor.loginWithPassword(user, password, [callback])
로그인하기, 성공 시 callback function 실행
• Meteor.logout() - 로그아웃
• Accounts.createUser(option, [callback]) - 사용자 생성
83. USERNAME
• 사용자명 추가
• https://github.com/ianmartorell/meteor-accounts-ui-bootstrap-3/#custom-signup-
options
• client/config.js
Accounts.ui.config({
extraSignupFields: [{
fieldName: "username",
fieldLabel: "username",
inputType: 'text'
}]
});
추가 입력 필드
84. USER IN METHOD
• server/methods.js 에 사용자 정보 적용
• 로그인 여부 검사 위해 check 사용
meteor add check
• username은 Meteor.user().username
• profile_image는 gravatar를 사용하자
meteor add jparker:gravatar
85. USER IN METHOD
• client/main.js 에 Method.call 에 사용자 정보 제거
Template.main.events({
"submit": function(event, template) {
Meteor.call('addPosts', {
pageId: Session.get('pageId'),
message: template.find("#post").value
}, function(err, result) {
if (err) {
throw(err);
} else {
template.find('#post').value = '';
}
});
event.preventDefault();
}
사용자 정보는 서버에서
추가하고 pageId와
Message만 전송
86. USER IN METHOD
• server/methods.js 에 사용자 정보 적용
Meteor.methods({
"addPosts": function(obj) {
check(this.userId, String);
Posts.insert({
author: {
_id: this.userId,
name: Meteor.user().username,
profile_image: Gravatar.imageUrl(Meteor.user().emails[0].address)+"?d=retro"
},
pageId: obj.pageId,
message: obj.message,
createdAt: new Date()
});
}
});
87. USER IN METHOD
• server/methods.js 에 사용자 정보 적용
Meteor.methods({
"addPosts": function(obj) {
check(this.userId, String);
Posts.insert({
author: {
_id: this.userId,
name: Meteor.user().username,
profile_image: Gravatar.imageUrl(Meteor.user().emails[0].address, {d: "retro"})
},
pageId: obj.pageId,
message: obj.message,
createdAt: new Date()
});
}
});
로그인 여부 체크
http://docs.meteor.com/#/full/check
88. USER IN METHOD
• server/methods.js 에 사용자 정보 적용
Meteor.methods({
"addPosts": function(obj) {
check(this.userId, String);
Posts.insert({
author: {
_id: this.userId,
name: Meteor.user().username,
profile_image: Gravatar.imageUrl(Meteor.user().emails[0].address, {d: "retro"})
},
pageId: obj.pageId,
message: obj.message,
createdAt: new Date()
});
}
});
사용자 ID
89. USER IN METHOD
• server/methods.js 에 사용자 정보 적용
Meteor.methods({
"addPosts": function(obj) {
check(this.userId, String);
Posts.insert({
author: {
_id: this.userId,
name: Meteor.user().username,
profile_image: Gravatar.imageUrl(Meteor.user().emails[0].address, {d: "retro"})
},
pageId: obj.pageId,
message: obj.message,
createdAt: new Date()
});
}
});
Accounts.ui.config에서 받은
사용자 이름
90. USER IN METHOD
• server/methods.js 에 사용자 정보 적용
Meteor.methods({
"addPosts": function(obj) {
check(this.userId, String);
Posts.insert({
author: {
_id: this.userId,
name: Meteor.user().username,
profile_image: Gravatar.imageUrl(Meteor.user().emails[0].address, {d: "retro"})
},
pageId: obj.pageId,
message: obj.message,
createdAt: new Date()
});
}
});
E-Mail 주소로 사용자
Image를 가져옴
91. USER IN METHOD
• server/methods.js 에 사용자 정보 적용
Meteor.methods({
"addPosts": function(obj) {
check(this.userId, String);
Posts.insert({
author: {
_id: this.userId,
name: Meteor.user().username,
profile_image: Gravatar.imageUrl(Meteor.user().emails[0].address, {d: "retro"})
},
pageId: obj.pageId,
message: obj.message,
createdAt: new Date()
});
}
});
(선택사항) 등록된 이미지가 없을 때
retro 아이콘을 임의로 생성
https://en.gravatar.com/site/implement/images/
100. REACTIVETIME
• meteor add random 패키지 추가
• posts.js
Template.posts.onCreated(function() {
…
this.interval = Meteor.setInterval(function() {
Session.set('live', Random.id());
}, 1000);
});
• Session.set('live', ....) 하는 순간
Session.get('live')가 helper 이나 autorun 같은 곳 안쪽에 있으면 전부 재실행한다.
http://docs.meteor.com/#/full/reactivity
1초마다 live라는 키로 고유값을 생성
107. FOLLOW/UNFOLLOW
• main.js helper 구현
사용자가 해당 토픽에 follow하고 있는지 검사
client에서 기본 접근 가능한 profile 객체를 사용
'isFollowing': function() {
var followings = Meteor.user().profile.followings;
return followings &&
followings[Session.get('pageId')];
}
111. DASHBOARD
• 홈 디렉토리 이동 시 Dashboard로
• head.html
<a class="navbar-brand" href="/">Sogon2x</a>
• / 일때 pageId를 리셋
• client/router.js
FlowRouter.route('/', {
action: function() {
Session.set('pageId');
}
});
112. DASHBOARD
• main.html 수정
• 페이지가 있으면 현재
페이지 (/page:pageId)
없으면 Dashboard로
분기
• {{> post}} helper에
pageId 인자 추가
• <template name="main">
<div class="container">
{{#if page}}
<h2>{{page}}'s Page
……
{{> posts
pageId=page}}
{{else}}
{{> dashboard}}
{{/if}}
113. DASHBOARD
• main.js 수정
• {{> post}} helper에 pageId 인자
전달
• Template.main.helpers({
'page': function() {
return Session.get('pageId');
},
• default 제거
• main.html / main.js 수정
• 페이지가 있으면 현재 페이지 (/page:pageId)
없으면 Dashboard로 분기
• <template name="main">
<div class="container">
{{#if page}}
<div>
<h2>{{page}}'s Page
……
{{> posts pageId=page}}
{{else}}
{{> dashboard}}
{{/if}}
114. DASHBOARD
• Template helper에서 받은 인자를 js에 적용
Session 에서 this.data.pageId로 변경
• posts.js 수정
Template.posts.onCreated(function() {
var pageId = this.data.pageId;
pageId && this.subscribe('getPage', pageId);
…
Template.posts.helpers({
"posts": function () {
return Posts.find({
pageId: Template.instance().data.pageId
}, {
…
this.data 로부터 상위
템플릿의 인자를 받는다.
Template.instance는
this.data와 같다.
Scope 이유로 다르게 씀.
116. DASHBOARD
• 운좋은 예감 - 무작위 Posts 추출
전체 데이터 갯수-count()이용-를 기준으로 랜덤만큼 skip하고 limit
을 이용해 1개만 값을 find한다.
• Meteor.publish('feelingLucky', function() {
return Posts.find({}, {
skip: Math.random()*Posts.find().count(),
limit: 1
});
});
117. DASHBOARD
• dashboard 생성 시 feelingLucky 를 구독(subscribe)
한다.
• client/dashboard.js 생성 후
Template.dashboard.onCreated(function() {
this.subscribe('feelingLucky');
});
118. DASHBOARD
• helper 정보 - luckyPage / pages
• dashboard.js
Template.dashboard.helpers({
'luckyPage': function() {
var post = Posts.findOne()
return post && post.pageId;
},
'pages': function() {
var result = [];
for (var i in Meteor.user().profile.followings) {
result.push({ pageId: i });
}
return result;
}
});
posts가 없을 때 오류 방지
119. DASHBOARD
• helper 정보 - luckyPage / pages
• dashboard.js
Template.dashboard.helpers({
'luckyPage': function() {
var post = Posts.findOne()
return post && post.pageId;
},
'pages': function() {
var result = [];
for (var i in Meteor.user().profile.followings) {
result.push({ pageId: i });
}
return result;
}
});
following 정보를 가져온다.
120. DASHBOARD
• helper 정보 - luckyPage / pages
• dashboard.js
Template.dashboard.helpers({
'luckyPage': function() {
var post = Posts.findOne()
return post && post.pageId;
},
'pages': function() {
var result = [];
for (var i in Meteor.user().profile.followings) {
result.push({ pageId: i });
}
return result;
}
});
pageId로 배열로 밀어넣는다.
121. DASHBOARD
• 화면 구성 - 사용자 여부에 따라 Feeling lucky와 최근 Posts를 나눠서 보여준다.
• dashboard.html
<template name="dashboard">
<div class="well">
<h2>Welcome to Sogon</h2>
<p>What do you want to talk about?</p>
<a href="/page/{{luckyPage}}" class="btn btn-primary">Feeling lucky</a>
</div>
{{#if currentUser}}
<h2>Recent Posts</h2>
{{#each pages}}
<h3><a href="/page/{{pageId}}">{{pageId}}</a></h3>
{{> posts pageId=pageId}}
{{/each}}
{{/if}}
</template>
운좋은 예감(랜덤링크)
사용자 정보가 “있으면”
following 중인 page들 목록
123. 더 좋은 서비스를 위해
• MongoDB Operator의 사용. (ex: $addToSet, $pull 등)
• OAuth를 사용한 외부 서비스(페이스북/네이버/카카오) 로그인 연동
• 수정/삭제 기능
• 외부 공유와 검색엔진 최적화
• iOS/Android Hybrid Apps 제작
• Deploy …
124. 참고 사이트
• https://github.com/MeteorKorea/meteor2015codelab
본 문서의 소스 코드 github 저장소
• http://meteorjs.rk
Meteor Korea
• http://www.meetup.com/Meteor-Seoul
Meteor Seoul Meetup 모임
• http://kr.discovermeteor.com/
Discover Meteor 한글
• https://www.facebook.com/groups/meteorschool/
Facebook Meteor School