Skip to content

Instantly share code, notes, and snippets.

@phillipkregg
Last active July 26, 2016 21:56
Show Gist options
  • Save phillipkregg/c91e98cd255a556311417ac603ab0315 to your computer and use it in GitHub Desktop.
Save phillipkregg/c91e98cd255a556311417ac603ab0315 to your computer and use it in GitHub Desktop.
Component With Service
import Ember from 'ember';
export default Ember.Component.extend({
movieService: Ember.inject.service('movie-displayer-service'),
currentSelectedMovie: '',
didInsertElement: function() {
// When the component is inserted into the DOM tree, use the model to set
// the 'currentSelectedMovie' property.
this.set('currentSelectedMovie', this.get('model').currentSelectedMovie);
},
actions: {
selectMovie: function(movie) {
// Instead of saving state in the component itself, let's
// save it in a service that can be consumed anywhere
// in the application.
this.get('movieService').setupCurrentSelectedMovie(movie);
// When the movie changes, we can override the 'currentSelectedMovie' property
// that is being populated with the
this.set('currentSelectedMovie', movie);
}
}
});
import Ember from 'ember';
export default Ember.Controller.extend({
appName: 'Component Backed by Service'
});
import Ember from 'ember';
const eq = (params) => params[0] === params[1];
export default Ember.Helper.helper(eq);
import Ember from 'ember';
import config from './config/environment';
const Router = Ember.Router.extend({
location: 'none',
rootURL: config.rootURL
});
Router.map(function() {
this.route('movies');
this.route('test-my-service-state');
this.route('third-transition');
});
export default Router;
import Ember from 'ember';
export default Ember.Route.extend({
movieService: Ember.inject.service('movie-displayer-service'),
model: function() {
return {
currentSelectedMovie: this.get('movieService').currentSelectedMovie,
movies: ['Captain America: Civil War', 'Guardians of the Galaxy', 'Ant Man']
}
},
actions: {
showServiceState: function() {
this.get('movieService').showSelectedMovie();
}
}
});
import Ember from 'ember';
export default Ember.Route.extend({
// Inject the service here to have access to this components state
movieService: Ember.inject.service('movie-displayer-service'),
renderTemplate: function() {
// My template has a different name from the route,
// so I can specify the exact template I want to render here.
this.render('my-current-service-state')
},
actions: {
checkServiceState: function() {
this.get('movieService').showSelectedMovie();
}
}
});
import Ember from 'ember';
export default Ember.Route.extend({
// Inject the service here to have access to this components state
movieService: Ember.inject.service('movie-displayer-service'),
renderTemplate: function() {
// My template has a different name from the route,
// so I can specify the exact template I want to render here.
this.render('my-current-service-state')
},
actions: {
checkServiceState: function() {
this.get('movieService').showSelectedMovie();
}
}
});
import Ember from 'ember';
export default Ember.Service.extend({
currentSelectedMovie: undefined,
setupCurrentSelectedMovie: function(movie) {
this.set('currentSelectedMovie', movie);
},
showSelectedMovie: function() {
if (this.get('currentSelectedMovie')) {
alert("The current selected movie of the movie-displayer component is: \n" + this.get('currentSelectedMovie'));
} else {
alert('Please Select a Movie First');
}
}
});
@import url(https://fonts.googleapis.com/css?family=Muli);
body {
margin: 12px 16px;
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
font-family: 'Muli';
font-size: 16px;
color: #333;
}
p {
font-size: 20px;
}
a {
padding: 5px 10px;
display: inline-block;
background: #4479BA;
color: #FFF;
font-size: 0.80em;
text-decoration: none;
}
button {
color: white;
border: none;
backgroudn: none;
border-radius: 4px;
text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);
background: rgb(28, 184, 65); /* this is a green */
height: 35px;
margin: 10px 0;
width: 100%;
font-size: 20px;
}
button:active {
background: rgb(28, 184, 55); /* this is a green */
}
.movie-list-container {
border: 1px solid #e5e5e5;
border-radius: 4px;
padding: 10px;
box-shadow: 0px 2px 3px 0px #e5e5e5;
}
.movie-list-title {
border-bottom: 1px solid #ccc;
color: #aaa;
}
.movie-list-container ul {
padding: 0;
margin: 0;
list-style-type: none;
}
.movie-list-container ul li {
padding: 10px;
margin: 10px;
background: #f5f5f5;
border: 1px solid #e5e5e5;
border-radius: 2px;
cursor: pointer;
transition: background 250ms;
}
.movie-list-container ul li.selected {
background: #4479BA;
color: white;
}
.movie-list-container ul li:active {
background: #4479BA;
color: white;
}
<h1>{{appName}}</h1>
{{#link-to 'index' }}Home{{/link-to}}
{{#link-to 'movies' }}Visit Movies{{/link-to}}
{{#link-to 'test-my-service-state' }}Check Current Service State{{/link-to}}
<br>
{{outlet}}
{{yield}}
<div class="movie-list-container">
<h4 class="movie-list-title">Movie List</h4>
<ul>
{{#each model.movies as |movie|}}
{{!-- 'eq' is a helper function that I made
to compare two values. You can check it out in
the 'helpers' folder.
--}}
<li class="{{if (eq movie currentSelectedMovie) "selected" "not-selected"}}" {{action 'selectMovie' movie}}>{{movie}}</li>
{{/each}}
</ul>
</div>
<h4>This is the applications index.hbs file - the main entry page.</h4>
<br>
<p>The movies link will take you to the 'movies' route that is being supplied with data (this could be from an ajax call). The data is then propagated down to a component called 'movie-displayer'. </p>
<p>If you select a movie from the 'movie-displayer' component, it will save the state of the 'movie-displayer' component inside the 'movie-displayer-service'</p>
<p>This way you will always have access to the components current state anywhere in the application!</p>
<h3>Here is the movies.hbs template with component added</h3>
{{movie-displayer
model=model
}}
<button {{action 'showServiceState'}}>Show Current Service State</button>
<br><br>
<strong>Fun Fact:</strong><p>That button isn't part of the component, but since the movie-displayer service has been injected into the 'movies.js' route file, I can access its state from here. </p>
<h4>This route knows nothing about the movie data...</h4>
<button {{action 'checkServiceState'}}>So let's check the service state!</button>
<br>
<br>
<br>
<p>The reason this works is because a service is a singleton that maintains its state and we injected the service into the 'test-my-service-state' route.</p>
{
"version": "0.10.1",
"EmberENV": {
"FEATURES": {}
},
"options": {
"use_pods": false,
"enable-testing": false
},
"dependencies": {
"jquery": "https://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.3/jquery.js",
"ember": "2.6.0",
"ember-data": "2.6.1",
"ember-template-compiler": "2.6.0"
},
"addons": {}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment