emberjs
In this part, we will see how Ember works, how to use Ember Data and how to build something simple with it. Router, Route, Model, Template and Store are some of the concepts of Ember. I’m not going to explain every one of those, so if you feel stuck, use the documentation. As usual, you can download the code for this part here.
在这一部分中,我们将看到Ember的工作原理,如何使用Ember Data以及如何使用它来构建简单的东西。 路由器,路由,模型,模板和存储是Ember的一些概念。 我不会解释其中的每一个,因此,如果您感到困惑,请使用文档 。 与往常一样,您可以在此处下载该部分的代码。
让我们编码 (Let’s code)
Note that while developing with Ember, it’s a good idea to download the Ember Inspector. They released Ember with a Chrome Extension and now that extension is also on Firefox.
请注意,在使用Ember开发时,最好下载Ember Inspector。 他们发布了带有Chrome扩展程序的Ember,现在该扩展程序也在Firefox上。
For this example, we are going to put every line of JS inside /public/static/app.js
. In a real project, this is not a good idea. This simplifies our example but ask yourself – have you ever done some serious work with MVC architecture in just one big file? We saw how Laravel works: controllers are in one folder, each of them in one file, the configuration is in its own folder, the models too. I suggest you do the same thing with Ember when you dive into a proper project.
对于此示例,我们将JS的每一行都放在/public/static/app.js
。 在实际的项目中,这不是一个好主意。 这简化了我们的示例,但请问自己-您是否曾经在一个大文件中对MVC架构进行过认真的工作? 我们看到了Laravel的工作原理:控制器位于一个文件夹中,每个控制器都位于一个文件中,配置位于其自己的文件夹中,而模型也位于其中。 我建议您在进入适当的项目时对Ember做同样的事情。
The first thing you ever do when starting Ember is create the application. It is a global namespace for everything that you code with Ember. An Application can be created like this:
启动Ember时要做的第一件事就是创建应用程序。 它是您使用Ember编写的所有代码的全局命名空间。 可以这样创建一个应用程序:
App = Ember.Application.create();
I suggest activating a bit of debugging just by adding a line of code when you create the application.
我建议在创建应用程序时仅通过添加一行代码来激活一些调试功能。
App = Ember.Application.create({
LOG_TRANSITIONS: true
});
It doesn’t do much more than output your movement through the URLs and templates in the console. Also, we are going to use Ember Data which is a separate module of Ember and provides a nice integration with REST, translating everything from Store Object to request on the server. By default, Ember Data uses the Rest Adapter. You can also use the Fixture Adapter for testing and local development. Basically, Ember Data is a bridge between servers (Rest API) and local storage with the Store Object.
它的作用不只是通过控制台中的URL和模板输出您的动作。 另外,我们将使用Ember Data,它是Ember的一个独立模块,可与REST很好地集成,将所有内容从存储对象转换为服务器上的请求。 默认情况下,Ember Data使用剩余适配器。 您也可以使用夹具适配器进行测试和本地开发。 基本上,Ember Data是服务器(Rest API)和具有存储对象的本地存储之间的桥梁。
As we saw earlier, our API uses a namespace. Ember’s Data comes with a Rest Adapter which accepts a namespace, a prefix like we saw on Laravel Route groups. Lets pass in our namespace as an argument.
如前所述,我们的API使用命名空间。 Ember的数据带有一个Rest适配器,该适配器接受一个名称空间,这个前缀就像我们在Laravel Route组上看到的一样。 让我们传入名称空间作为参数。
App.ApplicationAdapter = DS.RESTAdapter.extend({
namespace: 'api/v1'
});
The adapter now requests all the data via example.com/api/v1/
.
现在,适配器通过example.com/api/v1/
请求所有数据。
Link the App Store with the Adapter and you are ready to start developing.
将App Store与适配器链接起来,就可以开始开发了。
App.Store = DS.Store.extend({
adapter: 'App.ApplicationAdapter'
});
One of the main concepts of Ember is URL. Everything is built around that idea. The Router keeps the URLs and the templates synchronized. Inside the Router, you can define a resource and map that resource to a specific URL. In this example, we will work only with the photo resource and the user resource. Feel free to add the category resource and make some one to many relations with Ember. Don’t forget that earlier we created some relations (one-to-many and belongs-to) with Laravel, but we didn’t use them. Using one-to-many relations in Laravel is easy enough, but I don’t want to overwhelm you. If enough interest in generated in the comments, we’ll add this to our app in a followup post, along with pagination.
Ember的主要概念之一是URL。 一切都围绕着这个想法。 路由器使URL和模板保持同步。 在路由器内部,您可以定义资源并将该资源映射到特定的URL。 在此示例中,我们将仅使用照片资源和用户资源。 随时添加类别资源,并与Ember建立一对多关系。 不要忘记,我们之前曾与Laravel建立了一些关系(一对多和属于),但是我们并没有使用它们。 在Laravel中使用一对多关系很容易,但是我不想让您不知所措。 如果对评论产生了足够的兴趣,我们会将其与分页一起添加到我们的应用程序中。
The Router is the place where all the routes should be defined. Here, we defined two resources with their URLs. The URL is optional here. :photo_id
is an argument. Let’s say that we navigate to example.com/photo/2
. What would happen? We have a resource that passes our request to the model or controller, and there we grab some data from the Store. If the Store doesn’t find it, it looks on the server. :photo_id
can be used to retrieve this data. In this case it looks for example.com/api/v1/photos/2
. You see that photo is plural. Ember by itself looks for the plural of the resource.
路由器是应定义所有路由的地方。 在这里,我们用它们的URL定义了两个资源。 URL在这里是可选的。 :photo_id
是一个参数。 假设我们导航到example.com/photo/2
。 会发生什么? 我们有一个资源可以将我们的请求传递给模型或控制器,在那里我们可以从商店中获取一些数据。 如果商店找不到,它将在服务器上查找。 :photo_id
可用于检索此数据。 在这种情况下,它将查找example.com/api/v1/photos/2
。 您会看到照片是复数的。 Ember本身会寻找资源的复数形式。
App.Router.map(function() {
this.resource('photo', {path: "/photo/:photo_id"});
this.resource('user', {path: "/user/:user_id"});
});
A route begins with the first letter of the Resource capitalized and should be in the App namespace. Also, add the word “Route” after the resource’s name. So for the photo resource the route should be like this: App.PhotoRoute
路由以资源首字母大写开头,并且应位于App命名空间中。 另外,在资源名称后添加“ Route”一词。 因此,对于照片资源,路线应如下所示: App.PhotoRoute
It should also extend the Route object.
它还应该扩展Route对象。
App.PhotoRoute = Ember.Route.extend({});
The Route Object can have different hooks for different things. Two of those hooks are used for defining the Controller name for that resource and defining the Model. Let’s stick with the model.
路由对象可以具有用于不同事物的不同钩子。 这些挂钩中的两个用于定义该资源的控制器名称和定义模型。 让我们坚持使用模型。
App.PhotoRoute = Ember.Route.extend({
model: function(params){
return this.store.find('photo', params.photo_id);
}
});
Inside, we have specified the model hook and passed a parameter. Where does this parameter go? The photo resource has a url with a parameter: /photo/:photo_id
. photo_id
is stored in params
and can be used inside the function. Don’t forget that every resource and every route has access to the Store. The Store object saves all the info inside it and uses Local Storage for better performance. That way, it cuts down the number of requests on the server. That’s why developing with Ember speeds up your application – in the end, the users are happier.
在内部,我们指定了模型挂钩并传递了一个参数。 该参数在哪里? 图片资源的网址带有参数: /photo/:photo_id
。 photo_id
存储在params
,可以在函数内部使用。 不要忘记,所有资源和每条路线都可以访问商店。 Store对象将所有信息保存在其中,并使用Local Storage以获得更好的性能。 这样,它减少了服务器上的请求数量。 这就是为什么使用Ember开发可以加快您的应用程序的速度-最终,用户会更快乐。
By using store.find('resource')
you can retrieve all the data for this resource from the store object. You can also retrieve only one row. For example, if you want to receive only a photo with a given id, use the store object and find the photo resource with the given id as a second parameter.
通过使用store.find('resource')
您可以从store对象中检索该资源的所有数据。 您也只能检索一行。 例如,如果您只想接收具有给定id的照片,请使用store对象并找到具有给定id的照片资源作为第二个参数。
return this.store.find('photo', params.photo_id);
Ember searches for the data in example.com/api/v1/photo_id
. By default, Ember works with the data by looking for ids. If you have inserted some relations for this resource, then you can also retrieve the data associated with it. That’s all the code for the routes, very similar for each case and straightforward:
灰烬在example.com/api/v1/photo_id
搜索数据。 默认情况下,Ember通过查找ID来处理数据。 如果您为此资源插入了一些关系,则还可以检索与其关联的数据。 这就是路线的所有代码,每种情况都非常相似且简单明了:
App.IndexRoute = Ember.Route.extend({
model: function(){
return this.store.find('photo');
}
});
App.PhotoRoute = Ember.Route.extend({
model: function(params){
return this.store.find('photo', params.photo_id);
}
});
App.UserRoute = Ember.Route.extend({
model: function(params){
return this.store.find('user', params.user_id);
}
});
A quick note: the IndexRoute is a default Route, linked with the root URL. And by root I mean the example.com/
URL. There are other default Routes, like ApplicationRoute that executes as the application starts.
快速说明:IndexRoute是默认路由,与根URL链接。 从根本上讲,我的意思是example.com/
URL。 还有其他默认路由,例如ApplicationRoute在应用程序启动时执行。
模型对象 (The Model Object)
Inside Ember’s Model Object, you specify the data and its type of resource. A nice feature of Ember is that when the value of a resource is changed and another value depends on the changed value, it automatically gets updated via some observer magic. A model should start with a capitalized letter and should extend the Model Object.
在Ember的模型对象中,您可以指定数据及其资源类型。 Ember的一个不错的功能是,当资源的值更改并且另一个值取决于更改后的值时,它会通过观察者的魔法自动更新。 模型应以大写字母开头,并应扩展模型对象。
App.Photo = DS.Model.extend({});
Inside that Object you should specify all the fields and other values that depend on those core values. You can also add Relations inside the model.
在该对象内部,您应该指定所有字段以及依赖于这些核心值的其他值。 您也可以在模型内部添加“关系”。
The photo model should look something like this:
照片模型应如下所示:
var attr = DS.attr; // This cuts my writting. Inside the model i use attr instead of DS.attr
App.Photo = DS.Model.extend({
user_id: attr("number"), // The expected value is a number
url: attr("string"), // The expected value is a string
title: attr("string"),
description: attr("string"),
category: attr("number"),
fullUrl: function(){ // Another value that depends on core values.
return "/files/" + this.get("url");
}.property('url'),
backgroundImage: function(){// This depends on another value but not on core ones
return 'background: url("' + this.get("fullUrl") + '") no-repeat; ';
}.property('fullUrl')
});
With attr
(DS.attr
) you specify how you want this data to arrive. For example, we want the user_id
value to be a number. This way, we are secured from outside data.
使用attr
( DS.attr
),您可以指定如何希望这些数据到达。 例如,我们希望user_id
值是一个数字。 这样,我们可以免受外部数据的攻击。
The User Model is similar. Remember, Ember Data will look for it in /api/v1/users
. The naming convention is a bit tricky. For example, if you request a resource named user, Ember Data will look for example.com/prefix/users
, and if you request a particular resource then it requests example.com/prefix/users/user_id
. Knowing how Laravel exposes the data and how Ember wants its data can save you from headaches.
用户模型相似。 请记住,Ember Data将在/api/v1/users
寻找它。 命名约定有些棘手。 例如,如果您请求一个名为user的资源,Ember Data将查找example.com/prefix/users
;如果您请求一个特定的资源,则它将请求example.com/prefix/users/user_id
。 了解Laravel如何公开数据以及Ember如何希望其数据可以使您免于头痛。
App.User = DS.Model.extend({
name: attr("string"),
lastname: attr("string"),
username: attr("string"),
fullname: function(){
return this.get('name') + " " + this.get('lastname');
}.property("name", "lastname")
});
观看次数 (Views)
Before jumping into templates, I suggest using the Ember Inspector to view the state of your application. There you can find the Routes, Views and Controllers. You can also find the relations between the Controllers and Routes. Take some time to look around with the Inspector, it’ll be of great help later on when you develop your own Ember apps.
在跳入模板之前,建议您使用Ember Inspector查看应用程序的状态。 在此可以找到路线,视图和控制器。 您还可以找到控制器和路由之间的关系。 花一些时间与Inspector环顾一下,稍后在您开发自己的Ember应用程序时会提供很大的帮助。
Do you remember the first template we wrote in the third part? That’s the application template. That template will be rendered when example.com
is accessed in the browser.
您还记得我们在第三部分中编写的第一个模板吗? 那就是应用程序模板。 在浏览器中访问example.com
时,将渲染该模板。
You can’t develop the application further if you don’t make a modification inside that template. Replace <!-- The content will be here -->
comment with: {{outlet}}
.
如果未在该模板内进行修改,则无法进一步开发该应用程序。 将<!-- The content will be here -->
替换为<!-- The content will be here -->
用{{outlet}}
注释。
Why? All our resources are nested inside the application route. But if I look at my code I see no Index on the Router. Why is that?
为什么? 我们所有的资源都嵌套在应用程序路由内。 但是,如果我查看代码,则路由器上看不到索引。 这是为什么?
By default the example.com/
url is assigned to IndexRoute
unless you’ve assigned that URL to another route. Ember puts the application onto the top level by default and everything is nested inside it. If you request a URL inside that application route, then by using {{outlet}}
as a placeholder, Ember takes that route’s template and puts it inside that placeholder.
默认情况下, example.com/
url分配给IndexRoute
除非您已将该URL分配给另一个路由。 Ember默认情况下将应用程序置于顶层,并且所有内容都嵌套在其中。 如果您在该应用程序路由内请求一个URL,则通过使用{{outlet}}
作为占位符,Ember将采用该路由的模板并将其放在该占位符内。
Lets make another template and use it for the IndexRoute
. This will be the first page. The first template is the app template. The index template will be rendered inside the application’s {{outlet}}
.
让我们制作另一个模板并将其用于IndexRoute
。 这将是第一页。 第一个模板是应用程序模板。 索引模板将呈现在应用程序的{{outlet}}
。
data-template-name
is the name of the template. All the code inside that script tag will be placed inside the {{outlet}}
.
data-template-name
是data-template-name
。 该脚本标签内的所有代码都将放置在{{outlet}}
。
<script type="text/x-handlebars" data-template-name="index">
<ul class="small-block-grid-1 medium-block-grid-2 large-block-grid-3 custom-grid-ul">
{{#each}}
<li {{bind-attr style="backgroundImage"}}>
<div class="custom-grid">
{{#link-to 'photo' this}}<h5 class="custom-header">{{title}}</h5>{{/link-to}}
<span>Author: {{user_id}}</span>
</div>
</li>
{{/each}}
</ul>
</script>
{{#each}}
is something like a loop. If the model of the template has an array and we want to query for all the data, then we use this special tag. This loop starts with {{#each}}
and ends with {{/each}}
. Inside this loop, we use all the values that are returned from the loop. Remember that inside the model we returned the resource photo
. The model retrieves the data from the Store and returns it to the template. Look at the Photo model. We specified some fields there and those fields are being used inside the template, inside the {{#each}}
loop.
{{#each}}
就像一个循环。 如果模板的模型有一个数组,而我们想查询所有数据,则使用此特殊标记。 此循环以{{#each}}
开始,以{{/each}}
。 在此循环内,我们使用从循环返回的所有值。 记住,在模型内部我们返回了资源photo
。 该模型从商店中检索数据,并将其返回到模板。 看一下照片模型。 我们在此处指定了一些字段,并且在模板内部{{#each}}
循环中使用了这些字段。
Another special tag is the {{#link-to}}
tag. This tag generates a link to the photo route and passes a parameter. The this
parameter is the id
of that object. In this case the photo id. Again, the {{#link-to}}
tag ends with {{/link-to}}
. {{title}}
isn’t a special tag, it merely retrieves the title value for that object.
另一个特殊标签是{{#link-to}}
标签。 该标签会生成指向照片路线的链接并传递参数。 this
参数是该对象的id
。 在这种情况下,带照片的身份证。 同样, {{#link-to}}
标签以{{/link-to}}
结尾。 {{title}}
不是一个特殊标记,它仅检索该对象的标题值。
Lets add the photo template. This template is the template for the Photo Route. Again, I suggest to see the naming conventions for how this is mapped and how the naming is done.
让我们添加照片模板。 此模板是“照片路线”的模板。 同样,我建议查看有关如何映射以及如何完成命名的命名约定 。
<script type="text/x-handlebars" data-template-name="photo">
<div style="text-align: center;">
<h4>{{title}}</h4><br>
<img {{bind-attr src="fullUrl" alt="title"}}><br>
<span>Author: {{#link-to 'user' user_id}}{{author.name}}{{/link-to}}</span>
</div>
</script>
By using the {{attribute-here}}
tag, the selected attributes will be generated inside this tag. We have used it inside an <img>
tag. Using {{title}}
inside a tag as an attribute causes problems. Handlebars and Ember generate some extra objects inside the DOM. To solve this problem, we use {{bind-attr}}
instead. When we make a link to the user route, we pass a parameter: the user_id
. By clicking the link, the URL will be updated with example.com/user/the_id
. But we don’t have a user template yet. Let’s create one.
通过使用{{attribute-here}}
标签,所选属性将在此标签内生成。 我们在<img>
标签中使用了它。 在标签内使用{{title}}
作为属性会引起问题。 把手和Ember在DOM内生成一些额外的对象。 为了解决这个问题,我们改用{{bind-attr}}
。 当我们链接到用户路线时,我们传递一个参数: user_id
。 通过单击链接,URL将使用example.com/user/the_id
进行更新。 但是我们还没有用户模板。 让我们创建一个。
<script type="text/x-handlebars" data-template-name="user">
<h2>Hello: {{fullname}} </h2>
</script>
This displays only the full name. fullname
is a property of our App.User
that extends DS.Model
.
这仅显示全名。 fullname
是我们的财产App.User
扩展DS.Model
。
Before wrapping it all up, I made a gif of how it looks:
在将所有内容打包之前,我对它的外观进行了gif处理:
结语 (Wrapping up)
As you can see, this is not a completed project yet. A lot of work is still needed; go ahead and experiment with it, learn from it and change it. The full project will be hosted on my Github account and will be updated frequently. Any contribution is welcome, I’d love to work together.
如您所见,这尚未完成。 仍然需要大量工作。 继续尝试它,从中学习并改变它。 完整的项目将托管在我的Github帐户上 ,并将经常更新。 欢迎任何贡献,我很乐意共同努力。
In this series we learned a lot – I learned a lot too. We saw how to work with the cloud, learned about its good sides and bad sides. We saw how we could develop an application in both environments and how to configure Laravel for different environments. We saw how to build a REST API with Laravel by staying on the same page of an application with Ember. I hope you all had as much fun as I have.
在本系列中,我们学到了很多东西-我也学到了很多东西。 我们了解了如何使用云,了解了云的优缺点。 我们看到了如何在两种环境中开发应用程序,以及如何为不同的环境配置Laravel。 我们看到了如何通过与Ember保持在应用程序的同一页面上来使用Laravel构建REST API。 希望大家都和我一样开心。
What do you think? Do you want to see more on Heroku, Laravel or Ember? Leave a comment below, it’s always good to hear feedback from the readers!
你怎么看? 您想在Heroku,Laravel或Ember上看到更多吗? 在下面发表评论,总是很高兴听到读者的反馈!
翻译自: https://www.sitepoint.com/single-page-app-laravel-emberjs/
emberjs