computed.alias to model doesn't work in Ember 2.0 - ember.js

I've got a base route which loads all categories as the model like this:
import Ember from 'ember';
export default Ember.Route.extend({
// retrieve all categories as they are needed in several places
model: function() {
return this.store.findAll('category');
}
})
Then there's a sidebar (base.sidebar) which is supposed to use the model from base. The controller looks like this:
import Ember from 'ember';
export default Ember.Controller.extend({
needs: ['base'],
categories: Ember.computed.alias('controllers.base.model'),
});
However this doesn't work anymore as of Ember 2.0. categories is just empty.
Which deprecation did I miss?

The controller.needs property was deprecated in 1.13 and removed in 2.0. You can read this guide to see how to replace the functionality. For you it'll look something like this:
export default Ember.Controller.extend({
base: Ember.inject.controller(),
categories: Ember.computed.alias('base.model')
});

Related

Pass value from `route` to template

I am trying to pass a value from route to template. But I am not able to get the result. how to pass the value from route to template.
here is my try:
my route.js :
import Ember from 'ember';
export default Ember.Route.extend({
name:"SCB"
});
here is my hbs file :
<h1>My Name is : {{name}}</h1>
Live Twiddle
The template is mapped to the controller, not the route. To accomplish this, use the setupController function:
import Ember from 'ember';
export default Ember.Route.extend({
setupController(controller) {
this._super(...arguments);
controller.set('name', 'SCB');
}
});
Another solution would be to use a controller:
import Ember from 'ember';
export default Ember.Controller.extend({
name: 'SCB'
});
You need to set a variable in Controller:
export default Controller.extend({
name:"SCB"
});
And then set it in Route:
this.set('controller.name', 'newName');
And in hbs you can access it like:
{{ name }}

how to bind Application controller property in another controller ember

i have search property in ApplicationController and its linked with input field of searching.
i want to access search field of ApplicationController in ProjectController. it should be sync.
i use following code but its not working.
/ app/controllers/projects/index.js (project Controller)
import Ember from 'ember';
export default Ember.Controller.extend({
needs: ['application'],
searchBinding: 'controllers.application.search'
});
/ app/controllers/application.js (Application Controller)
import Ember from 'ember';
export default Ember.Controller.extend({
search: ''
)}
application.hbs
{{input value = search}}
Ember needs is deprecated and is now used differently.
It works like this:
applicationController: Ember.inject.controller('application'),
mySearch: Ember.computed.alias('applicationController.search')
In your hbs template -
{{mySearch}}
 is in sync with applications property "search".
You can access any controller within controller by inject it.
import Ember from 'ember';
export default Ember.Controller.extend({
applicationController: Ember.inject.controller('application'),
searchProperty: Ember.computed.alias('applicationController.search'),
)};
Managing Dependences between Ember controllers
You can access controllers properties included with needs this way :
{{controllers.neededController.property}}
In you case try :
{{input value=controllers.application.search}}
See example here : http://jsfiddle.net/6Evrq/

setupController no longer working for Ember route

I can not longer setup a route that has a hash of multiple models. What I use to do is this:
import Ember from 'ember';
export default Ember.Route.extend({
model() {
return Ember.RSVP.hash({
products: this.store.findAll('product'),
suppliers: this.store.findAll('supplier')
});
},
setupController(controller, model) {
controller.set('products', model.products);
controller.set('suppliers', model.suppliers);
}
});
When I do this I can't loop through each {{#each products}} but I still can with {{#each model.products}}
Object proxying is deprecated, so you should refer to your models with a model. prefix.
The correct way to do this would be to leave out your setupController and use the model as an object with .products and .suppliers keys on it.
You'll still have to {{#each model.products as |product|}} unless you want to alias them in your controller like this:
products: Ember.computed.alias("model.products")
I'd recommend sticking with model.products in your template though to alleviate any confusion as to where that particular data came from. Removing it would imply it's controller-related vs. model data fetched in the route's model hook.
EDIT: The above solution was done in Ember 1.13.5 and should also work in any 2.x version.

ember.js, ember-cli: Outlets not nesting properly

I'm having an issue where I'm unable to get nested outlets to appear properly in my Ember CLI app. The view tree I want is as follows:
application (list of all resources, of which client_availability is one)
- client_availabilities.index (list of client_availabilities)
-- client_availability (individual client_availability)
This is very similar to the "application > posts.index > post" hierarchy in the Ember Starter Kit. My desired behavior is for a list of client_availabilities to appear in "mainoutlet" when I navigate to client_availabilities.index, then persist when I bring up an individual client_availability in "suboutlet".
Easy, right? This is the default behavior & why we all love Ember. However, I can't seem to get it working. When I explicitly target my named suboutlet in client_availabilities.index and click on an individual client_availability, nothing shows up in either outlet:
Scenario 1: Render suboutlet inside client_availabilities
/app/template/application.hbs:
{{link-to 'Client Availabilities' 'client_availabilities'}}
{{outlet 'mainoutlet'}}
/app/template/client-availabilities/index.hbs:
{{outlet 'suboutlet'}}
/app/routes/client-availabilities/index.js:
import Ember from 'ember';
export default Ember.Route.extend({
renderTemplate: function(){
this.render({
into: "application",
outlet: "mainoutlet"
});
},
model: function() {
return this.store.find('client_availability');
}
});
/app/routes/client-availability.js:
import Ember from 'ember';
export default Ember.Route.extend({
renderTemplate: function(){
this.render('client_availability', {
into: "client_availabilities",
outlet: "suboutlet"
});
},
model: function(params) {
return this.store.find('client_availability', params.client_availability_id);
}
});
Alternately, when I target my mainoutlet in application, client_availability appears in "suboutlet" client_availabilities.index disappears from "mainoutlet":
Scenario 2: Render suboutlet inside application
/app/template/application.hbs:
{{link-to 'Client Availabilities' 'client_availabilities'}}
{{outlet 'mainoutlet'}}
{{outlet 'suboutlet'}}
/app/template/client-availabilities/index.hbs: (empty)
/app/routes/client-availabilities/index.js:
import Ember from 'ember';
export default Ember.Route.extend({
renderTemplate: function(){
this.render({
into: "application",
outlet: "mainoutlet"
});
},
model: function() {
return this.store.find('client_availability');
}
});
/app/routes/client-availability.js:
import Ember from 'ember';
export default Ember.Route.extend({
renderTemplate: function(){
this.render('client_availability', {
into: "application",
outlet: "suboutlet"
});
},
model: function(params) {
return this.store.find('client_availability', params.client_availability_id);
}
});
And here's my router, the same in both cases:
/app/router.js:
import Ember from 'ember';
var Router = Ember.Router.extend({
location: 'auto'
});
Router.map(function() {
this.resource('client_availabilities', function() {
this.resource('client_availability', { path: ':client_availability_id' });
});
});
export default Router;
I'm happy to share more code, but the application is split into several files and unfortunately not something I can post in its entirety. Can anyone see what I'm doing wrong? The rest of the app is working fine, I just can't seem to get this basic behavior to work.
Do you have an /app/templates/client-availibilities.hbs template with only {{outlet}} inside of it? Without this, the app is going to lose its place in the outlet tree. Ember-CLI and the Ember Starter Kit are very, very different from each other in structure, so I can see where the confusion comes from.
How I like to think of Ember's rendering style is that each handlebars file inside the templates folder (i.e. /templates/users.hbs) represents a change the overall state of the application from one subject to another (example: from newsfeed to users).
The corresponding subfolders inside the templates folder change the state of the subject itself.
For example:
Required Templates
Users container OR the only users page you need app-wide is at /templates/users.hbs
Optional Templates
Users Index would be at /templates/users/index.hbs
Users Show would be at /templates/users/show.hbs
Users New would be at /templates/users/new.hbs
You can have [ /templates/users.hbs ] without having [ /templates/users/*.hbs ] and still keep track of your data; however, you cannot have [ templates/users/index.hbs ] without [ /templates/users.hbs ] and still keep track of your data. Why? Imagine if you navigate to somesite.com/users. There is currently no top-level template with an outlet into which Ember can render the [ users/index.hbs ] template. The [ /templates/users.hbs ] template bridges that gap and also serves as a container for all other pages inside the /templates/users folder as well.
For example, in the terms of your app, in order to render [ /app/templates/client-availibilities/index.hbs ] when a user visits http://www.yourwebsite.com/client-availibilities, your app will need these templates defined so that ember can drill down into them.
application.hbs // and in its outlet, it will render...
--client-availibilities.hbs // and in its outlet, it will render by default...
----client-availibilities/index.hbs // then, for the client-availability (singular), you can have ember render it in
----client-availibilities/show.hbs // will render also in the client-availabilites as it is a separate state of the subject. Can also be nested inside the index route within the router so that it renders inside the index template.
As it is, I would structure your app as such...
/app/router.js
... // previous code
Router.map(function() {
this.resource('client_availabilities', function() {
this.route('show', { path: '/:client_availability_id' });
// this.route('new'); ! if needed !
// this.route('edit', { path: '/:client_availability_id/edit' ); ! if needed !
});
});
... // code
/app/templates/application.hbs
{{link-to 'Client Availabilities' 'client_availabilities'}}
{{outlet}}
/app/templates/client-availabilities.hbs
{{outlet}}
/app/templates/client-availabilities/index.hbs
<ul>
{{#each}}
{{#if available}}
<li>
{{#link-to #link-to 'client-availabilities.show' this}}
{{firstName}} {{lastName}}
{{/link-to}}
</li>
{{/if}}
{{else}} <!-- we want this to only render if the each loop returns nothing, which is why it's outside the if statement -->
<li>Nobody is available</li>
{{/each}}
</ul>
<!-- Note: you don't need to put an outlet here because you're at the end of the tree -->
/app/templates/client-availabilities/show.hbs
<!-- Everything you want to show about each availability -->>
<!-- Note: you don't need to put an outlet here because you're at the end of the tree -->
/app/routes/client-availabilities/index.js
import Ember from 'ember';
export default Ember.Route.extend({
model: function() {
return this.store.findAll('client_availability');
}
});
/app/routes/client-availabilities/show.js
import Ember from 'ember';
export default Ember.Route.extend({
model: function(params) {
return this.store.find('client-availability', params.client_availability_id);
}
});
/app/models/client-availability.js
import DS from 'ember-data';
var client-availability = DS.Model.extend({
firstName: DS.attr('string'),
lastname: DS.attr('string'),
available: DS.attr('boolean'),
available_on: DS.attr('date')
});
export default client-availability;
However, are you sure you want to structure your app by the availability of each client? Wouldn't it make more sense to structure it by each client and then just filter each client to show if they were available or not? Resources are supposed to be nouns, and routes are supposed to be adjectives. Therefore, it would be best to use a client as your model instead of their availability and have a either an isAvailable property on the model (as used in the example above) or a one-to-many association with an additional availability model if you want to show clients who have several availabilities (as shown below).
For example,
/app/models/client.js
import DS from 'ember-data';
var Client = DS.Model.extend({
firstName: DS.attr('string'),
lastName: DS.attr('string'),
availabilities: DS.hasMany('availability')
});
export default Client;
/app/models/availability.js
import DS from 'ember-data';
var Availability = DS.Model.extend({
date: DS.attr('date'),
client: DS.belongsTo('client')
});
export default Availability;
In the long run, this latter approach would set up your app to show all availabilities at once and allow the user to filter by the client, plus it would allow the user to view a client and see all their availabilities. With the original approach (the isAvailable property on the client model), the user can only get the availabilities from the client model itself, but what if the user wants to see all clients who are available on, say, March 3rd at noon? Well, without an availability model associated with the client model, you are going to have to put a lot of code into your client controller that ember would give you by default if you go down the one-to-many path.
If you need more advice on where to go from here, let me know. I'm more than happy to add more examples of the templates, controllers, and routes that you'll need in order to pull this off.

Why is Firebase data not displaying properly in my Ember CLI generated output?

I've successfully setup Ember CLI and Firebase and I'm attempting to bring some basic data into my templates. My 'title' and 'subtitle' data are apparent in the Ember Inspector, as well as my Firebase project dashboard. However, {{foo.title}} and {{foo.subtitle}} are coming back empty and undefined in the browser. Why is that? Here's my code:
application.js (adapter)
import DS from 'ember-data';
export default DS.FirebaseAdapter.extend({
firebase: new window.Firebase('https://<firebase-database-name>.firebaseio.com/')
});
foo.js (model)
import DS from 'ember-data';
export default DS.Model.extend({
title: DS.attr('string'),
subtitle: DS.attr('string')
});
index.js (controller)
import Ember from 'ember';
export default Ember.Controller.extend({
model: function() {
var titles = this.store.createRecord('foo', {
title: 'Title',
subtitle: 'Subtitle'
});
titles.save();
}
});
index.js (route)
import Ember from 'ember';
export default Ember.Route.extend({
model: function() {
return this.store.findAll('foo');
}
});
application.hbs (template)
<h2 id='title'>{{foo.title}}</h2>
{{outlet}}
index.hbs (template)
<h1>{{foo.title}}</h1>
<h3>{{foo.subtitle}}</h3>
The title and subtitle fail to display in the templates.
The Ember Inspector View Tree tab shows 'index' with 'DS.RecordArray:ember368' for the model.
The Ember Inspector Data tab shows Model Type of 'foo' with # Records of 1. When I click on that record, it displays the Firebase ID, title, and subtitle values. When I inspect my Firebase data url, I see the following structure:
firebase-database-name
|— foos
|— JU1Ay8emCNNZBeqYoda
|— subtitle: "Subtitle"
|— title: "Title"
Seems like everything is correct, but the templates do not display the data values. Thanks for any help.
The answer to this question centers on properly retrieving and exposing Ember Data, and not so much to do with Firebase or Ember CLI. There are multiple issues with the code above…
The foo.js code represents a simple model, and is written correctly.
The index.js route is implemented correctly. It is retrieving and returning the ‘foo’ model from the Ember Data store as an array, which, via EmberFire and the Firebase adapter, is ultimately being pulled from the Firebase database. However, this is part 1 of 3 problems. If you want this data displayed once across the application, dispense with the index.js route, and just define an application.js route, like this:
import Ember from 'ember';
export default Ember.Route.extend({
model: function() {
return this.store.findAll('foo');
}
}
The index.js controller has a number of issues, and is part 2 of 3 problems. Firstly, controllers do not have a ‘model’ method, they only have a ‘model’ property (Ember Routes are the ones that employ a ‘model’ method, and can also set the ‘model’ property of a controller via a Route’s ‘setupController’ method). Secondly, instead of Ember.Controller, it needs to extend Ember.ObjectController for a singular data instance, or, Ember.ArrayController for an array of data, which is the controller needed here, since ‘this.store.findAll(“foo”)’ in the index.js route is going to return an array of objects. Controllers are not used to save or retrieve data from a server, but they can be used to decorate a model. Given that the route is returning the model, the controller, in this simple data exercise, is not even necessary.
The application.hbs handlebars template is part 3 of 3 problems. It is not setup to properly display the model that is being provided to it via the route. It’s necessary to employ the {{#each}} helper, to loop over the data array that is being returned via the route’s model method. Try this:
{{!-- looping over the 'foo' model returned via the route --}}
{{#each foo in model}}
<h2>Application Title = <span style="color: blue;">{{foo.title}}</span></h2>
<h4>Application Tagline = <span style="color: blue;">{{foo.tagline}}</span></h4>
{{/each}}
{{outlet}}
The index.hbs handlebars template is not necessary. The application.hbs template is sufficient to display the data of interest.
This is a very basic exercise, but illustrates fundamental aspects of using Ember Data properly.