DESIGN IS HOW IT WORKS GOOD DESIGN IS REACTIVE GOOD DESIGN IS PLAYFUL GOOD DESIGN IS INFORMATIVE GOOD DESIGN IS INTUITIVE
“Most people make the mistake of thinking design is what it looks like. That’s not what we
think design is. It’s not just what it looks like and feels like. Design is how it works.”
DESIGN IS HOW IT WORKS GOOD DESIGN IS REACTIVE GOOD DESIGN IS PLAYFUL GOOD DESIGN IS INFORMATIVE GOOD DESIGN IS INTUITIVE
.asEventStream('click')https://gist.github.com/staltz/868e7e9bc2a7b8c1f754
export default Ember.Object.extend({ fullName: computed('firstName', 'lastName', function() { return `${get(this, 'firstName')} ${get(this, 'lastName')}`; }) });
export default function(separator, dependentKeys) { let computedFunc = computed(function() { let values = dependentKeys.map((dependentKey) => { return getWithDefault(this, dependentKey, ''); });
return values.join(separator); }); return computedFunc.property.apply(computedFunc, dependentKeys); };
DEMO http://emberjs.jsbin.com/vubaga/12/edit?js,output
import joinWith from '...';
export default Ember.Object.extend({ fullName: joinWith(' ', [ 'title', 'firstName', 'middleName', 'lastName', 'suffix' ]) });
get(this, 'fullName'); // Mr Harvey Reginald Specter Esq.
Ember.computed.{map,mapBy} Ember.computed.{filter,filterBy} Ember.computed.sort Ember.computed.intersect Ember.computed.setDiff Ember.computed.uniq Ember.computed.readTheAPIDocs
http://emberjs.com/api/#method_computed
DESIGN IS HOW IT WORKS GOOD DESIGN IS REACTIVE GOOD DESIGN IS PLAYFUL GOOD DESIGN IS INFORMATIVE GOOD DESIGN IS INTUITIVE
' /index
( /users
) route:user
model() { this.store.find('user') }
// returns Promise
GET "https://foo.com/v1/api/users"
+ /loading
, /error
resolve()
reject()
- Service
& Reddit API
' Index Route
. User Route
+ Loading Route
Fetch top posts
/ Component
Fetch user records resolve()
Get random message
Display shower thought
messages : Ember.A([]), topPeriods : [ 'day', 'week', 'month', 'year', 'all' ], topPeriod : 'day', subreddit : 'showerthoughts',
getPostsBy(subreddit, period) { let url = `//www.reddit.com/r/${subreddit}/top.json?sort=top&t=${period}`; return new RSVP.Promise((resolve, reject) => { getJSON(url) .then((res) => { let titles = res.data.children.mapBy('data.title'); resolve(titles); }).catch(/* ... */); }); }
_handleTopPeriodChange: observer('subreddit', 'topPeriod', function() { let subreddit = get(this, 'subreddit'); let topPeriod = get(this, 'topPeriod'); run.once(this, () => { this.getPostsBy(subreddit, topPeriod) .then((posts) => { set(this, 'messages', posts); }); }); }).on('init'),
export default Ember.Component.extend({ service : inject.service('shower-thoughts'), randomMsg : computedSample('service.messages'), loadingText : 'Loading', classNames : [ 'loadingMessage' ] });
export default function(dependentKey) { return computed(`${dependentKey}.@each`, () => { let items = getWithDefault(this, dependentKey, Ember.A([])); let randomItem = items[Math.floor(Math.random() * items.get('length'))];
return randomItem || ''; }).volatile().readOnly(); }
DESIGN IS HOW IT WORKS GOOD DESIGN IS REACTIVE GOOD DESIGN IS PLAYFUL GOOD DESIGN IS INFORMATIVE GOOD DESIGN IS INTUITIVE
Ember.get(this, 'flashes').success('Success!', 2000);
Ember.get(this, 'flashes').warning('...');
Ember.get(this, 'flashes').info('...');
Ember.get(this, 'flashes').danger('...');
Ember.get(this, 'flashes').addMessage('Custom message', 'myCustomType', 3000)
Ember.get(this, 'flashes').clearMessages();
SERVICE: PROPS
queue : Ember.A([]), isEmpty : computed.equal('queue.length', 0), defaultTimeout : 2000
SERVICE: PUBLIC APIsuccess(message, timeout=get(this, 'defaultTimeout')) { return this._addToQueue(message, 'success', timeout); },
info(/* ... */) { return ...; },
warning(/* ... */) { return ...; },
danger(/* ... */) { return ...; },
addMessage(message, type='default', timeout=get(this, 'defaultTimeout')) { return this._addToQueue(message, type, timeout); }
SERVICE: PRIVATE API
_addToQueue(message, type, timeout) { let flashes = get(this, 'queue'); let flash = this._newFlashMessage(this, message, type, timeout);
flashes.pushObject(flash); }
SERVICE: PRIVATE API
_newFlashMessage(service, message, type='info', timeout=get(this, 'defaultTimeout')) { Ember.assert('Must pass a valid flash service', service); Ember.assert('Must pass a valid flash message', message);
return FlashMessage.create({ type : type, message : message, timeout : timeout, flashService : service }); }
FLASH MESSAGE: PROPS
isSuccess : computed.equal('type', 'success'), isInfo : computed.equal('type', 'info'), isWarning : computed.equal('type', 'warning'), isDanger : computed.equal('type', 'danger'),
defaultTimeout : computed.alias('flashService.defaultTimeout'), queue : computed.alias('flashService.queue'), timer : null
FLASH MESSAGE: LIFECYCLE HOOK
_destroyLater() { let defaultTimeout = get(this, 'defaultTimeout'); let timeout = getWithDefault(this, 'timeout', defaultTimeout); let destroyTimer = run.later(this, '_destroyMessage', timeout);
set(this, 'timer', destroyTimer); }.on('init')
FLASH MESSAGE: PRIVATE API
_destroyMessage() { let queue = get(this, 'queue');
if (queue) { queue.removeObject(this); }
this.destroy(); }
FLASH MESSAGE: PUBLIC API & OVERRIDE
destroyMessage() { this._destroyMessage(); },
willDestroy() { this._super(); let timer = get(this, 'timer');
if (timer) { run.cancel(timer); set(this, 'timer', null); } }
import FlashMessagesService from '...';
export function initialize(_container, application) { application.register('service:flash-messages', FlashMessagesService, { singleton: true }); application.inject('controller', 'flashes', 'service:flash-messages'); application.inject('route', 'flashes', 'service:flash-messages'); }
export default { name: 'flash-messages-service', initialize: initialize };
COMPONENT: PUBLIC APIexport default Ember.Component.extend({ classNames: [ 'alert', 'flashMessage' ], classNameBindings: [ 'alertType' ],
alertType: computed('flash.type', function() { let flashType = get(this, 'flash.type');
return `alert-${flashType}`; }),
click() { let flash = get(this, 'flash');
flash.destroyMessage(); } });
{{#each flashes.queue as |flash|}} {{#flash-message flash=flash}} <h6>{{flash.type}}</h6> <p>{{flash.message}}</p> {{/flash-message}} {{/each}}
DEMOhttp://emberjs.jsbin.com/ranewo/46/edit?js,output
DESIGN IS HOW IT WORKS GOOD DESIGN IS REACTIVE GOOD DESIGN IS PLAYFUL GOOD DESIGN IS INFORMATIVE GOOD DESIGN IS INTUITIVE
7 Draggable Dropzone
8 Draggable Item
8 Draggable Item
8 Draggable Item 2 Controller
sendAction()
' Route
COMPONENT/VIEW EVENTS
http://emberjs.com/api/classes/Ember.View.html#toc_event-names
https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Drag_operations#draggableattribute
https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer#getData.28.29
export default Ember.Component.extend({ classNames : [ 'draggableDropzone' ], classNameBindings : [ 'dragClass' ], dragClass : 'deactivated', dragLeave(event) { event.preventDefault(); set(this, 'dragClass', 'deactivated'); }, dragOver(event) { event.preventDefault(); set(this, 'dragClass', 'activated'); }, drop(event) { let data = event.dataTransfer.getData('text/data'); this.sendAction('dropped', data); set(this, 'dragClass', 'deactivated'); } });
export default Ember.Component.extend({ classNames : [ 'draggableItem' ], attributeBindings : [ 'draggable' ], draggable : 'true', dragStart(event) { return event.dataTransfer.setData('text/data', get(this, 'content')); } });
<div class="selectedUsers"> {{#draggable-dropzone dropped="addUser"}} <ul class="selected-users-list"> {{#each selectedUsers as |user|}} <li>{{user.fullName}}</li> {{/each}} </ul> {{/draggable-dropzone}} </div> <div class="availableUsers"> {{#each users as |user|}} {{#draggable-item content=user.id}} <span>{{user.fullName}}</span> {{/draggable-item}} {{/each}} </div>
actions: { addUser(userId) { let selectedUsers = get(this, 'selectedUsers'); let user = get(this, 'model').findBy('id', parseInt(userId));
if (!selectedUsers.contains(user)) { return selectedUsers.pushObject(user); } } }
DEMOhttp://emberjs.jsbin.com/denep/18/edit?js,output
DESIGN IS HOW IT WORKS GOOD DESIGN IS REACTIVE GOOD DESIGN IS PLAYFUL GOOD DESIGN IS INFORMATIVE GOOD DESIGN IS INTUITIVE
DESIGN IS HOW IT WORKS GOOD DESIGN IS REACTIVE GOOD DESIGN IS PLAYFUL GOOD DESIGN IS INFORMATIVE GOOD DESIGN IS INTUITIVE
DESIGN IS HOW IT WORKS GOOD DESIGN IS REACTIVE GOOD DESIGN IS PLAYFUL GOOD DESIGN IS INFORMATIVE GOOD DESIGN IS INTUITIVE
DESIGN IS HOW IT WORKS GOOD DESIGN IS REACTIVE GOOD DESIGN IS PLAYFUL GOOD DESIGN IS INFORMATIVE GOOD DESIGN IS INTUITIVE
DESIGN IS HOW IT WORKS GOOD DESIGN IS REACTIVE GOOD DESIGN IS PLAYFUL GOOD DESIGN IS INFORMATIVE GOOD DESIGN IS INTUITIVE
Top Related