Model for application route in ember.js - javascript

I have the following code where I am trying to set the model for ApplicationRoute but it doesn't seem to work. I have a few doubts regarding the Ember code. Firstly, Can I set a model for application route? Secondly, if the model for the route has fields named count and fileName, do I need to declare these fields in the controller also. It looks like if I do so, the value in the controller takes precedence over the model value. Also can I do something like this.set('total',5) in the setupController even though total isn't defined anywhere.
App.ApplicationRoute=Ember.Route.extend({
model:function(){
console.log('model called');
return {count:3,fileName:'Doc1'};
},
setupController:function(){
console.log(this.get('model').fileName);
this.set('count',this.get('model.count')); //Do I manually need to do this?
this.set('fileName',this.get('model.fileName')); //Do I manually need to do this?
}
});
App.ApplicationController=Ember.Controller.extend({
count:0,//Is this necessary?? Can I directly set the property with declaring it like this
fileName:''
});

You can do:
App.ApplicationController=Ember.Controller.extend({
count: function(){
return this.get('model').get('count');
}.property('model.count')
});
So anytime model.count changes, the propery would get updated automatically.
And yep, you can set the model directly on the route. When you do this.set('total', 5) in the controller, you only set that property on the controller and not the model. In order to update the model, you would need to do:
var model = this.get('model');
model.set('total', 5);
Lastly, your setupController code isn't correct. Here is the sample method found on the Ember docs (located here):
App.SongRoute = Ember.Route.extend({
setupController: function(controller, song) {
controller.set('model', song);
}
});

Related

Ember route or controller expose data model as json

I am trying to work with Ember.js
Can I expose my data model as JSON through a route or controller?
I have an object like this saved in the store:
this.store.createRecord('Person', {
id: 1,
name: this.get('name'),
email: this.get('email')
});
I want to expose this data from a route or controller as JSON object. I don't want to use any view.
Is it possible to do this?
Thanks for help!
EDIT
My route is:
App.ResultRoute = Ember.Route.extend({
model: function() {
return this.store.find('person', 1);
}
});
There is '1' because I want only this record.
In this way It works and I see in the view the {{name}} and the {{email} of the Person object.
I want to see only the JSON, I tried to do how you suggest me :
App.ResultRoute = Ember.Route.extend({
afterModel: function (model) {
model.get('content').forEach(function (item) {
console.log(item.get('content'));
});
}
});
But I receive this error:
Uncaught Error: Assertion Failed: Error: More context objects were passed than there are dynamic segments for the route: error
What is my error?
The way I would do this would be, I would have an api in my model which would return a plain json object to whoever asked it. So the Person model would have a getPersonDetails method which will hide all the internal details, including the attributes and associations and whatever else, and return the state of the person object it is invoked upon.
So, for example, if you wanted to display a table of persons or something, you would do a createRecord, and just ask the newly created person object for it's details.
Start from the beginning of this guide. http://emberjs.com/guides/routing/specifying-a-routes-model/ It will show you how to specify a model for a route.
Then, read this entire guide on controllers: http://emberjs.com/guides/controllers/
In general, you would access that data from the route's model hook with:
this.store.find('person') // All records
If you wanted to access that first object as JSON, you could do:
var person_JSON = this.store.find('person').then(function (persons) {
//The persons records are now available so you can do whatever you want with them
console.log(persons.objectAt(0).get('content'));
});
You could also iterate over all records and strip out the content to produce raw json without the Ember wrapping... Just depends on what you need to really do.
Really the best place to put this would be the route's afterModel hook, though. You wouldn't be working with a promise, as Ember would have dealt with that for you:
afterModel: function (model) {
model.get('content').forEach(function (item) {
console.log(item.get('content'));
});
}
Hope that helps.
Edit: Since you have one record try this:
afterModel: function (model) {
console.log(model.get('content'));
}

Ember.js: dependencies between two controllers failing

I am trying to access one of two models in a controller that uses needs on a sibling controller. My router looks like the following:
App.Router.map(function() {
this.route('login');
this.route('mlb.lineups', {path: 'tools/mlb/lineups'})
this.resource('mlb.lineups.site', { path: 'tools/mlb/lineups/site/:site_id' });
});
The mlb.lineups route definition looks like the following:
App.MlbLineupsRoute = Ember.Route.extend({
model: function() {
var self = this;
return Ember.RSVP.hash({
sites: self.store.find('site')
})
},
setupController: function(controller, models) {
controller.set('model', models.get('sites'));
},
afterModel: function(models) {
var site = models.sites.get('firstObject');
this.transitionTo('mlb.lineups.site', site);
}
});
The reason I am using Ember.RSVP.hash({}) here is I plan on adding another model to be retrieved after I retrieve the site model.
Now in my MlbLineupsSiteController I am trying to access the sites model with the following:
App.MlbLineupsSiteController = Ember.ArrayController.extend({
needs: "mlb.lineups",
sites: Ember.computed.alias("controllers.models.sites")
});
This is the error I'm getting in my Ember console: needs must not specify dependencies with periods in their names (mlb.lineups)
What's the best way to make the sites model from the MlbLineups controller available in my MlbLineupsSiteController?
Note:
#NicholasJohn16's answer isn't valid anymore. It always gives an error that controller couldn't be found. Generally you should also never use needs property and always use Ember.inject.controller if you have to make your controllers dependent on each other. I'd also recommend using services instead of dependencies between controllers. It's easier to maintain code which contains communication between controllers through services, than controller directly accessing other controller's properties. You might not always be aware of such access, and using services gives you another layer of security.
Solution:
Tested in Ember.js 1.10.0-beta.4. Use following code in Controller to reference nested controller in needs:
needs: ['classic/about']
Then you can access it later using:
const aboutController = this.get('controllers.classic/about');
const aboutProperty = aboutController.get('customProperty');
Works as expected. Basically you need to replace dots with slashes.
It should be:
needs:" MlbLineupsSite "
Basically, the name of the controller you want to include, minus the word controller.
Everything else you posted should work.

Ember Model and Component, getting components to detect changes in models

I am confused and in a fix with regards to controllers and components detecting changes in models. According to the Ember Official Documentation --
"By default, the value returned from your model hook will be assigned to the model property of the associated controller. For example, if your App.PostsRoute returns an object from its model hook, that object will be set as the model property of the App.PostsController."
Therefore, shouldn't the controller update when the model changes in the route or, asynchronously by way of an external function?
App.IndexRoute = Ember.Route.extend({
model: function(){
App.set('localStore', this.get('store'));
App.localStore.createRecord('stats', {'name': 'cde'});
return this.store.find("stats");
}
});
App.IndexController = Ember.Controller.extend({
modelObs: function() {
// Never triggered!
console.log("CONTROLLER: model updated!");
}.property('model')
});
// Component with the controller's model property passed to it as localModel
// in the template
App.NewCompComponent = Ember.Component.extend({
localModel: null,
modelObs: function() {
console.log("COMPONENT: Model updated!");
}.property('localModel')
Here's a Jsbin that illustrates the problem - http://jsbin.com/tavis/3/edit
Is there anything I might be doing wrong? How to get a component detect a change in a passed model from the controller, and similarly how to get the controller detect a change in the route's model? Perhaps I'm missing a thing or two -- pointers are appreciated! Thanks
Computed properties aren't evaluated unless they are used. They are lazily evaluated.
Using either of those properties will cause them to be evaluated and your logs will occur.
http://jsbin.com/suheroya/1/edit
Additionally it's important to know that the model itself isn't changing, so that computed property won't be called over and over. Properties on the model are changing, and if you want the computed property to be called over and over you'll need to watch those properties.

Ember js wait for controller this.get request / rest adapter lag

I am trying to access my model's content in its respective controller but it initially returns a promise with undefined attributes, then when accessed a second or third time it returns the value.
Could it be there is a delay in retrieving data from the REST adapter?
Also trying to use '.then()' on the request in a controller does not work as I believe it for use only in the route.
App.EquipmentsController = Ember.ArrayController.extend({
getContentForMapping: function() {
console.log(this.get('model').objectAt(1).get('contractor.name'));
//returns undefined first time
}
});
What is strange is that when I access the model's properties from the template view in a loop it returns them straight away.
{{#each equipment in model}}
<p>{{equipment.contractor.name}}</p>
{{/each}}
Below is how I have set up the route. It's grabbing a list of equipment relevant to a specific site:
App.EquipmentsRoute = Ember.Route.extend({
model: function(){
//Get the model for the selected site and grab its equipment list.
return this.modelFor('site').get('equipment');
},
//Set the model we just grabbed above as the model to use in the controller
setupController: function(controller, model) {
controller.set('model', model);
}
});
Changing our API endpoint to support sideloading seems to have fixed the delay we were experiencing when making the this.get('model') request.
There is a small section in the ember guides that covers this: http://emberjs.com/guides/models/the-rest-adapter/
I think the mistake is in your App.EquipmentsRoute's setupController function. Try to set the content property, not the model hook property.
controller.set('content', model);
in
App.EquipmentsRoute = Ember.Route.extend({
[...]
setupController: function(controller, model) {
controller.set('content', model);
}
});

setupController not being called when using {{linkTo}} or transtionTo("path", model);

Is there any reason why setupController would not get called when using {{linkTo}}? I have two instances in my app where linkTo is being used, and in the second case. It doesn't work. The only difference that I can see is that in the first case linkTo is being used in a loop, and in the second it's not. Below is relevant code for the non-working one:
App.Router.map(function() {
this.resource("search", { path: "/search/:args" });
});
App.SearchCriteria = Ember.Object.extend({ });
App.SearchRoute = Ember.Route.extend({
serialize: function(model, params) {
// .. some code that converts model to a string called args
return {'args': args}
},
model: function(params) {
// convert args, which is query string-formatted, to an object
// and then make a App.SearchCriteria object out of it.
return App.SearchCriteria.create($.deparam(params.args));
},
setupController: function(controller, model) {
controller.set("searchCriteria", model);
}
});
In the search template:
{{view Ember.Checkbox checkedBinding="searchCriteria.music"}} Music
{{#linkTo search searchCriteria}}Search{{/linkTo}}
The last thing I see in the logs is:
Transitioned into 'search'
Normally, I'd see the setupController being called at some point, but it's not happening or some reason. I even tried using the {{action}} method to call a handler and then use transtionTo, but that had the same results.
UPDATE 1: Adding more details
The only difference between the working and non-working cases is that in the working case, the {{linkTo}} is being called from the same template as that of the controller and router (i.e., the linkTo is in the search template and it's invoking the SearchRoute). In the working case, the linkTo is being called on the SearchRoute but from a different template belonging to a different router).
After some Chrome debugging of Ember code, I found out that the router isn't being called is because partitioned.entered is empty. In the working case, it is non-empty.
var aborted = false;
eachHandler(partition.entered, function(handler, context) {
if (aborted) { return; }
if (handler.enter) { handler.enter(); }
setContext(handler, context);
if (handler.setup) {
if (false === handler.setup(context)) {
aborted = true;
}
}
});
UPDATE 2: Root issue found - bug?
I think I understand the root cause of why the handler isn't being triggered, and I think it's because the partitionHandlers(oldHandlers, newHandlers) method doesn't think that the model has changed, thus doesn't fire the handler.
To be specific, this is the relevant part of the view:
{{view Ember.Checkbox checkedBinding="searchCriteria.music"}} Music
{{#linkTo search searchCriteria}}Search{{/linkTo}}
Although the user checks off the checkbox (thus changing the state of searchCriteria), Ember doesn't think that searchCriteria is any different, thus doesn't do anything.
Is this a bug?
I'm not sure what your problem is, but this may help.
setupController is called every time the route is entered. But model hook may not be called every time.
See Ember guide: http://emberjs.com/guides/routing/specifying-a-routes-model/
Note: A route with a dynamic segment will only have its model hook called when it is entered via the URL. If the route is entered through a transition (e.g. when using the link-to Handlebars helper), then a model context is already provided and the hook is not executed. Routes without dynamic segments will always execute the model hook.
Genrally speaking, if you click the link generated by link-to to enter the route, Ember will not call model hook for that route. Instead it passes the model (link-to parameter) to that route.
The philosophy here is since the client already has the model context, Ember think there is no need to get it again from server (that's model hook's job).

Categories