来源:yoember.com
作者:Zoltan
声明:本文的转载与翻译是经过作者认可的,再次感谢原作,如有侵权请给我留言,我会删除博文!! 希望本系列教程能帮助更多学习Ember.js的初学者。
接着前面三篇:
- 环境搭建以及使用Ember.js创建第一个静态页面
- 引入计算属性、action、动态内容
- 模型,保存数据到数据库
应用发布
发布方式一
发布的详细教程请看guide on firebase。执行如下命令发布项目。
1 2 3 4
| npm install -g firebase-tools ember build --prod firebase login firebase init
|
执行命令过程需要输入一个public的目录,输入dist
后按enter
。更新firebase.json
的内容。
1 2 3 4 5 6 7 8
| { "firebase": "YOUR-APP-NAME", "public": "dist", "rewrites": [{ "source": "**", "destination": "/index.html" }] }
|
遗憾的是在我电脑上一直提示没有firebase
命令,即使我已经安装了这个插件也不行。
发布方式二
由于上述方式无法发布想到到firebase,所以使用最原始的发布方式,使用ember
命令打包项目。然后自己把项目部署到服务器上。
- 打包项目
打包项目使用命令ember build --prod
,等到命令执行完毕后再项目的dist
目录下的所有文件即使打包后的项目文件。
- 复制打包后的文件到服务器上
得到打包后的文件后可以直接把这些文件复制到服务器上运行,比如复制到tomcat的webapps
目录下。
- 运行项目
复制到服务器之后启动服务器,直接访问:http://localhost:8080
增加删除、修改功能
修改项目的library列表页面,增加删除和修改功能。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
|
## List
<div class="row"> {{#each model as |library|}} <div class="col-md-4"> <div class="panel panel-default library-item"> <div class="panel-heading">
### {{library.name}}
</div> <div class="panel-body">
Address: {{library.address}}
Phone: {{library.phone}}
</div> <div class="panel-footer text-right"> {{#link-to 'libraries.edit' library.id class='btn btn-success btn-xs'}}Edit{{/link-to}} <button class="btn btn-danger btn-xs" {{action 'deleteLibrary' library}}>Delete</button> </div> </div> </div> {{/each}} </div>
|
相比原来的代码增加了一个连接和一个按钮,分别用于编辑和删除library信息。相对于需要增加一个路由libraries/edit
和一个处理的动作{{action 'deleteLibrary'}}
。
如果此时运行http://localhost:4200/libraries会出现错误,因为还没定义路由libraries/edit
和action
。别急,先一步步来,下面先增加一些css样式。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| # app/styles/app.scss @import 'bootstrap';
body { padding-top: 20px; }
html { overflow-y: scroll; }
.library-item { min-height: 150px; }
|
创建路由libraries/edit
和路由对应的模板
简单起见直接使用Ember CLI命令创建,就不手动创建了。执行命令:ember g route libraries/edit
创建路由和路由对应的模板。
创建完成之后还需要手动修改app/router.js
文件,内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
|
import Ember from 'ember'; import config from './config/environment';
var Router = Ember.Router.extend({ location: config.locationType });
Router.map(function() {
this.route('about'); this.route('contact');
this.route('admin', function() { this.route('invitation'); this.route('contact'); });
this.route('libraries', function() { this.route('new'); this.route('edit', { path: '/:library_id/edit' }); }); });
export default Router;
|
注意this.route('edit', { path: '/:library_id/edit' });
这行代码的设置。与普通的路由稍有不同这里增加了一个参数,并且参数内使用path
设定路由渲染之后edit
会被/:library_id/edit
替换。
编译、渲染之后的URL格式为http://example.com/libraries/1234/edit
其中:library_id
这是一个动态段,这个URL例子中动态段library_id
的值就是1234
,并且可以在路由类中获取这个动态段的值。
更多有关动态段的介绍请看Ember.js 入门指南之十三{{link-to}} 助手或者Dynamic Segments。
配置完路由之后修改路由libraries/edit.js
的代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| import Ember from 'ember';
export default Ember.Route.extend({
model(params) { return this.store.findRecord('library', params.library_id); },
actions: {
saveLibrary(newLibrary) { newLibrary.save().then(() => this.transitionTo('libraries')); },
willTransition(transition) {
let model = this.controller.get('model');
if (model.get('hasDirtyAttributes')) { let confirmation = confirm("Your changes haven't saved yet. Would you like to leave this form?");
if (confirmation) { model.rollbackAttributes(); } else { transition.abort(); } } } } });
|
代码this.store.findRecord('library', params.library_id);
的意思是根据模型的id
属性值查询某个记录,其中library_id
就是动态段的值,这个值是Ember解析URL得到的。正如前面所说:http://example.com/libraries/1234/edit
这个URL动态段的值就是1234
。
Ember会自动根据URL的格式解析得到。并且可以在路由类中获取。默认情况下动态段的值是数据的id
值。代码中的另外两个方法saveLibrary()
和willTransition()
在前一篇文章模型,保存数据到数据库已经介绍过,在此不再赘述。
方法willTransition()
的作用就是:当用户修改了数据之后没有点击保存就离开页面时会提示用户是否确认不保存就离开页面!通过控制器中的属性hasDirtyAttributes
判断页面的值是否发生了变化。方法rollbackAttributes()
会重置model
中的值。方法abourt()
可以阻止路由的跳转,有关路由的跳转请看Ember.js 入门指南之二十四终止与重试路由跳转。从new.hbs
复制代码到edit.hbs
,然后在稍加修改。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
|
## Edit Library
<div class="form-horizontal"> <div class="form-group"> <label class="col-sm-2 control-label">Name</label> <div class="col-sm-10"> {{input type="text" value=model.name class="form-control" placeholder="The name of the Library"}} </div> </div> <div class="form-group"> <label class="col-sm-2 control-label">Address</label> <div class="col-sm-10"> {{input type="text" value=model.address class="form-control" placeholder="The address of the Library"}} </div> </div> <div class="form-group"> <label class="col-sm-2 control-label">Phone</label> <div class="col-sm-10"> {{input type="text" value=model.phone class="form-control" placeholder="The phone number of the Library"}} </div> </div> <div class="form-group"> <div class="col-sm-offset-2 col-sm-10"> <button type="submit" class="btn btn-default" {{action 'saveLibrary' model}}>Save changes</button> </div> </div> </div>
|
等待项目重启完成,进入到修改界面,任意修改界面上的数据,不点击保存然后任意点击其他链接会弹出提示,询问你是否确认离开页面。操作步骤如下截图。
注意:看浏览器的URL。首页模板代码{{#link-to 'libraries.edit' library.id class='btn btn-success btn-xs'}}Edit{{/link-to}}
中的路由libraries.edit
渲染之后会得到形如libraries/xxx/edit
的URL,其中xxx
就是动态段的值。
弹出提示信息。如果点击取消会停留在当前页面,如果选中确定会跳转到首页(因为我点击的是菜单的Home)。
成功保存了修改的内容。到此实现了修改功能。
实现删除功能
删除功能比修改更加简单,直接在方法deleteLibrary
里根据id
属性值删除数据即可。id
属性值已经在模板页面作为参数传递到方法中。直接获取即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
import Ember from 'ember';
export default Ember.Route.extend({ model() { return this.store.findAll('library'); }, actions: { deleteLibrary(library) { let confirmation = confirm('Are you sure?');
if (confirmation) { library.destroyRecord(); } } } });
|
模板中是这样调用删除方法的
,看到参数library
了吧,这个参数就是一个library
模型对象。
可以直接调用方法destroyRecord()
实现删除数据。
选中确定之后删除就会立刻删除,列表上的数据也会动态更新。
家庭作业
参照library的功能实现contact的删除与修改。
新建路由和模板
1 2
| ember g route admin/contact/edit ember g template admin/contact/index
|
修改router.js,增加配置
1 2 3 4 5 6 7 8
|
this.route('admin', function() { this.route('invitation'); this.route('contact', function() { this.route('edit', { path: '/:contact_id/edit' }); }); });
|
省略其他内容,仅仅列出修改部分。
admin/contact.hbs
admin/contact/index.hbs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| {{! app/templates/admin/contact/index.hbs}}
# Contacts
<table class="table table-bordered table-striped"> <thead> <tr> <th>ID</th> <th>E-mail</th> <th>Message</th> <th>Operation</th> </tr> </thead> <tbody> {{#each model as |contact|}} <tr> <th>{{contact.id}}</th> <td>{{contact.email}}</td> <td>{{contact.message}}</td> <td> {{#link-to 'admin.contact.edit' contact.id class='btn btn-success btn-xs'}}Edit{{/link-to}} <button class="btn btn-danger btn-xs" {{action 'deleteContact' contact}}>Delete</button> </td> </tr> {{/each}}
</tbody> </table>
|
增加删除、修改按钮。
admin/contact/edit.hbs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| {{! app/templates/admin/contact/edit.hbs}}
<div class="col-md-6 col-xs-6"> <form> <div class="form-group"> <label for="exampleInputEmail1">Email address</label> {{input type="email" value=model.email class="form-control col-sm-6 col--6" placeholder="Please type your e-mail address." autofocus="autofocus"}} </div> <div class="form-group"> <label for="exampleInputPassword1">Your message</label> {{textarea class="form-control" placeholder="Your message. (At least 5 characters.)" rows="7" value=model.message}} </div>
<button class="btn btn-primary" disabled={{model.isDisabled}} {{action 'saveContact' model}}>Save</button> {{#link-to 'admin.contact' class="btn btn-default"}}Return{{/link-to}} </form> </div>
|
修改routes/context.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
import Ember from 'ember';
export default Ember.Route.extend({ model: function() { return this.store.findAll('contact'); }, actions: { deleteContact: function(contact) { let confirmation = confirm('Are you sure?');
if (confirmation) { contact.destroyRecord(); } } } });
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
|
import Ember from 'ember';
export default Ember.Route.extend({
model(params) { return this.store.findRecord('contact', params.contact_id); },
actions: {
saveContact(newContact) { newContact.save().then(() => this.transitionTo('admin.contact')); },
willTransition(transition) {
let model = this.controller.get('model');
if (model.get('hasDirtyAttributes')) { let confirmation = confirm("Your changes haven't saved yet. Would you like to leave this form?");
if (confirmation) { model.rollbackAttributes(); } else { transition.abort(); } } } } });
|
运行结果不再截图列出,请读者自行试验。
为了照顾懒人我把完整的代码放在GitHub上,可以拿来做参照。博文经过多次修改,博文上的代码与github代码可能有出入,不过影响不大!如果你觉得博文对你有点用,请在github项目上给我点个star
吧。您的肯定对我来说是最大的动力!!