到目前为止,我们一直在使用硬编码数据,这通常是不现实的。大多数的时间,你有一些 REST 或实时数据需要与后端同步;Ember Data 可以帮助我们了。我已经得到了一个地址簿应用程序的。左边的是我们的联系人列表,当被点击时,我们会显示右边的联系人。在这一集里,我们将看到如何Ember Data 可以帮助我们填充列表-创建和编辑。
我已经得到了一个地址簿应用程序的框架。左边的是我们的联系人列表,当被点击时,我们会显示右边的联系人。在这一集里,我们将看到如何Ember Data可以帮助我们填充-创建和编辑列表项。
所有八次课程的英文视频下载在链接:http://pan.baidu.com/s/1bo2HEdp 密码:lbx0;分享给大家。
Ember Data
首先让我们创建数据仓库:
App.Store = DS.Store.extend({
revision: 12,
adapter: DS.RESTAdapter.create({
url: 'http://addressbook-api.herokuapp.com'
})
});
该仓库是您和数据仓库之间的主要接口。当你获取和访问数据时,它本质上是一个对象台账。该适配器负责将仓库请求转换为对持久层采取适当的动作。我们使用默认的REST适配器,因此它将Contact.find(1)
自动转换为一个Ajax请求/contacts/1
。理想情况下,您可以不用更改任何其他应用程序代码来更换适配器。
App.Contact = DS.Model.extend({
first: DS.attr('string'),
last: DS.attr('string'),
avatar: DS.attr('string'),
github: DS.attr('string'),
notes: DS.attr('string')
});
model 模型
我们得到了所有这些字符串属性的联系模型。我们让DS.attr模型知道这些属性,并能够持久化到我们的数据仓库。
最后,我们可以把Contact信息插入路由的模型钩子。
App.ApplicationRoute = Ember.Route.extend({
model: function() {
return App.Contact.find();
}
});
App.ContactRoute = Ember.Route.extend({
model: function(params) {
return App.Contact.find(params.contact_id);
}
});
就像我们的应用程序的是有生命的。你可能想知道其中的细节,是从一个服务器获取资源,这是一个异步操作。
Contact.find(1)总是返回一个模型。它会发送请求,但立即返回一个空属性模型。由于我们的模板是绑定到模型数据,它将填充的模型属性,尽快向服务器请求数据。这不需要考虑任何的动作。
任何已被调用的模型的后续调用将返回同一个对象作为第一个调用。一旦服务器已作出回应,就不再需要访问服务器了。这使得应用程序真正有效。因为在contactroute模型钩是如此普遍,我们甚至不需要它,ember有默认的约定。
它怎么知道?
你可能非常想知道ember是如何知道网址的。Ember对象的toString方法返回相当聪明的信息 restadapter使用它来构建传统的URL。
App.Contact.toString()
'App.Contact'
让我们再看一下代码。非常令人难以置信的是,我们用这么少的代码中得到这么多的功能。
完整代码:
<!DOCTYPE html>
<!--
Created using JS Bin
http://jsbin.com
Copyright (c) 2016 by symphonyh (http://jsbin.com/doricu/1/edit)
Released under the MIT license: http://jsbin.mit-license.org
-->
<meta name="robots" content="noindex">
<html>
<head>
<meta name="description" content="ED: Reading" />
<script src="http://code.jquery.com/jquery-1.9.1.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/handlebars.js/1.0.0-rc.4/handlebars.js"></script>
<script src="http://builds.emberjs.com.s3.amazonaws.com/ember-1.0.0-rc.4.js"></script>
<script src="http://builds.emberjs.com.s3.amazonaws.com/ember-data-0.13.js"></script>
<meta charset=utf-8 />
<title>JS Bin</title>
<style id="jsbin-css">
/* @override http://localhost:8000/css/app.css */
/* @override http://localhost:8000/css/app.css */
body {
font-family: sans-serif;
background: #fff;
}
#master {
position: absolute;
left: 0;
width: 200px;
top: 0;
bottom: 0;
border-top: 1px solid #888;
}
#detail {
position: absolute;
left: 200px;
right: 0;
top: 0;
bottom: 0;
border-left: 1px solid #b4b4b4;
border-top: 1px solid #888;
overflow: auto;
}
.welcome {
padding: 20px;
text-align: center;
}
#master ul {
list-style: none;
padding-left: 0;
margin: 0;
}
#master a {
display: block;
padding: 4px 8px;
text-decoration: none;
color: inherit;
font-size: 14px;
background: #fff;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
#master a:hover {
background: #fcfcfc;
}
#master a.active {
background: #3875d7;
color: #fff;
}
#master li {
border-bottom: 1px solid #e0e0e0;
}
#master header {
font-size: 12px;
text-align: center;
padding: 2px;
border-bottom: 1px solid #aaa;
color: #666;
background-color: #ffffff;
background-image: -webkit-gradient(linear, left top, left bottom, from(#ffffff), to(#eeeeee));
background-image: -webkit-linear-gradient(top, #ffffff, #eeeeee);
background-image: -moz-linear-gradient(top, #ffffff, #eeeeee);
background-image: -o-linear-gradient(top, #ffffff, #eeeeee);
background-image: linear-gradient(to bottom, #ffffff, #eeeeee);
}
#master ul {
position: absolute;
top: 19px;
left: 0;
right: 0;
bottom: 43px;
overflow: auto;
}
#controls {
position: absolute;
bottom: 0;
left: 0;
right: 0;
padding: 4px;
border-top: 1px solid #aaa;
background-color: #ffffff;
background-image: -webkit-gradient(linear, left top, left bottom, from(#ffffff), to(#eeeeee));
background-image: -webkit-linear-gradient(top, #ffffff, #eeeeee);
background-image: -moz-linear-gradient(top, #ffffff, #eeeeee);
background-image: -o-linear-gradient(top, #ffffff, #eeeeee);
background-image: linear-gradient(to bottom, #ffffff, #eeeeee);
}
.contact-data dt,
.contact-header .avatar {
width: 30%;
text-align: right;
color: #888;
}
.contact-data dt label {
display: inline-block;
padding: 4px;
}
.contact-data input[type=text],
.contact-data textarea {
font-family: inherit;
font-size: inherit;
border: 1px solid transparent;
padding: 2px;
width: 80%;
outline: none;
}
.contact-data input[type=text]:hover,
.contact-data textarea:hover {
border-color: #ccc;
}
.contact-data input[type=text]:focus,
.contact-data textarea:focus {
border-color: #9cbaeb;
}
.contact-data textarea {
height: 150px;
padding: 4px 2px;
}
.contact-data dd,
.contact-header h1 {
width: 65%;
}
.contact-data dt,
.contact-data dd,
.contact-header h1,
.contact-header .avatar {
display: inline-block;
vertical-align: top;
margin: 0;
padding: 0;
}
.contact-header h1 {
font-size: 18px;
}
.contact-header img {
max-width: 64px;
height: 64px;
}
.contact-header {
margin-top: 55px;
}
.contact-data a {
margin-left: 4px;
color: #3875d7;
text-decoration: none;
}
.contact-data a:hover {
color: #d79d38;
}
.btn {
display: inline-block;
padding: 4px 10px 4px;
font-size: 16px;
line-height: 20px;
color: #333333;
text-align: center;
text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75);
vertical-align: middle;
background-color: #f5f5f5;
background-image: -ms-linear-gradient(top, #ffffff, #e6e6e6);
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6));
background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6);
background-image: -o-linear-gradient(top, #ffffff, #e6e6e6);
background-image: linear-gradient(top, #ffffff, #e6e6e6);
background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6);
border: 1px solid #cccccc;
border-color: #ccc #ccc #888;
border-bottom-color: #b3b3b3;
border-radius: 4px;
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
background-repeat: repeat-x;
}
.btn:hover,
.btn:active,
.btn.active,
.btn.disabled,
.btn[disabled] {
background-color: #e6e6e6;
*background-color: #d9d9d9;
}
.btn:hover {
color: #333333;
text-decoration: none;
background-color: #e6e6e6;
*background-color: #d9d9d9;
background-position: 0 -15px;
}
.btn.active,
.btn:active {
background-color: #e6e6e6;
background-image: none;
outline: 0;
box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
}
.btn.disabled,
.btn[disabled] {
cursor: default;
background-color: #e6e6e6;
background-image: none;
opacity: 0.65;
box-shadow: none;
}
.pull-right {
float: right;
}
</style>
</head>
<body>
<script type="text/x-handlebars">
<nav id="master">
<header>
All Contacts ({{controller.length}})
</header>
<ul>
{{#each controller}}
<li>
{{#linkTo "contact" this}}
{{first}} {{last}}
{{/linkTo}}
</li>
{{/each}}
</ul>
<div id="controls">
<button class="btn">+</button>
<button class="btn pull-right">-</button>
</div>
</nav>
<div id="detail">
{{outlet}}
</div>
</script>
<script type="text/x-handlebars" id="index">
<div class="welcome">
<h2>Address Book</h2>
</div>
</script>
<script type="text/x-handlebars" id="contact">
<header class="contact-header">
<div class="avatar">
<img {{bindAttr src="avatar"}}>
</div>
</header>
<dl class="contact-data">
<dt><label for="contact-first">First Name</label></dt>
<dd>{{input value=first id="contact-first"}}</dd>
<dt><label for="contact-last">Last Name</label></dt>
<dd>{{input value=last id="contact-last"}}</dd>
<dt><label for="contact-avatar">Avatar URL</label></dt>
<dd>{{input value=avatar id="contact-avatar"}}</dd>
<dt><label for="contact-github">Github</label></dt>
<dd>
{{input value=github id="contact-github"}}
{{#if github}}
<br><a {{bindAttr href="github"}}>view ➚</a>
{{/if}}
</dd>
<dt><label for="contact-twitter">Twitter</label></dt>
<dd>
{{input value=twitter id="contact-twitter"}}
{{#if twitter}}
<br><a {{bindAttr href="twitter"}}>view ➚</a>
{{/if}}
</dd>
<dt><label for="contact-notes">Notes</label></dt>
<dd>{{textarea value=notes id="contact-notes"}}</dd>
</dl>
</script>
<script id="jsbin-javascript">
var App = Ember.Application.create();
App.Store = DS.Store.extend({
revision: 12,
adapter: DS.RESTAdapter.create({
url: 'http://addressbook-api.herokuapp.com'
})
});
App.Contact = DS.Model.extend({
first: DS.attr('string'),
last: DS.attr('string'),
avatar: DS.attr('string'),
github: DS.attr('string'),
twitter: DS.attr('string'),
notes: DS.attr('string')
});
App.Router.map(function() {
this.resource('contact', {path: '/contact/:contact_id'});
});
App.ApplicationRoute = Ember.Route.extend({
model: function() {
return App.Contact.find();
}
});
</script>
</body>
</html>