SlideShare una empresa de Scribd logo
1 de 67
Descargar para leer sin conexión
Parse Basic
Building Web Apps WITHOUT Programming Server.
http://goo.gl/8IqkAa
2014 Spring Web Programming, NCCU
Author: pa4373 (Licensed by CC-By 4.0)
So far,你的網頁都是一成不變的
http://www.pmichaud.com/toast/ (從1994年後都沒變過)
但實際上,很多網站是隨時在改變的
為什麼網站可以不斷的、及時變化?
因為有後端啊。
*Web伺服器:接收http請求、產生或委派http回應並傳回client
端
*應用程式伺服器:根據使用者的請求產生相對的回應
資料庫:像一張巨大的Excel表,存各地來的資料
Backend Technology Stack
What if?
如果有一個工具可以讓我不用寫後端程式碼,但
還是可以使用後端的功能,該有多好啊......
Parse來拯救咧!
Parse是什麼
Parse是一個BaaS(Backend as Service)。
只要會用Parse提供的SDK, 還有正確的設定。開發者毋需擔
心後端的開發撰寫以及主機的擴張和維護。
這讓開發者免於開發者實現的繁瑣細節,而將高度提升到更
接近心智建模(Mental Modeling)的層級。
Parse開發模式概覽
Your Code
Parse SDK (黑箱)
Parse Cloud
知道Parse SDK怎麼用就可以寫互動式網站
了(SDK還跨平台喔!)
很好很強大!
● localStorage:
○ jsbin.com/rubej/1/watch?html,js,output
● Parse:
○ jsbin.com/fezuq/5/watch?html,js,output
Ex: localStorage vs. Parse
● Data Store
○ Database + File
● User Management
● Background Jobs
● ……
○ (see also: https://parse.com/products)
What Parse can do?
Website vs. Web Application
Website vs. Web Application
● Information Oriented vs. Action Oriented
● Creation vs. Consumption
● Way of designing
● Anything else?
● http://www.visionmobile.com/blog/2013/07/web-sites-vs-
web-apps-what-the-experts-think/
Class vs. Object
(雖然JavaScript不是Class-based object-
oriented programming language.)
Class -> 食譜
Object (instacne) -> 菜
Class -> 藍圖
Object (instacne) -> 建築物
Model-View-Controller
SOURCE: http://online.stanford.edu/course/developing-ios7-apps-fall-2013
範例:Parse Store
● 模仿 ‘GetMore 二次時尚’ (其實根本抄襲)
● 二手洋裝專賣網站
● 能瀏覽商品、放入購物車
● 每個使用者有自己專屬的購物車(登入才能使
用)
● 沒有結賬功能
● http://pa4373.github.io/parsestore_js/
Parse Store
商品 (Dress)
購物清單 (Order)
使用者 (User)
Parse Store (Model)
Parse Store (View)
選單
產品型錄
Parse Store (View)
選單
產品細項
Parse Store (View)
選單
登入 & 註冊
● 版型引擎 (Template Engine)
○ 解決navbar困境
○ Template Tag -> 編譯-> 能產生HTML的JS函數
○ 以doT.js為例
● 路由器 (Router)
○ Facebook Photo
○ 網址和處理函數的對應
■ ex: ‘#mycart/’ -> 處理函數1
■ ‘#login/’ -> 處理函數2
○ Hash (#) vs HTML5 pushState
○ Provided by Backbone.js (Parse SDK是Backbone.js的變種)
● EventListener
○ 監聽特定事件的發生,觸發行為
○ DOM.addEventListener(事件行為, 處理函數);
○ 重複綁定?
■ https://developer.mozilla.org/en-US/docs/Web/API/EventTarget.addEventListener
Parse Store (Controller)
Use Parse SDK
Use Parse SDK
Use Parse SDK
記下Application Key以及JavaScript Key
Use Parse SDK
<!doctype html>
<head>
<meta charset="utf-8">
<title>My Parse App</title>
<meta name="description" content="My Parse App">
<meta name="viewport" content="width=device-width">
<link rel="stylesheet" href="css/reset.css">
<link rel="stylesheet" href="css/styles.css">
</head>
<body>
…….
</body>
<!--匯入Parse SDK-->
<script type="text/javascript" src="http://www.parsecdn.com/js/parse-1.2.18.min.js"
></script>
<script type="text/javascript">
// 初始化SDK (把你剛剛抄下來的Application ID和 JavaScript Key放上去)
Parse.initialize("APPLICATION_ID", "JAVASCRIPT_KEY");
</script>
</html>
Parse App Dashboard
Analytics: App使用狀況分析
Data Browser: 瀏覽儲存App的資料庫
Cloud Code: Server Code (進階)
Push Notifications: iOS、Android推播通知
Settings: App設定
下載Startup Project
https://github.
com/pa4373/parsestore_js/archive/startkit.zip
index.html
css/style.css
js/app.js
Dig into HTML.
<!doctype html>
…….
</body>
<!--網站各個組件的版型,包在script裏面讓template engine調用(稍後回提到)-->
<script id="loginTemplate" type="text/x-dot-template">
<div class='grid_6 prefix_3 suffix_3'>
……
</div>
</script>
<!--jQuery, required by Prase SDK-->
<script src="http://code.jquery.com/jquery-1.11.0.min.js"></script>
<!--Prase SDK-->
<script src='https://www.parsecdn.com/js/parse-1.2.18.min.js'></script>
<!--doT.js, the template engine-->
<script src='./js/vendors/doT.min.js'></script>
<script src='./js/app.js'></script>
</html>
Dig into JavaScript. (app.js)
// 防止潛在和其他套件的衝突
(function(){
初始化Parse SDK();
將版型編譯(compile)並載入記憶體中();
各個View相對應的處理函數();
設定Router以及相對應的處理函數();
初始化整個App();
})();
Template Engine (doT.js)
● 解決navbar困境
● 編譯
○ var tempFn = doT.template("<h1>Here is a sample template {{=it.foo}}
</h1>");
○ tempFn = function(it) { var out='<h1>Here is a sample template '+(it.foo)
+'</h1>';return out; }
○ 調用doT.template是有翻譯成本的,把編譯好的存起來以供以後使用。
● 編譯在HTML裡的版型(Little DOM Magic)
○ var tpl = document.getElementById("loginTemplate").text;
○ dot.template(tpl);
● 調用:var out = tempFN({foo: 'Sherlock'}); // <h1>Here is a sample template
Sherlock</h1>
○ 把它put回HTML裡面 (Little DOM Magic)
○ document.getElementById("content").innerHTML = out;
● 語法請參考:http://olado.github.io/doT/tutorial.html#intro
Router
● linkable, bookmarkable, shareable URLs for important locations in the app
● Hash vs. pushState (Why use Hash in the example?)
var App = Parse.Router.extend({
routes: {
'': 'index',
'page/:page/': 'catalog',
'dress/:dress_id/': 'dress_detail',
'mycart/': 'mycart',
'login/*redirect': 'login',
},
// If frontpage is requested, show the first page of catalog.
index: function(){
return handlers.catalog(1);
},
catalog: handlers.catalog,
dress_detail: handlers.dress_detail,
mycart: handlers.mycart,
login: handlers.login,
});
路徑規則和相對應的處理函數
(從物件的其他方法找 查)
處理函數名稱以及函數本體
(匿名宣告 or 參照)
:page -> 參數
function catalog
(page)
(*redirect也是另外一
種參數)
Ref: http://backbonejs.org/#Router
Router
● 當訪問#page/1/發生了什麼事呢?
var App = Parse.Router.extend({
routes: {
'': 'index',
'page/:page/': 'catalog',
'dress/:dress_id/': 'dress_detail',
'mycart/': 'mycart',
'login/*redirect': 'login',
},
// If frontpage is requested, show the first page of catalog.
index: function(){
return handlers.catalog(1);
},
catalog: handlers.catalog,
dress_detail: handlers.dress_detail,
mycart: handlers.mycart,
login: handlers.login,
});
路徑匹配
呼叫handlers.catalog(1)函數。
(1 = :page)
Ref: https://developer.mozilla.org/en-US/docs/Web/API/Window.onhashchange
Router
● 讓Router活起來。
// this = window
this.Router = new App();
Parse.history.start();
Handler Function
var handlers = {
A: function(){},
B: function(){},
C: function(){},
};
vs.
var handlerA = function(){};
var handlerB = function(){};
var handlerC = function(){};
Handler Function
與Router相關:
index: function(){
return handlers.catalog(1);
}, -> 視同瀏覽產品型錄第一頁
catalog: handlers.catalog, -> 顯示產品型錄
dress_detail: handlers.dress_detail, -> 顯示商品細項
mycart: handlers.mycart, -> 顯示購物車
login: handlers.login, -> 顯示
與Router無關:
navbar -> 根據使用者登入與否顯示navbar內容
Handler Function (Login / Signup)
if (登入了){
重新導向到首頁();
} else {
印出登入+註冊版型();
綁定登入按鈕觸發事件(); // Parse User Object
綁定兩次密碼一致與否檢查事件();
綁定註冊按鈕觸發事件(); // Parse User Object
}
Handler Function (Login / Signup)
// 綁定登入按鈕觸發事件();
document.getElementById('loginForm').addEventListener('submit', function(){
Parse.User.logIn(document.getElementById('loginForm_username').value,
document.getElementById('loginForm_password').value, {
success: function(user) {
// Do stuff after successful login
postAction();
}, error: function(user, error) {
// The login failed. Check error to see why.
}
});
});
/* Parse.User : Parse SDK提供的User物件,讓開發者可以簡便的建立會員機制
* Parse.User.logIn(帳號, 密碼,
* {success: 登入成功的回調函數, error: 登入失敗的回調函數});
* 登入成功後,會在瀏覽器裡面留下session cookie, 可以透過Parse SDK調用的函數。
*/
Handler Function (Login / Signup)
// 還記得這段語法嗎?
var currentUser = Parse.User.current();
if (currentUser) {
...
}else{
...
}
/* 如果使用者有登入的話,Parse.User.current()會回傳現今登入的
* 使用者物件,透過檢查物件物件的存在,我們能夠設計需要登入的函數。
*/
Handler Function (Login / Signup)
// 綁定兩次密碼一致與否檢查事件();
document.getElementById('singupForm_password1').
addEventListener('keyup', function(){
// 動態抓密碼欄的值 (Why?)
var singupForm_password = document.getElementById('singupForm_password');
var message = (this.value !== singupForm_password.value) ? '密碼不一致,請再
確認一次。' : '';
document.getElementById('signupForm_message').innerHTML = message;
});
Handler Function (Login / Signup)
// 綁定註冊按鈕觸發事件();
document.getElementById('singupForm').addEventListener('submit', function(){
var user = new Parse.User();
user.set("username", document.getElementById('singupForm_username').value);
user.set("password", document.getElementById('singupForm_password').value);
user.set("email", document.getElementById('singupForm_emailAddress').value);
user.signUp(null, {
success: function(user) {
postAction();
// Hooray! Let them use the app now.
},
error: function(user, error) {
// Show the error message somewhere and let the user try again.
document.getElementById('signupForm_message').innerHTML =
error.message + '['+error.code+']';
}
});
}, false);
Handler Function (Login / Signup)
// 綁定註冊按鈕觸發事件();
// 在本地創建一個User物件
var user = new Parse.User();
// 設定帳號密碼電子郵件
user.set("username", 帳號);
user.set("password", 密碼);
user.set("email", 電子郵件地址);
/* 註冊一個新的使用者並直接登入(不用做兩次!)
* 第一個null是啥?
* Extra fields to set on the new user, or null.
*/
user.signUp(null, {success: 登入成功的回調函數, error: 登入失敗的回調函數});
Handler Function (Catalog)
移動到文件最上方 // 按next時會怎麼樣?
設定分頁參數(); // pagination = skip + limit;
設定查詢參數(); // Parse Query
查詢Parse伺服器資料庫(); // 取回物件列表
印出產品型錄版型();
設定查詢參數(); // 解除所有限制
印出分頁版型(); // Parse Dress Object (為什麼晚查?)
// 因為分頁版型要加附的DOM在型錄版型內
Handler Function (Catalog)
var handler = function(page){
// page意指現今頁數
window.scrollTo(0,0); // 移動到文件最上方
var limit = 16; // 每頁顯示多少筆資料
var skip = (page-1) * limit; // 要略過多少筆之前的資料
var Dress = Parse.Object.extend("Dress"); // 取得Parse的Dress class
var query = new Parse.Query(Dress); // 創建一個找查Dress的Query物件
query.limit(limit); // 設定Query條件
query.skip(skip);
query.descending("createdAt"); // 按照創造時間降冪排序
// 執行query (網路連結直到此處才會觸發)
query.find({success: function(results){
// 處理回傳的結果,results變數指向回傳的物件列表
...
}});
}
Handler Function (Catalog)
{success: function(results){
var objList = results.map(function(e){ return e.toJSON() }); // 將物件列表轉化成版型能消化的格式
document.getElementById('content').innerHTML =
templates.catalogTemplate(objList); // 呼叫型錄的模板函數。
query.limit(0);
query.skip(0); // 設成0, 我們才能找到所有Dress object總數
var option = {};
query.count({success: function(count){
var totalPage = Math.ceil(count / limit); // Math.celi(3.1415926) = 4;
var currentPage = parseInt(page); // 轉型( string => int )
option = {
// Watch out the limit.
'previous': (currentPage === 1) ? 1 : currentPage-1,
'next': (currentPage === totalPage) ? currentPage : currentPage+1, // 不可以超過最前最後頁
'current': currentPage,
'last': totalPage,
};
document.getElementById('pagination').innerHTML =
templates.catalogPaginationTemplate(option); // 呼叫分頁的模板函數。
}, error: function(err){}
});
}
Handler Function (Dress Detail)
if(有洋裝Id參數){
設定查詢參數(); // Parse Query
查詢Parse伺服器資料庫(); // 取回物件內容
印出產品細則版型();
綁定加入購物車功能(); // Parse Relational Object
} else {
重新導向到首頁();
}
Handler Function (Dress Detail)
var handler = function(dress_id){
if(dress_id){
var Dress = Parse.Object.extend("Dress"); // 取得Parse的Dress class
var query = new Parse.Query(Dress); // 創建一個找查Dress的Query物件
query.get(dress_id, { // 執行query,注意get方法 -> 給定物件ID, 回傳物件
success: function(dress){
document.getElementById('content').innerHTML =
templates.dress_detialTemplate(dress.toJSON());
綁定加入購物車功能 (); // 下一張slide會解釋
}, error: function(object, error){
}
});
} else {
window.location.hash = '';
}
}
Parse Relational Object
var John = {
‘height’: 180,
‘girlfriend’: Jenny
}
What is the relationship between John and Jenny?
How tall is John’s girlfriend? John.girlfriend.height = 167
Why? Data Consistency.
var Jenny = {
‘height’: 167,
}
Parse Relational Object
var order = {
‘user’: <User obj>,
‘dress’: <Dress obj>,
‘amount’: 10,
}
Handler Function (Dress Detail)
document.getElementById('addToCart').addEventListener('click', function(){
var currentUser = Parse.User.current(); // 檢查登入
if(currentUser){
var e = document.getElementById('amount');
var amount = parseInt(e.options[e.selectedIndex].value);
myCart.setAmountTo(currentUser, dress, amount, function(){
alert("此商品已加入到您的購物車。 ");
}); // 下一張slide會解釋
} else {
// 重新導向到登入頁面,登入後會回到商品
window.location.hash = 'login/'+ window.location.hash;
}
});
myCart.setAmoutTo
myCart = {
setAmountTo: function(user, dress, amount, callback){
var Order = Parse.Object.extend("Order"); // 取得Parse的Order class
// 創建一個找查Order的Query物件
var query = new Parse.Query(Order);
// 設定Query條件(object的user欄位指向到給定的User object)
query.equalTo('user', user);
// 設定Query條件(object的dress欄位指向到給定的Dress object)
query.equalTo('dress', dress);
// 執行query,注意first方法 -> 給定物件ID, 回傳物件列表第一項(可能會沒有)
query.first({success: 查詢成功的回調函數, error: 查詢失敗的回調函數});
},
};
/*
* myCart.setAmountTo(User物件, Dress物件, 數量(int), 回調函數);
*/
myCart.setAmoutTo
{
success: function(order){
if( amount === 0 && order ){ // 如果已經有存在的order,並收到將數量設成0的話,等於消滅order物件
order.destroy({ // 消滅Parse物件
success: function(order){
callback(); //調用當作參數的callback函數
}
});
} else {
if( order === undefined ){ // 如果order還不存在,創一個新的object
order = new Order();
order.set('user', user); // 指定新object的user欄位指向到給定的Dress object
order.set('dress', dress); // 指定新object的dress欄位指向到給定的Dress object
}
order.set('amount', amount);
order.save(null, { // 將新增或更改過的order object 存到Parse Server
success: function(order){
callback();
}
});
}
}, error: function(object, err){
}
}
Handler Function (My Cart)
if (登入了){
設定查詢參數(); // Parse Query for Order
查詢Parse伺服器資料庫(); // 取回物件內容
迴圈印出各訂單並綁上修改數量和刪除的事件();
} else {
重新導向到首頁();
}
Handler Function (My Cart)
mycart: function(){
var currentUser = Parse.User.current();
if (currentUser) {
var Order = Parse.Object.extend("Order");
var query = new Parse.Query(Order);
query.equalTo('user', currentUser);
query.include('dress');
query.find({success: 登入成功的回調函數 , error: 登入失敗的回調函數 });
} else {
window.location.hash = 'login/'+ window.location.hash;
}
}
Handler Function (My Cart)
{
success: function (results) {
var objList = results.map(function (e) {
return {
'dressId': e.get('dress').id,
'amount': e.get('amount'),
'name': e.get('dress').get('name'),
'previewUrl': e.get('dress').get('previewUrl'),
}
});
document.getElementById('content').innerHTML = templates.mycartTemplate(objList);
results.forEach(function (e) {
var changeAmount = document.getElementById('change_amount_' + e.get('dress').id);
changeAmount.addEventListener('change', function () {
var amount = parseInt(this.options[this.selectedIndex].value);
myCart.setAmountTo(currentUser, e.get('dress'), amount, function () {});
});
var cancelOrderBtn = document.getElementById('cancel_order_' + e.get('dress').id);
cancelOrderBtn.addEventListener('click', function () {
myCart.setAmountTo(currentUser, e.get('dress'), 0, function () {
if (cancelOrderBtn.parentNode.parentNode.childElementCount === 1) {
handlers.mycart();
} else {
cancelOrderBtn.parentNode.remove();
}
});
});
});
document.getElementById('payButton').parentNode.addEventListener('click', function () {
alert('沒做這功能喔');
});
}, error: function (error){ },
}
Handler Function
// See the pattern?
function(){
預處理(); // ex: 檢查登入狀況
載入模型(); // optional
使用樣板引擎將模型顯示到browser上();
事件綁定(); // Event binding (eg. click)
};
註:這樣的設計只是參考不是絕對,應按照合理的情況去撰寫
相對應的程序
Privilege Issues
How to protect data?
Parse Class-Based Privilege (Data
Browser)
Ref: https://parse.com/docs/data#security-classes
Parse Class-Based Privilege (Data
Browser)
Parse ACL (more complicated!)
ACL: Access Control List
“...each object has a list of users and roles
along with what permissions that user or role
has...”
user vs. roles
Ref: https://parse.com/docs/data#security-objects
Parse ACL
{ "*":{"read":true}, "SaMpLeUsErId":{"write":
true,"read":true} }
SaMpLeUsErId 這個user可以讀寫這個物件
其他人只能讀
Parse ACL
How to make the certain ‘Order’ object
available only to the owner?
var orderACL = new Parse.ACL();
orderACL.setPublicReadAccess(false);
orderACL.setPublicWriteAccess(false);
orderACL.setReadAccess(user, true);
orderACL.setWriteAccess(user, true);
// 附加到物件實體(instance)上
order.setACL(postACL);
order.save();
Ref: http://parse.com/docs/js/symbols/Parse.ACL.html
Parse ACL
Parse Store
All Source codes are available on GitHub:
https://github.com/pa4373/parsestore_js
using git to clone!
$ git clone https://github.com/pa4373/parsestore_js.git
More Topics…...
● Parse JavaScript Tutorial
● Parse JavaScript SDK Reference
● Pricing
● Loading indicator
● Backbone.js
○ Data-Binding

Más contenido relacionado

La actualidad más candente

PHP & MySQL 教學
PHP & MySQL 教學PHP & MySQL 教學
PHP & MySQL 教學Bo-Yi Wu
 
Js的国(转载)
Js的国(转载)Js的国(转载)
Js的国(转载)Leo Hui
 
Php设计模式介绍
Php设计模式介绍Php设计模式介绍
Php设计模式介绍cyf5513
 
PHPUnit + Xdebug 单元测试技术
PHPUnit + Xdebug 单元测试技术PHPUnit + Xdebug 单元测试技术
PHPUnit + Xdebug 单元测试技术hoopchina
 
Asp.net mvc 培训
Asp.net mvc 培训Asp.net mvc 培训
Asp.net mvc 培训lotusprince
 
2009 CSBB LAB 新生訓練
2009 CSBB LAB 新生訓練2009 CSBB LAB 新生訓練
2009 CSBB LAB 新生訓練Abner Huang
 
OpenWebSchool - 02 - PHP Part I
OpenWebSchool - 02 - PHP Part IOpenWebSchool - 02 - PHP Part I
OpenWebSchool - 02 - PHP Part IHung-yu Lin
 
常見設計模式介紹
常見設計模式介紹常見設計模式介紹
常見設計模式介紹Jace Ju
 
XMLHTTPRequest的属性和方法简介
XMLHTTPRequest的属性和方法简介XMLHTTPRequest的属性和方法简介
XMLHTTPRequest的属性和方法简介wensheng wei
 
Ejb工作原理学习笔记
Ejb工作原理学习笔记Ejb工作原理学习笔记
Ejb工作原理学习笔记yiditushe
 
论 Python 与设计模式。
论 Python 与设计模式。论 Python 与设计模式。
论 Python 与设计模式。勇浩 赖
 
页游开发中的 Python 组件与模式
页游开发中的 Python 组件与模式页游开发中的 Python 组件与模式
页游开发中的 Python 组件与模式勇浩 赖
 
Python 于 webgame 的应用
Python 于 webgame 的应用Python 于 webgame 的应用
Python 于 webgame 的应用勇浩 赖
 
从问题开始,谈前端架构
从问题开始,谈前端架构从问题开始,谈前端架构
从问题开始,谈前端架构裕波 周
 
PHPUnit 入門介紹
PHPUnit 入門介紹PHPUnit 入門介紹
PHPUnit 入門介紹Jace Ju
 
iPhone,ios,Object-C基础入门
iPhone,ios,Object-C基础入门iPhone,ios,Object-C基础入门
iPhone,ios,Object-C基础入门Lucien Li
 
改善程序设计技术的50个有效做法
改善程序设计技术的50个有效做法改善程序设计技术的50个有效做法
改善程序设计技术的50个有效做法crasysatan
 
张所勇:前端开发工具推荐
张所勇:前端开发工具推荐张所勇:前端开发工具推荐
张所勇:前端开发工具推荐zhangsuoyong
 

La actualidad más candente (20)

PHP & MySQL 教學
PHP & MySQL 教學PHP & MySQL 教學
PHP & MySQL 教學
 
Js的国(转载)
Js的国(转载)Js的国(转载)
Js的国(转载)
 
Php设计模式介绍
Php设计模式介绍Php设计模式介绍
Php设计模式介绍
 
PHPUnit + Xdebug 单元测试技术
PHPUnit + Xdebug 单元测试技术PHPUnit + Xdebug 单元测试技术
PHPUnit + Xdebug 单元测试技术
 
Node way
Node wayNode way
Node way
 
Asp.net mvc 培训
Asp.net mvc 培训Asp.net mvc 培训
Asp.net mvc 培训
 
2009 CSBB LAB 新生訓練
2009 CSBB LAB 新生訓練2009 CSBB LAB 新生訓練
2009 CSBB LAB 新生訓練
 
OpenWebSchool - 02 - PHP Part I
OpenWebSchool - 02 - PHP Part IOpenWebSchool - 02 - PHP Part I
OpenWebSchool - 02 - PHP Part I
 
常見設計模式介紹
常見設計模式介紹常見設計模式介紹
常見設計模式介紹
 
XMLHTTPRequest的属性和方法简介
XMLHTTPRequest的属性和方法简介XMLHTTPRequest的属性和方法简介
XMLHTTPRequest的属性和方法简介
 
Ejb工作原理学习笔记
Ejb工作原理学习笔记Ejb工作原理学习笔记
Ejb工作原理学习笔记
 
ios分享
ios分享ios分享
ios分享
 
论 Python 与设计模式。
论 Python 与设计模式。论 Python 与设计模式。
论 Python 与设计模式。
 
页游开发中的 Python 组件与模式
页游开发中的 Python 组件与模式页游开发中的 Python 组件与模式
页游开发中的 Python 组件与模式
 
Python 于 webgame 的应用
Python 于 webgame 的应用Python 于 webgame 的应用
Python 于 webgame 的应用
 
从问题开始,谈前端架构
从问题开始,谈前端架构从问题开始,谈前端架构
从问题开始,谈前端架构
 
PHPUnit 入門介紹
PHPUnit 入門介紹PHPUnit 入門介紹
PHPUnit 入門介紹
 
iPhone,ios,Object-C基础入门
iPhone,ios,Object-C基础入门iPhone,ios,Object-C基础入门
iPhone,ios,Object-C基础入门
 
改善程序设计技术的50个有效做法
改善程序设计技术的50个有效做法改善程序设计技术的50个有效做法
改善程序设计技术的50个有效做法
 
张所勇:前端开发工具推荐
张所勇:前端开发工具推荐张所勇:前端开发工具推荐
张所勇:前端开发工具推荐
 

Destacado

Workshop: building your mobile backend with Parse - Droidcon Paris2014
Workshop: building your mobile backend with Parse - Droidcon Paris2014Workshop: building your mobile backend with Parse - Droidcon Paris2014
Workshop: building your mobile backend with Parse - Droidcon Paris2014Paris Android User Group
 
Building Android apps with Parse
Building Android apps with ParseBuilding Android apps with Parse
Building Android apps with ParseDroidConTLV
 
Introduction to Parse backend for mobile developers
Introduction to Parse backend for mobile developersIntroduction to Parse backend for mobile developers
Introduction to Parse backend for mobile developersGrigor Yeghiazaryan
 
How Parse Built a Mobile Backend as a Service on AWS (MBL307) | AWS re:Invent...
How Parse Built a Mobile Backend as a Service on AWS (MBL307) | AWS re:Invent...How Parse Built a Mobile Backend as a Service on AWS (MBL307) | AWS re:Invent...
How Parse Built a Mobile Backend as a Service on AWS (MBL307) | AWS re:Invent...Amazon Web Services
 
Tinder powerpoint Final
Tinder powerpoint FinalTinder powerpoint Final
Tinder powerpoint FinalHannah Carlson
 
The secret of Tinder
The secret of TinderThe secret of Tinder
The secret of TinderDori Adar
 
Company Presentation: Tinder
Company Presentation: TinderCompany Presentation: Tinder
Company Presentation: TinderNate Rubin
 
Comparison of Tinder, Match.com, Zoosk, Bumble and Other Dating Apps on Faceb...
Comparison of Tinder, Match.com, Zoosk, Bumble and Other Dating Apps on Faceb...Comparison of Tinder, Match.com, Zoosk, Bumble and Other Dating Apps on Faceb...
Comparison of Tinder, Match.com, Zoosk, Bumble and Other Dating Apps on Faceb...Unmetric
 

Destacado (14)

Workshop: building your mobile backend with Parse - Droidcon Paris2014
Workshop: building your mobile backend with Parse - Droidcon Paris2014Workshop: building your mobile backend with Parse - Droidcon Paris2014
Workshop: building your mobile backend with Parse - Droidcon Paris2014
 
Doc app cracker
Doc app crackerDoc app cracker
Doc app cracker
 
What's Parse
What's ParseWhat's Parse
What's Parse
 
Building Android apps with Parse
Building Android apps with ParseBuilding Android apps with Parse
Building Android apps with Parse
 
Parse
ParseParse
Parse
 
Introduction to Parse backend for mobile developers
Introduction to Parse backend for mobile developersIntroduction to Parse backend for mobile developers
Introduction to Parse backend for mobile developers
 
How Parse Built a Mobile Backend as a Service on AWS (MBL307) | AWS re:Invent...
How Parse Built a Mobile Backend as a Service on AWS (MBL307) | AWS re:Invent...How Parse Built a Mobile Backend as a Service on AWS (MBL307) | AWS re:Invent...
How Parse Built a Mobile Backend as a Service on AWS (MBL307) | AWS re:Invent...
 
Tinder
TinderTinder
Tinder
 
Tinder powerpoint Final
Tinder powerpoint FinalTinder powerpoint Final
Tinder powerpoint Final
 
Tinder, ou l'amour 2.0
Tinder, ou l'amour 2.0Tinder, ou l'amour 2.0
Tinder, ou l'amour 2.0
 
The secret of Tinder
The secret of TinderThe secret of Tinder
The secret of Tinder
 
Company Presentation: Tinder
Company Presentation: TinderCompany Presentation: Tinder
Company Presentation: Tinder
 
Tinder
TinderTinder
Tinder
 
Comparison of Tinder, Match.com, Zoosk, Bumble and Other Dating Apps on Faceb...
Comparison of Tinder, Match.com, Zoosk, Bumble and Other Dating Apps on Faceb...Comparison of Tinder, Match.com, Zoosk, Bumble and Other Dating Apps on Faceb...
Comparison of Tinder, Match.com, Zoosk, Bumble and Other Dating Apps on Faceb...
 

Similar a Introduction to Parse JavaScript SDK

Ajax Transportation Methods
Ajax Transportation MethodsAjax Transportation Methods
Ajax Transportation Methodsyiditushe
 
網站設計100步
網站設計100步網站設計100步
網站設計100步evercislide
 
Node.js开发体验
Node.js开发体验Node.js开发体验
Node.js开发体验QLeelulu
 
给聚划算后端开发的前端培训
给聚划算后端开发的前端培训给聚划算后端开发的前端培训
给聚划算后端开发的前端培训j5726
 
钟志 第八期Web标准化交流会
钟志 第八期Web标准化交流会钟志 第八期Web标准化交流会
钟志 第八期Web标准化交流会Zhi Zhong
 
第三方内容开发最佳实践
第三方内容开发最佳实践第三方内容开发最佳实践
第三方内容开发最佳实践taobao.com
 
Javascript 性能优化总结.docx
Javascript 性能优化总结.docxJavascript 性能优化总结.docx
Javascript 性能优化总结.docxbaixingfa
 
PHP Coding Standard and 50+ Programming Skills
PHP Coding Standard and 50+ Programming SkillsPHP Coding Standard and 50+ Programming Skills
PHP Coding Standard and 50+ Programming SkillsHo Kim
 
Open Api&Sip
Open Api&SipOpen Api&Sip
Open Api&Sipcenwenchu
 
Lucene 全文检索实践
Lucene 全文检索实践Lucene 全文检索实践
Lucene 全文检索实践yiditushe
 
javascript的分层概念 --- 阿当
javascript的分层概念 --- 阿当javascript的分层概念 --- 阿当
javascript的分层概念 --- 阿当裕波 周
 
Exam 98-375 HTML5 Application Development Fundamentals
Exam 98-375 HTML5 Application Development FundamentalsExam 98-375 HTML5 Application Development Fundamentals
Exam 98-375 HTML5 Application Development FundamentalsChieh Lin
 
Javascript之昨是今非
Javascript之昨是今非Javascript之昨是今非
Javascript之昨是今非Tony Deng
 
异步编程与浏览器执行模型
异步编程与浏览器执行模型异步编程与浏览器执行模型
异步编程与浏览器执行模型keelii
 
The Evolution of Async Programming (GZ TechParty C#)
The Evolution of Async Programming (GZ TechParty C#)The Evolution of Async Programming (GZ TechParty C#)
The Evolution of Async Programming (GZ TechParty C#)jeffz
 
JavaScript 脚本控件(二)
JavaScript 脚本控件(二)JavaScript 脚本控件(二)
JavaScript 脚本控件(二)RANK LIU
 
Go语言web开发
Go语言web开发Go语言web开发
Go语言web开发Andy Shi
 

Similar a Introduction to Parse JavaScript SDK (20)

Ajax Transportation Methods
Ajax Transportation MethodsAjax Transportation Methods
Ajax Transportation Methods
 
網站設計100步
網站設計100步網站設計100步
網站設計100步
 
Node.js开发体验
Node.js开发体验Node.js开发体验
Node.js开发体验
 
给聚划算后端开发的前端培训
给聚划算后端开发的前端培训给聚划算后端开发的前端培训
给聚划算后端开发的前端培训
 
钟志 第八期Web标准化交流会
钟志 第八期Web标准化交流会钟志 第八期Web标准化交流会
钟志 第八期Web标准化交流会
 
第三方内容开发最佳实践
第三方内容开发最佳实践第三方内容开发最佳实践
第三方内容开发最佳实践
 
Web base 吴志华
Web base 吴志华Web base 吴志华
Web base 吴志华
 
Php
PhpPhp
Php
 
Javascript 性能优化总结.docx
Javascript 性能优化总结.docxJavascript 性能优化总结.docx
Javascript 性能优化总结.docx
 
PHP Coding Standard and 50+ Programming Skills
PHP Coding Standard and 50+ Programming SkillsPHP Coding Standard and 50+ Programming Skills
PHP Coding Standard and 50+ Programming Skills
 
Open Api&Sip
Open Api&SipOpen Api&Sip
Open Api&Sip
 
Lucene 全文检索实践
Lucene 全文检索实践Lucene 全文检索实践
Lucene 全文检索实践
 
javascript的分层概念 --- 阿当
javascript的分层概念 --- 阿当javascript的分层概念 --- 阿当
javascript的分层概念 --- 阿当
 
Exam 98-375 HTML5 Application Development Fundamentals
Exam 98-375 HTML5 Application Development FundamentalsExam 98-375 HTML5 Application Development Fundamentals
Exam 98-375 HTML5 Application Development Fundamentals
 
Javascript之昨是今非
Javascript之昨是今非Javascript之昨是今非
Javascript之昨是今非
 
异步编程与浏览器执行模型
异步编程与浏览器执行模型异步编程与浏览器执行模型
异步编程与浏览器执行模型
 
The Evolution of Async Programming (GZ TechParty C#)
The Evolution of Async Programming (GZ TechParty C#)The Evolution of Async Programming (GZ TechParty C#)
The Evolution of Async Programming (GZ TechParty C#)
 
JavaScript 脚本控件(二)
JavaScript 脚本控件(二)JavaScript 脚本控件(二)
JavaScript 脚本控件(二)
 
四天学会Ajax
四天学会Ajax四天学会Ajax
四天学会Ajax
 
Go语言web开发
Go语言web开发Go语言web开发
Go语言web开发
 

Introduction to Parse JavaScript SDK

  • 1. Parse Basic Building Web Apps WITHOUT Programming Server. http://goo.gl/8IqkAa 2014 Spring Web Programming, NCCU Author: pa4373 (Licensed by CC-By 4.0)
  • 5.
  • 9. Parse是什麼 Parse是一個BaaS(Backend as Service)。 只要會用Parse提供的SDK, 還有正確的設定。開發者毋需擔 心後端的開發撰寫以及主機的擴張和維護。 這讓開發者免於開發者實現的繁瑣細節,而將高度提升到更 接近心智建模(Mental Modeling)的層級。
  • 12. ● localStorage: ○ jsbin.com/rubej/1/watch?html,js,output ● Parse: ○ jsbin.com/fezuq/5/watch?html,js,output Ex: localStorage vs. Parse
  • 13. ● Data Store ○ Database + File ● User Management ● Background Jobs ● …… ○ (see also: https://parse.com/products) What Parse can do?
  • 14. Website vs. Web Application
  • 15. Website vs. Web Application ● Information Oriented vs. Action Oriented ● Creation vs. Consumption ● Way of designing ● Anything else? ● http://www.visionmobile.com/blog/2013/07/web-sites-vs- web-apps-what-the-experts-think/
  • 16. Class vs. Object (雖然JavaScript不是Class-based object- oriented programming language.) Class -> 食譜 Object (instacne) -> 菜 Class -> 藍圖 Object (instacne) -> 建築物
  • 19. ● 模仿 ‘GetMore 二次時尚’ (其實根本抄襲) ● 二手洋裝專賣網站 ● 能瀏覽商品、放入購物車 ● 每個使用者有自己專屬的購物車(登入才能使 用) ● 沒有結賬功能 ● http://pa4373.github.io/parsestore_js/ Parse Store
  • 20. 商品 (Dress) 購物清單 (Order) 使用者 (User) Parse Store (Model)
  • 24. ● 版型引擎 (Template Engine) ○ 解決navbar困境 ○ Template Tag -> 編譯-> 能產生HTML的JS函數 ○ 以doT.js為例 ● 路由器 (Router) ○ Facebook Photo ○ 網址和處理函數的對應 ■ ex: ‘#mycart/’ -> 處理函數1 ■ ‘#login/’ -> 處理函數2 ○ Hash (#) vs HTML5 pushState ○ Provided by Backbone.js (Parse SDK是Backbone.js的變種) ● EventListener ○ 監聽特定事件的發生,觸發行為 ○ DOM.addEventListener(事件行為, 處理函數); ○ 重複綁定? ■ https://developer.mozilla.org/en-US/docs/Web/API/EventTarget.addEventListener Parse Store (Controller)
  • 27. Use Parse SDK 記下Application Key以及JavaScript Key
  • 28. Use Parse SDK <!doctype html> <head> <meta charset="utf-8"> <title>My Parse App</title> <meta name="description" content="My Parse App"> <meta name="viewport" content="width=device-width"> <link rel="stylesheet" href="css/reset.css"> <link rel="stylesheet" href="css/styles.css"> </head> <body> ……. </body> <!--匯入Parse SDK--> <script type="text/javascript" src="http://www.parsecdn.com/js/parse-1.2.18.min.js" ></script> <script type="text/javascript"> // 初始化SDK (把你剛剛抄下來的Application ID和 JavaScript Key放上去) Parse.initialize("APPLICATION_ID", "JAVASCRIPT_KEY"); </script> </html>
  • 29. Parse App Dashboard Analytics: App使用狀況分析 Data Browser: 瀏覽儲存App的資料庫 Cloud Code: Server Code (進階) Push Notifications: iOS、Android推播通知 Settings: App設定
  • 31. Dig into HTML. <!doctype html> ……. </body> <!--網站各個組件的版型,包在script裏面讓template engine調用(稍後回提到)--> <script id="loginTemplate" type="text/x-dot-template"> <div class='grid_6 prefix_3 suffix_3'> …… </div> </script> <!--jQuery, required by Prase SDK--> <script src="http://code.jquery.com/jquery-1.11.0.min.js"></script> <!--Prase SDK--> <script src='https://www.parsecdn.com/js/parse-1.2.18.min.js'></script> <!--doT.js, the template engine--> <script src='./js/vendors/doT.min.js'></script> <script src='./js/app.js'></script> </html>
  • 32. Dig into JavaScript. (app.js) // 防止潛在和其他套件的衝突 (function(){ 初始化Parse SDK(); 將版型編譯(compile)並載入記憶體中(); 各個View相對應的處理函數(); 設定Router以及相對應的處理函數(); 初始化整個App(); })();
  • 33. Template Engine (doT.js) ● 解決navbar困境 ● 編譯 ○ var tempFn = doT.template("<h1>Here is a sample template {{=it.foo}} </h1>"); ○ tempFn = function(it) { var out='<h1>Here is a sample template '+(it.foo) +'</h1>';return out; } ○ 調用doT.template是有翻譯成本的,把編譯好的存起來以供以後使用。 ● 編譯在HTML裡的版型(Little DOM Magic) ○ var tpl = document.getElementById("loginTemplate").text; ○ dot.template(tpl); ● 調用:var out = tempFN({foo: 'Sherlock'}); // <h1>Here is a sample template Sherlock</h1> ○ 把它put回HTML裡面 (Little DOM Magic) ○ document.getElementById("content").innerHTML = out; ● 語法請參考:http://olado.github.io/doT/tutorial.html#intro
  • 34. Router ● linkable, bookmarkable, shareable URLs for important locations in the app ● Hash vs. pushState (Why use Hash in the example?) var App = Parse.Router.extend({ routes: { '': 'index', 'page/:page/': 'catalog', 'dress/:dress_id/': 'dress_detail', 'mycart/': 'mycart', 'login/*redirect': 'login', }, // If frontpage is requested, show the first page of catalog. index: function(){ return handlers.catalog(1); }, catalog: handlers.catalog, dress_detail: handlers.dress_detail, mycart: handlers.mycart, login: handlers.login, }); 路徑規則和相對應的處理函數 (從物件的其他方法找 查) 處理函數名稱以及函數本體 (匿名宣告 or 參照) :page -> 參數 function catalog (page) (*redirect也是另外一 種參數) Ref: http://backbonejs.org/#Router
  • 35. Router ● 當訪問#page/1/發生了什麼事呢? var App = Parse.Router.extend({ routes: { '': 'index', 'page/:page/': 'catalog', 'dress/:dress_id/': 'dress_detail', 'mycart/': 'mycart', 'login/*redirect': 'login', }, // If frontpage is requested, show the first page of catalog. index: function(){ return handlers.catalog(1); }, catalog: handlers.catalog, dress_detail: handlers.dress_detail, mycart: handlers.mycart, login: handlers.login, }); 路徑匹配 呼叫handlers.catalog(1)函數。 (1 = :page) Ref: https://developer.mozilla.org/en-US/docs/Web/API/Window.onhashchange
  • 36. Router ● 讓Router活起來。 // this = window this.Router = new App(); Parse.history.start();
  • 37. Handler Function var handlers = { A: function(){}, B: function(){}, C: function(){}, }; vs. var handlerA = function(){}; var handlerB = function(){}; var handlerC = function(){};
  • 38. Handler Function 與Router相關: index: function(){ return handlers.catalog(1); }, -> 視同瀏覽產品型錄第一頁 catalog: handlers.catalog, -> 顯示產品型錄 dress_detail: handlers.dress_detail, -> 顯示商品細項 mycart: handlers.mycart, -> 顯示購物車 login: handlers.login, -> 顯示 與Router無關: navbar -> 根據使用者登入與否顯示navbar內容
  • 39. Handler Function (Login / Signup) if (登入了){ 重新導向到首頁(); } else { 印出登入+註冊版型(); 綁定登入按鈕觸發事件(); // Parse User Object 綁定兩次密碼一致與否檢查事件(); 綁定註冊按鈕觸發事件(); // Parse User Object }
  • 40. Handler Function (Login / Signup) // 綁定登入按鈕觸發事件(); document.getElementById('loginForm').addEventListener('submit', function(){ Parse.User.logIn(document.getElementById('loginForm_username').value, document.getElementById('loginForm_password').value, { success: function(user) { // Do stuff after successful login postAction(); }, error: function(user, error) { // The login failed. Check error to see why. } }); }); /* Parse.User : Parse SDK提供的User物件,讓開發者可以簡便的建立會員機制 * Parse.User.logIn(帳號, 密碼, * {success: 登入成功的回調函數, error: 登入失敗的回調函數}); * 登入成功後,會在瀏覽器裡面留下session cookie, 可以透過Parse SDK調用的函數。 */
  • 41. Handler Function (Login / Signup) // 還記得這段語法嗎? var currentUser = Parse.User.current(); if (currentUser) { ... }else{ ... } /* 如果使用者有登入的話,Parse.User.current()會回傳現今登入的 * 使用者物件,透過檢查物件物件的存在,我們能夠設計需要登入的函數。 */
  • 42. Handler Function (Login / Signup) // 綁定兩次密碼一致與否檢查事件(); document.getElementById('singupForm_password1'). addEventListener('keyup', function(){ // 動態抓密碼欄的值 (Why?) var singupForm_password = document.getElementById('singupForm_password'); var message = (this.value !== singupForm_password.value) ? '密碼不一致,請再 確認一次。' : ''; document.getElementById('signupForm_message').innerHTML = message; });
  • 43. Handler Function (Login / Signup) // 綁定註冊按鈕觸發事件(); document.getElementById('singupForm').addEventListener('submit', function(){ var user = new Parse.User(); user.set("username", document.getElementById('singupForm_username').value); user.set("password", document.getElementById('singupForm_password').value); user.set("email", document.getElementById('singupForm_emailAddress').value); user.signUp(null, { success: function(user) { postAction(); // Hooray! Let them use the app now. }, error: function(user, error) { // Show the error message somewhere and let the user try again. document.getElementById('signupForm_message').innerHTML = error.message + '['+error.code+']'; } }); }, false);
  • 44. Handler Function (Login / Signup) // 綁定註冊按鈕觸發事件(); // 在本地創建一個User物件 var user = new Parse.User(); // 設定帳號密碼電子郵件 user.set("username", 帳號); user.set("password", 密碼); user.set("email", 電子郵件地址); /* 註冊一個新的使用者並直接登入(不用做兩次!) * 第一個null是啥? * Extra fields to set on the new user, or null. */ user.signUp(null, {success: 登入成功的回調函數, error: 登入失敗的回調函數});
  • 45. Handler Function (Catalog) 移動到文件最上方 // 按next時會怎麼樣? 設定分頁參數(); // pagination = skip + limit; 設定查詢參數(); // Parse Query 查詢Parse伺服器資料庫(); // 取回物件列表 印出產品型錄版型(); 設定查詢參數(); // 解除所有限制 印出分頁版型(); // Parse Dress Object (為什麼晚查?) // 因為分頁版型要加附的DOM在型錄版型內
  • 46. Handler Function (Catalog) var handler = function(page){ // page意指現今頁數 window.scrollTo(0,0); // 移動到文件最上方 var limit = 16; // 每頁顯示多少筆資料 var skip = (page-1) * limit; // 要略過多少筆之前的資料 var Dress = Parse.Object.extend("Dress"); // 取得Parse的Dress class var query = new Parse.Query(Dress); // 創建一個找查Dress的Query物件 query.limit(limit); // 設定Query條件 query.skip(skip); query.descending("createdAt"); // 按照創造時間降冪排序 // 執行query (網路連結直到此處才會觸發) query.find({success: function(results){ // 處理回傳的結果,results變數指向回傳的物件列表 ... }}); }
  • 47. Handler Function (Catalog) {success: function(results){ var objList = results.map(function(e){ return e.toJSON() }); // 將物件列表轉化成版型能消化的格式 document.getElementById('content').innerHTML = templates.catalogTemplate(objList); // 呼叫型錄的模板函數。 query.limit(0); query.skip(0); // 設成0, 我們才能找到所有Dress object總數 var option = {}; query.count({success: function(count){ var totalPage = Math.ceil(count / limit); // Math.celi(3.1415926) = 4; var currentPage = parseInt(page); // 轉型( string => int ) option = { // Watch out the limit. 'previous': (currentPage === 1) ? 1 : currentPage-1, 'next': (currentPage === totalPage) ? currentPage : currentPage+1, // 不可以超過最前最後頁 'current': currentPage, 'last': totalPage, }; document.getElementById('pagination').innerHTML = templates.catalogPaginationTemplate(option); // 呼叫分頁的模板函數。 }, error: function(err){} }); }
  • 48. Handler Function (Dress Detail) if(有洋裝Id參數){ 設定查詢參數(); // Parse Query 查詢Parse伺服器資料庫(); // 取回物件內容 印出產品細則版型(); 綁定加入購物車功能(); // Parse Relational Object } else { 重新導向到首頁(); }
  • 49. Handler Function (Dress Detail) var handler = function(dress_id){ if(dress_id){ var Dress = Parse.Object.extend("Dress"); // 取得Parse的Dress class var query = new Parse.Query(Dress); // 創建一個找查Dress的Query物件 query.get(dress_id, { // 執行query,注意get方法 -> 給定物件ID, 回傳物件 success: function(dress){ document.getElementById('content').innerHTML = templates.dress_detialTemplate(dress.toJSON()); 綁定加入購物車功能 (); // 下一張slide會解釋 }, error: function(object, error){ } }); } else { window.location.hash = ''; } }
  • 50. Parse Relational Object var John = { ‘height’: 180, ‘girlfriend’: Jenny } What is the relationship between John and Jenny? How tall is John’s girlfriend? John.girlfriend.height = 167 Why? Data Consistency. var Jenny = { ‘height’: 167, }
  • 51. Parse Relational Object var order = { ‘user’: <User obj>, ‘dress’: <Dress obj>, ‘amount’: 10, }
  • 52. Handler Function (Dress Detail) document.getElementById('addToCart').addEventListener('click', function(){ var currentUser = Parse.User.current(); // 檢查登入 if(currentUser){ var e = document.getElementById('amount'); var amount = parseInt(e.options[e.selectedIndex].value); myCart.setAmountTo(currentUser, dress, amount, function(){ alert("此商品已加入到您的購物車。 "); }); // 下一張slide會解釋 } else { // 重新導向到登入頁面,登入後會回到商品 window.location.hash = 'login/'+ window.location.hash; } });
  • 53. myCart.setAmoutTo myCart = { setAmountTo: function(user, dress, amount, callback){ var Order = Parse.Object.extend("Order"); // 取得Parse的Order class // 創建一個找查Order的Query物件 var query = new Parse.Query(Order); // 設定Query條件(object的user欄位指向到給定的User object) query.equalTo('user', user); // 設定Query條件(object的dress欄位指向到給定的Dress object) query.equalTo('dress', dress); // 執行query,注意first方法 -> 給定物件ID, 回傳物件列表第一項(可能會沒有) query.first({success: 查詢成功的回調函數, error: 查詢失敗的回調函數}); }, }; /* * myCart.setAmountTo(User物件, Dress物件, 數量(int), 回調函數); */
  • 54. myCart.setAmoutTo { success: function(order){ if( amount === 0 && order ){ // 如果已經有存在的order,並收到將數量設成0的話,等於消滅order物件 order.destroy({ // 消滅Parse物件 success: function(order){ callback(); //調用當作參數的callback函數 } }); } else { if( order === undefined ){ // 如果order還不存在,創一個新的object order = new Order(); order.set('user', user); // 指定新object的user欄位指向到給定的Dress object order.set('dress', dress); // 指定新object的dress欄位指向到給定的Dress object } order.set('amount', amount); order.save(null, { // 將新增或更改過的order object 存到Parse Server success: function(order){ callback(); } }); } }, error: function(object, err){ } }
  • 55. Handler Function (My Cart) if (登入了){ 設定查詢參數(); // Parse Query for Order 查詢Parse伺服器資料庫(); // 取回物件內容 迴圈印出各訂單並綁上修改數量和刪除的事件(); } else { 重新導向到首頁(); }
  • 56. Handler Function (My Cart) mycart: function(){ var currentUser = Parse.User.current(); if (currentUser) { var Order = Parse.Object.extend("Order"); var query = new Parse.Query(Order); query.equalTo('user', currentUser); query.include('dress'); query.find({success: 登入成功的回調函數 , error: 登入失敗的回調函數 }); } else { window.location.hash = 'login/'+ window.location.hash; } }
  • 57. Handler Function (My Cart) { success: function (results) { var objList = results.map(function (e) { return { 'dressId': e.get('dress').id, 'amount': e.get('amount'), 'name': e.get('dress').get('name'), 'previewUrl': e.get('dress').get('previewUrl'), } }); document.getElementById('content').innerHTML = templates.mycartTemplate(objList); results.forEach(function (e) { var changeAmount = document.getElementById('change_amount_' + e.get('dress').id); changeAmount.addEventListener('change', function () { var amount = parseInt(this.options[this.selectedIndex].value); myCart.setAmountTo(currentUser, e.get('dress'), amount, function () {}); }); var cancelOrderBtn = document.getElementById('cancel_order_' + e.get('dress').id); cancelOrderBtn.addEventListener('click', function () { myCart.setAmountTo(currentUser, e.get('dress'), 0, function () { if (cancelOrderBtn.parentNode.parentNode.childElementCount === 1) { handlers.mycart(); } else { cancelOrderBtn.parentNode.remove(); } }); }); }); document.getElementById('payButton').parentNode.addEventListener('click', function () { alert('沒做這功能喔'); }); }, error: function (error){ }, }
  • 58. Handler Function // See the pattern? function(){ 預處理(); // ex: 檢查登入狀況 載入模型(); // optional 使用樣板引擎將模型顯示到browser上(); 事件綁定(); // Event binding (eg. click) }; 註:這樣的設計只是參考不是絕對,應按照合理的情況去撰寫 相對應的程序
  • 59. Privilege Issues How to protect data?
  • 60. Parse Class-Based Privilege (Data Browser) Ref: https://parse.com/docs/data#security-classes
  • 61. Parse Class-Based Privilege (Data Browser)
  • 62. Parse ACL (more complicated!) ACL: Access Control List “...each object has a list of users and roles along with what permissions that user or role has...” user vs. roles Ref: https://parse.com/docs/data#security-objects
  • 63. Parse ACL { "*":{"read":true}, "SaMpLeUsErId":{"write": true,"read":true} } SaMpLeUsErId 這個user可以讀寫這個物件 其他人只能讀
  • 64. Parse ACL How to make the certain ‘Order’ object available only to the owner? var orderACL = new Parse.ACL(); orderACL.setPublicReadAccess(false); orderACL.setPublicWriteAccess(false); orderACL.setReadAccess(user, true); orderACL.setWriteAccess(user, true); // 附加到物件實體(instance)上 order.setACL(postACL); order.save(); Ref: http://parse.com/docs/js/symbols/Parse.ACL.html
  • 66. Parse Store All Source codes are available on GitHub: https://github.com/pa4373/parsestore_js using git to clone! $ git clone https://github.com/pa4373/parsestore_js.git
  • 67. More Topics…... ● Parse JavaScript Tutorial ● Parse JavaScript SDK Reference ● Pricing ● Loading indicator ● Backbone.js ○ Data-Binding