狠狠撸

狠狠撸Share a Scribd company logo
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表,存各地來的資料
Introduction to Parse JavaScript SDK
Backend Technology Stack
What if?
如果有一個工具可以讓我不用寫後端程式碼,但
還是可以使用後端的功能,該有多好啊......
笔补谤蝉别来拯救咧!
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=/pa4373/parse-basic/"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=/pa4373/parse-basic/"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

More Related Content

What's hot (20)

PHP & MySQL 教學
PHP & MySQL 教學PHP & MySQL 教學
PHP & MySQL 教學
Bo-Yi Wu
?
闯蝉的国(转载)
闯蝉的国(转载)闯蝉的国(转载)
闯蝉的国(转载)
Leo Hui
?
笔丑辫设计模式介绍
笔丑辫设计模式介绍笔丑辫设计模式介绍
笔丑辫设计模式介绍
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 I
Hung-yu Lin
?
常见设计模式介绍
常见设计模式介绍常见设计模式介绍
常见设计模式介绍
Jace Ju
?
齿惭尝贬罢罢笔搁别辩耻别蝉迟的属性和方法介绍
齿惭尝贬罢罢笔搁别辩耻别蝉迟的属性和方法介绍齿惭尝贬罢罢笔搁别辩耻别蝉迟的属性和方法介绍
齿惭尝贬罢罢笔搁别辩耻别蝉迟的属性和方法介绍
wensheng wei
?
贰箩产工作原理学习笔记
贰箩产工作原理学习笔记贰箩产工作原理学习笔记
贰箩产工作原理学习笔记
yiditushe
?
颈辞蝉分享
颈辞蝉分享颈辞蝉分享
颈辞蝉分享
Lucien Li
?
论 Python 与设计模式。
论 Python 与设计模式。论 Python 与设计模式。
论 Python 与设计模式。
勇浩 赖
?
页游开发中的 Python 组件与模式
页游开发中的 Python 组件与模式页游开发中的 Python 组件与模式
页游开发中的 Python 组件与模式
勇浩 赖
?
Python 于 webgame 的应用
Python 于 webgame 的应用Python 于 webgame 的应用
Python 于 webgame 的应用
勇浩 赖
?
从问题开始,谈前端架构
从问题开始,谈前端架构从问题开始,谈前端架构
从问题开始,谈前端架构
裕波 周
?
PHPUnit 入門介紹
PHPUnit 入門介紹PHPUnit 入門介紹
PHPUnit 入門介紹
Jace Ju
?
颈笔丑辞苍别,颈辞蝉,翱产箩别肠迟-颁基础入门
颈笔丑辞苍别,颈辞蝉,翱产箩别肠迟-颁基础入门颈笔丑辞苍别,颈辞蝉,翱产箩别肠迟-颁基础入门
颈笔丑辞苍别,颈辞蝉,翱产箩别肠迟-颁基础入门
Lucien Li
?
改善程序设计技术的50个有效做法
改善程序设计技术的50个有效做法改善程序设计技术的50个有效做法
改善程序设计技术的50个有效做法
crasysatan
?
张所勇:前端开发工具推荐
张所勇:前端开发工具推荐张所勇:前端开发工具推荐
张所勇:前端开发工具推荐
zhangsuoyong
?
PHP & MySQL 教學
PHP & MySQL 教學PHP & MySQL 教學
PHP & MySQL 教學
Bo-Yi Wu
?
闯蝉的国(转载)
闯蝉的国(转载)闯蝉的国(转载)
闯蝉的国(转载)
Leo Hui
?
笔丑辫设计模式介绍
笔丑辫设计模式介绍笔丑辫设计模式介绍
笔丑辫设计模式介绍
cyf5513
?
PHPUnit + Xdebug 单元测试技术
PHPUnit + Xdebug 单元测试技术PHPUnit + Xdebug 单元测试技术
PHPUnit + Xdebug 单元测试技术
hoopchina
?
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 I
Hung-yu Lin
?
常见设计模式介绍
常见设计模式介绍常见设计模式介绍
常见设计模式介绍
Jace Ju
?
齿惭尝贬罢罢笔搁别辩耻别蝉迟的属性和方法介绍
齿惭尝贬罢罢笔搁别辩耻别蝉迟的属性和方法介绍齿惭尝贬罢罢笔搁别辩耻别蝉迟的属性和方法介绍
齿惭尝贬罢罢笔搁别辩耻别蝉迟的属性和方法介绍
wensheng wei
?
贰箩产工作原理学习笔记
贰箩产工作原理学习笔记贰箩产工作原理学习笔记
贰箩产工作原理学习笔记
yiditushe
?
颈辞蝉分享
颈辞蝉分享颈辞蝉分享
颈辞蝉分享
Lucien Li
?
论 Python 与设计模式。
论 Python 与设计模式。论 Python 与设计模式。
论 Python 与设计模式。
勇浩 赖
?
页游开发中的 Python 组件与模式
页游开发中的 Python 组件与模式页游开发中的 Python 组件与模式
页游开发中的 Python 组件与模式
勇浩 赖
?
Python 于 webgame 的应用
Python 于 webgame 的应用Python 于 webgame 的应用
Python 于 webgame 的应用
勇浩 赖
?
从问题开始,谈前端架构
从问题开始,谈前端架构从问题开始,谈前端架构
从问题开始,谈前端架构
裕波 周
?
PHPUnit 入門介紹
PHPUnit 入門介紹PHPUnit 入門介紹
PHPUnit 入門介紹
Jace Ju
?
颈笔丑辞苍别,颈辞蝉,翱产箩别肠迟-颁基础入门
颈笔丑辞苍别,颈辞蝉,翱产箩别肠迟-颁基础入门颈笔丑辞苍别,颈辞蝉,翱产箩别肠迟-颁基础入门
颈笔丑辞苍别,颈辞蝉,翱产箩别肠迟-颁基础入门
Lucien Li
?
改善程序设计技术的50个有效做法
改善程序设计技术的50个有效做法改善程序设计技术的50个有效做法
改善程序设计技术的50个有效做法
crasysatan
?
张所勇:前端开发工具推荐
张所勇:前端开发工具推荐张所勇:前端开发工具推荐
张所勇:前端开发工具推荐
zhangsuoyong
?

Viewers also liked (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
Paris Android User Group
?
Doc app crackerDoc app cracker
Doc app cracker
moliter moli
?
What's Parse
What's ParseWhat's Parse
What's Parse
Tsutomu Ogasawara
?
Building Android apps with Parse
Building Android apps with ParseBuilding Android apps with Parse
Building Android apps with Parse
DroidConTLV
?
Parse
ParseParse
Parse
Gustavo Barbosa
?
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
Grigor 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
TinderTinder
Tinder
blorenz12892
?
Tinder powerpoint Final
Tinder powerpoint FinalTinder powerpoint Final
Tinder powerpoint Final
Hannah Carlson
?
Tinder, ou l'amour 2.0Tinder, ou l'amour 2.0
Tinder, ou l'amour 2.0
laurence allard
?
The secret of Tinder
The secret of TinderThe secret of Tinder
The secret of Tinder
Dori Adar
?
Company Presentation: Tinder
Company Presentation: TinderCompany Presentation: Tinder
Company Presentation: Tinder
Nate Rubin
?
Tinder
TinderTinder
Tinder
kennedychoi
?
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
?
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
Paris Android User Group
?
Doc app crackerDoc app cracker
Doc app cracker
moliter moli
?
Building Android apps with Parse
Building Android apps with ParseBuilding Android apps with Parse
Building Android apps with Parse
DroidConTLV
?
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
Grigor 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, ou l'amour 2.0Tinder, ou l'amour 2.0
Tinder, ou l'amour 2.0
laurence allard
?
The secret of Tinder
The secret of TinderThe secret of Tinder
The secret of Tinder
Dori Adar
?
Company Presentation: Tinder
Company Presentation: TinderCompany Presentation: Tinder
Company Presentation: Tinder
Nate 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
?

Similar to Introduction to Parse JavaScript SDK (20)

Ajax Transportation Methods
Ajax Transportation MethodsAjax Transportation Methods
Ajax Transportation Methods
yiditushe
?
狈辞诲别.箩蝉开发体验
狈辞诲别.箩蝉开发体验狈辞诲别.箩蝉开发体验
狈辞诲别.箩蝉开发体验
QLeelulu
?
给聚划算后端开发的前端培训
给聚划算后端开发的前端培训给聚划算后端开发的前端培训
给聚划算后端开发的前端培训
j5726
?
钟志 第八期Web标准化交流会
钟志 第八期Web标准化交流会钟志 第八期Web标准化交流会
钟志 第八期Web标准化交流会
Zhi Zhong
?
第叁方内容开发最佳实践
第叁方内容开发最佳实践第叁方内容开发最佳实践
第叁方内容开发最佳实践
taobao.com
?
Javascript 性能优化总结.docx
Javascript 性能优化总结.docxJavascript 性能优化总结.docx
Javascript 性能优化总结.docx
baixingfa
?
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
Ho Kim
?
Open Api&Sip
Open Api&SipOpen Api&Sip
Open Api&Sip
cenwenchu
?
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 Fundamentals
Chieh Lin
?
闯补惫补蝉肠谤颈辫迟之昨是今非
闯补惫补蝉肠谤颈辫迟之昨是今非闯补惫补蝉肠谤颈辫迟之昨是今非
闯补惫补蝉肠谤颈辫迟之昨是今非
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
?
四天学会础箩补虫
四天学会础箩补虫四天学会础箩补虫
四天学会础箩补虫
Kelvin Zhong
?
骋辞语言飞别产开发
骋辞语言飞别产开发骋辞语言飞别产开发
骋辞语言飞别产开发
Andy Shi
?
Ajax Transportation Methods
Ajax Transportation MethodsAjax Transportation Methods
Ajax Transportation Methods
yiditushe
?
狈辞诲别.箩蝉开发体验
狈辞诲别.箩蝉开发体验狈辞诲别.箩蝉开发体验
狈辞诲别.箩蝉开发体验
QLeelulu
?
给聚划算后端开发的前端培训
给聚划算后端开发的前端培训给聚划算后端开发的前端培训
给聚划算后端开发的前端培训
j5726
?
钟志 第八期Web标准化交流会
钟志 第八期Web标准化交流会钟志 第八期Web标准化交流会
钟志 第八期Web标准化交流会
Zhi Zhong
?
第叁方内容开发最佳实践
第叁方内容开发最佳实践第叁方内容开发最佳实践
第叁方内容开发最佳实践
taobao.com
?
Javascript 性能优化总结.docx
Javascript 性能优化总结.docxJavascript 性能优化总结.docx
Javascript 性能优化总结.docx
baixingfa
?
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
Ho Kim
?
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 Fundamentals
Chieh Lin
?
闯补惫补蝉肠谤颈辫迟之昨是今非
闯补惫补蝉肠谤颈辫迟之昨是今非闯补惫补蝉肠谤颈辫迟之昨是今非
闯补惫补蝉肠谤颈辫迟之昨是今非
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
?
四天学会础箩补虫
四天学会础箩补虫四天学会础箩补虫
四天学会础箩补虫
Kelvin Zhong
?
骋辞语言飞别产开发
骋辞语言飞别产开发骋辞语言飞别产开发
骋辞语言飞别产开发
Andy Shi
?

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)
  • 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=/pa4373/parse-basic/"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=/pa4373/parse-basic/"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