/danilovaz
@_danilovaz
- Um framework para criar aplicações web ambiciosas
- Criado pensando na produtividade do desenvolvedor
- Opinado e alinhado com os Padrões Web
- Convenção ao invés de configuração
- Core Team trabalhando em apps reais e robustos
It's more important to reduce the effort of maintenance than it's to reduce the effort of implementation.
Max Kanat-Alexander, Code Quality
- Manter organizado
- Modularizar o código
- Separar as responsabilidades
- Estabelecer convenções para a equipe
- Manter tudo testável
//app/models/user.js
import Ember from 'ember';
import DS from 'ember-data';
export default DS.Model.extend({
firstName: DS.attr('string'),
lastName: DS.attr('string'),
fullName: Ember.computed('firstName', 'lastName', function() {
return `${this.get('firstName')} ${this.get('lastName')}`;
})
});
- Renderiza um template
- Carrega um model e disponibiliza para o template
- Redireciona para uma nova rota
- Manipula ações que envolvem mudanças em um model
//app/router.js
Router.map(function() {
this.route('posts', { path: '/posts' });
});
//app/router.js
Router.map(function() {
this.route('posts', { path: '/posts' }, function() {
this.route('new');
});
});
Rotas
Rotas Aninhadas
//app/router.js
Router.map(function() {
this.route('posts', { path: '/posts' }, function() {
this.route('new');
this.route('post', { path: '/post/:post_id' });
});
});
//app/routes/post.js
import Ember from 'ember';
export default Ember.Route.extend({
model(params) {
return this.get('store').findRecord('post', params.post_id);
}
});
//app/templates/photos.hbs
<h1>Posts</h1>
{{#each model as |post|}}
{{#link-to 'post' post.id}}
{{post.title}}
{{/link-to}}
{{/each}}
- Template engine Handlebars
- Helpers e Built-in Helpers
- Input Helpers
- Actions
//app/templates/application.hbs
<p>Olá, <strong>{{firstName}} {{lastName}}</strong>!</p>
<p>Seja bem vindo ao Hackers House!</p>
Handlebars
Helpers
//app/helpers/sum.js
import Ember from 'ember';
export function sum(params) {
return params.reduce((a, b) => {
return a + b;
});
};
export default Ember.Helper.helper(sum);
//app/templates/application.hbs
<p>Total: {{sum 1 2 3}}</p>
Built-in Helpers
{{#if authenticated}}
<p>Bem vindo, <strong>{{user.firstName}} {{user.lastName}}</strong>!</p>
{{else}}
<p>Por favor, é necessário fazer o login para acessar essa página.</p>
{{/if}}
<ul>
{{#each users as |user|}}
<li>{{user.firstName}}!</li>
{{/each}}
</ul>
{{input type="text" value=firstName disabled=entryNotAllowed size="50"}}
{{input type="checkbox" name="isAdmin" checked=isAdmin}}
{{textarea value=description cols="80" rows="6"}}
Actions
//app/components/single-post.hbs
<p><button {{action "select" post}}>✓</button> {{post.title}}</p>
//app/components/single-post.js
import Ember from 'ember';
export default Ember.Component.extend({
actions: {
select(post) {
console.log(post.get('title'));
}
}
});
- Template engine Handlebars
- Helpers e Built-in Helpers
- Input Helpers
- Actions
- Web Components
- Reutilizáveis
//HTML renderizado
<nav class="nav-bar">
<ul>
<li><a href="/" id="ember323" class="active ember-view">Início</a></li>
<li><a href="/posts" id="ember324" class="ember-view">Posts</a></li>
</ul>
</nav>
//app/components/navigation-bar.js
import Ember from 'ember';
export default Ember.Component.extend({
classNames: ['nav-bar'],
tagName: 'nav'
});
//app/templates/components/navigation-bar.hbs
<ul>
<li>{{#link-to "home"}}Início{{/link-to}}</li>
<li>{{#link-to "post"}}Posts{{/link-to}}</li>
</ul>
+
=
//app/templates/application.hbs
{{navigation-bar}}
Só precisamos gerar um Controller se desejarmos customizar suas propriedades ou providenciar alguma action. Caso contrário, se você não gerar um, o Ember irá provindenciar uma instância de um Controller em run time.
//app/templates/blog-post.hbs
<h1>{{model.title}}</h1>
<h2>Autor: {{model.author}}</h2>
<div class='intro'>
{{model.intro}}
</div>
<hr>
{{#if isExpanded}}
<button {{action "toggleBody"}}>Ver menos</button>
<div class="body">
{{model.body}}
</div>
{{else}}
<button {{action "toggleBody"}}>Ver mais</button>
{{/if}}
//app/controllers/blog-post.js
import Ember from 'ember';
export default Ember.Controller.extend({
actions: {
toggleBody() {
this.toggleProperty('isExpanded');
}
}
});
- Arquitetura
- Definição
- Relacionamento
- CRUD
- Caching
//app/models/post.js
import DS from 'ember-data';
export default DS.Model.extend({
title: DS.attr('string'),
body: DS.attr('string'),
published: DS.attr('boolean', { defaultValue: false }),
createdAt: DS.attr('date', {
defaultValue() { return new Date(); }
})
});
//app/models/user.js
import DS from 'ember-data';
export default DS.Model.extend({
name: DS.attr('string'),
profile: DS.belongsTo('profile')
});
//app/models/profile.js
import DS from 'ember-data';
export default DS.Model.extend({
title: DS.attr('string'),
user: DS.belongsTo('user')
});
One-to-One
//app/models/post.js
import DS from 'ember-data';
export default DS.Model.extend({
title: DS.attr('string'),
body: DS.attr('string'),
published: DS.attr('boolean', { defaultValue: false }),
createdAt: DS.attr('date', {
defaultValue() { return new Date(); }
})
comments: DS.hasMany('comment')
});
//app/models/comment.js
import DS from 'ember-data';
export default DS.Model.extend({
text: DS.attr('string'),
post: DS.belongsTo('post')
});
One-to-Many
//app/models/post.js
import DS from 'ember-data';
export default DS.Model.extend({
title: DS.attr('string'),
body: DS.attr('string'),
published: DS.attr('boolean', { defaultValue: false }),
createdAt: DS.attr('date', {
defaultValue() { return new Date(); }
})
comments: DS.hasMany('comment'),
tags: DS.hasMany('tag')
});
//app/models/tag.js
import DS from 'ember-data';
export default DS.Model.extend({
title: DS.attr('string'),
post: DS.hasMany('post')
});
Many-to-Many
let post = store.createRecord('post', {
title: 'Ember.js no Hackers House',
body: 'Lorem ipsum'
});
// => chamada POST em '/posts'
post.save();
// => chamada GET em /posts
let posts = this.get('store').findAll('post');
// => chamada GET em /posts/1
let post = this.get('store').findRecord('post', 1);
Create
Read
this.get('store').findRecord('user', 1).then(function(response) {
// após o dado ter sido carregado
response.set('firstName', "Danilo Vaz");
});
// => chamada DELETE em /posts/2
store.findRecord('post', 2, { backgroundReload: false }).then(function(post) {
post.destroyRecord();
});
Update
Delete
// => Nenhuma requisição web é feita. Busca no Storage.
let posts = this.get('store').peekAll('post');
peekAll
peekRecord
// => Nenhuma requisição web é feita. Busca no Storage.
let post = this.get('store').peekRecord('post', 1);
- DS.Adapter
- DS.JSONAPIAdapter
- DS.RESTAdapter
//app/adapters/application.js
import DS from 'ember-data';
export default DS.JSONAPIAdapter.extend({
session: Ember.inject.service('session'),
host: 'https://api.meusite.com.br',
headers: Ember.computed('session.authToken', function() {
return {
'TOKEN': this.get('session.authToken'),
'OUTRO-HEADER': 'Hackers House 2017'
};
})
});
{
"data": {
"id": "1",
"type": "product",
"attributes": {
"name": "My Product",
"amount": 100,
"currency": "SEK"
}
}
}
{
"data": {
"id": "1",
"type": "product",
"attributes": {
"name": "My Product",
"cost": {
"amount": 100,
"currency": "SEK"
}
}
}
}
import DS from 'ember-data';
export default DS.JSONAPISerializer.extend({
serialize(snapshot, options) {
let json = this._super(...arguments);
json.data.attributes.cost = {
amount: json.data.attributes.amount,
currency: json.data.attributes.currency
};
delete json.data.attributes.amount;
delete json.data.attributes.currency;
return json;
},
});
- Glimmer 2
- Fastboot
- RFCS
Ember - Por que você ainda não está usando
By Danilo Vaz
Ember - Por que você ainda não está usando
Por que você ainda não está usando Ember?
- 1,025