Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save kumkanillam/c349568e0944c6110354ec5a814c6de7 to your computer and use it in GitHub Desktop.
Save kumkanillam/c349568e0944c6110354ec5a814c6de7 to your computer and use it in GitHub Desktop.
Actions Up - Capturing State
import Ember from 'ember';
export default Ember.Component.extend({
currentlySelectedRestaurant: undefined,
actions: {
selectRestaurant: function(restaurant) {
// The 'sendAction' method is where the magic happens.
// A method called 'stateSetter' references a function
// that lives either on the controller or the route.
// This was setup when the component was instantiated in the
// fancy-restaurants.hbs file.
this.sendAction('stateSetter', restaurant);
this.set('currentlySelectedRestaurant', restaurant);
}
}
});
import Ember from 'ember';
export default Ember.Controller.extend({
appName: 'Capturing State without using a 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('fancy-restaurants');
});
export default Router;
import Ember from 'ember';
export default Ember.Route.extend({
// Properties Here
currentlySelectedRestaurant: 'Please Select a Restaurant',
model: function() {
return ['Taco Bell', 'McDonalds', 'Dennys']
},
actions: {
setupRestaurantState : function(restaurant) {
this.set('currentlySelectedRestaurant', restaurant);
},
getComponentState: function() {
alert(this.get('currentlySelectedRestaurant'));
}
}
});
import Ember from 'ember';
export default Ember.Route.extend({
});
@import url(https://fonts.googleapis.com/css?family=Poppins);
body {
margin: 12px 16px;
font-family: 'Poppins';
font-size: 16px;
color: #333;
background-color: #ffe9e9;
}
p {
font-size: 20px;
}
a {
padding: 10px 15px;
display: inline-block;
background: #000;
color: #FFF;
font-size: 1em;
text-decoration: none;
}
a.active {
background: #7a3131;
}
button {
color: white;
border: none;
background: none;
border-radius: 4px;
text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);
background: #000;
height: 70px;
margin: 10px 0;
width: 100%;
font-size: 20px;
}
button:active {
background: rgba(0, 0, 0, 0.75); /* this is a green */
}
.restaurant-list-container {
}
.restaurant-list-title {
border-bottom: 1px solid #ccc;
color: #aaa;
}
.restaurant-list-container ul {
padding: 0;
margin: 0;
list-style-type: none;
}
.restaurant-list-container ul li {
padding: 10px;
margin: 10px 0;
background: #7a3131;
border: 1px solid #000;
border-radius: 2px;
cursor: pointer;
transition: background 250ms;
color: #ffe9e9;
}
.restaurant-list-container ul li.selected {
background: #db6b6b;
color: #ffe9e9;
}
a.body-link {
display: inline;
background: none;
color: #7a3131;
font-size: 20px;
text-decoration: underline;
}
.restaurant-list-container ul li:active {
background: #db6b6b;
color: white;
}
<h1>{{appName}}</h1>
{{#link-to 'index' }}Home{{/link-to}}
{{#link-to 'fancy-restaurants' }}Fancy Restaurants{{/link-to}}
<br>
{{outlet}}
{{yield}}
<div class="restaurant-list-container">
<ul>
{{#each model as |restaurant|}}
<li class="{{if (eq currentlySelectedRestaurant restaurant ) 'selected' 'not-selected' }}" {{action 'selectRestaurant' restaurant}}>{{restaurant}}</li>
{{/each}}
</ul>
</div>
<h3>Here is the fancy-restaurants.hbs template with component added</h3>
{{!--
'stateSetter' is the name we use when calling
'sendAction' in the component. Its value will be
the name of the action that gets called on the controller
or on the route: 'setupRestaurantState'.
If 'setupRestaurantState' is not found on the controller, it
bubbles up to the route level.
--}}
{{restaurant-list
model=model
stateSetter='setupRestaurantState'
}}
<br>
<button {{action 'getComponentState'}}>Get Restaurant Component State</button>
<h3>Everything is controlled by the Route</h3>
<p>Even though the button is outside of the component, it can access the component's state because the component pushed its state back up to the router level.</p>
<p>... And the action on the button is also being propagated up to the route level with sendAction.</p>
<p>Since the route owns everything, it can be used to check the states of multiple components and/or its own template.</p>
<h4>This is the applications index.hbs file - the main entry page.</h4>
<h3>Services are great for maintaining state</h3>
<p>Since data is typically passed down at the route level, there may be times when you need to access the state of a component from a different route - like a shopping cart or session data.</p>
<p>However, since they need to be injected everywhere they are used, it creates a dependency. Having lots of services injected throughout the application may not be necessary.</p>
<h3>Do I Really Need a Service?</h3>
<p>Most of the time you will probably just need to capture state from the current route you are on and send it up to the controller or the route level for processing.</p>
<h3>Good News! It's easy.</h3>
<p>The 'fancy-restaurants' route has a component called 'restaurant-list'.</p>
<p>The file 'templates/components/restaurant-list' is listening for a click action that is passed up to it's JavaScript file in the components folder.</p>
<p>Look in 'components/restaurant-list.js' to see the actions that are called on it.</p>
<h3>this.sendAction is your friend</h3>
<p>In the component you will find a method called 'sendAction'. This is where the magic happens... it will allow you to call methods on the controller and/or the route and pass them parameters.</p>
<p>Try it out by clicking the {{#link-to 'fancy-restaurants' class="body-link"}}Fancy Restaurants{{/link-to}} link.</p>
<p></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