EmberJs using inject.controller to access parent data - ember.js

I am trying to access from a child template to its parent data
in the previous versions of emberjs this could have be done using the needs keyword:
app.RepositoriesController = Ember.Controller.extend({
needs: "user",
user : Ember.computed.alias("controllers.user");
});
from what I understand with the new ember version this should be done like the following (as the needs keywords became deprecated):
app.RepositoriesController = Ember.Controller.extend({
user: Ember.inject.controller('user')
});
but it doesn't seems to work in my html code I use the following line which is blank:
{{user.name}}
Thanks!

All you need to do is call:
user: Ember.inject.controller()
And ember is smart enough to automatically pick up the correct controller based on the property key.
http://emberjs.com/api/classes/Ember.inject.html#method_controller

I am not sure that it is the best practice but it did the job:
i added into the Route a new function :
setupController: function (controller, model) {
var user = this.modelFor('user');
controller.set('user', user);
Ember.$.getJSON(user.repos_url).then(function(res){
controller.set('model', res);
});
}

usually fetching data should go to model hook so your code above could be written as:
model: function(){
var user = this.modelFor('user');
return Ember.$.getJSON(user.repos_url).then(function(res){
return { user: user, res: res}
});
}
in controller now you can access model like
user: Ember.computed.alias('model.user'),
res: Ember.computed.alias('model.res')

Related

How to access the params in controller ember.js

This is my router.js code.
this.route('contact',{'path': '/contact/:chat_id'});
and This is my route.js code.
model(params) {
return this.store.findRecord("chat", params.chat_id)
},
and This is my controller.js code and can i use like this. It shows error as null value
please help me. How to use params in controller
recordChat: function() {
var chat = this.get(params.chat_id)
Ember.RSVP.hash({
offer_id: chat,
})
}
Edited for 2021: There's actually probably a much simpler way to do this now in Ember. See https://guides.emberjs.com/v3.27.0/routing/query-params/
Original Answer
I think the simplest answer is to create a variable in route and then set it in the setupController:
your_route.js
export default Ember.Route.extend({
model(params) {
this.set('myParam',params.my_Params);
// Do Model Stuff...
},
setupController(controller, model) {
// Call _super for default behavior
this._super(controller, model);
// Implement your custom setup after
controller.set('myParam', this.get('myParam'));
}
});
In your route.js, you need to call the setupController function like this:
setupController(controller, model) {
this._super(...arguments);
controller.set('chat', model);
}
Now you have access to it in your controller by calling:
recordChat() {
const chat = this.get('chat');
// if you don't call the setupController function, you could also do:
// const chat = this.get('model') or this.get('model.id') if you want the id only
}
UPDATE:
See working twiddle here
I think you can fetch the id you want from the model because you used the parameter chat_id to find the record and that id is now part of your chat object (which is the route model itself).
So, in your controller you just need to do: this.get('model').id

Ember-Data "TypeError: this.container is undefined"

I'm trying to load the current user into the data store but am having some difficulty. The server uses PassportJS and visiting /api/users/me returns a JSON object similar to this:
{"user":{"_id":"53a4d9c4b18d19631d766980","email":"ashtonwar#gmail.com",
"last_name":"War","first_name":"Ashton","location":"Reading, England",
"birthday":"12/24/1993","gender":"male","fb_id":"615454635195582","__v":0}}
My store is just defined by App.store = DS.Store.create();
The controller to retrieve the current user is:
App.UsersCurrentController = Ember.ObjectController.extend({
content: null,
retrieveCurrentUser: function() {
var controller = this;
Ember.$.getJSON('api/users/me', function(data) {
App.store.createRecord('user', data.user);
var currentUser = App.store.find(data.user._id);
controller.set('content', currentUser);
});
}.call()
});
It is called by my application controller:
App.ApplicationController = Ember.Controller.extend({
needs: "UsersCurrent",
user: Ember.computed.alias("controllers.UsersCurrent")
});
I suspect the line App.store.createRecord('user', data.user); is causing issues but I don't have any idea how to fix it.
The console logs TypeError: this.container is undefined while the Ember debugger shows every promise is fulfilled and the users.current controller has no content. Thankyou for any help you can provide.
Are you defining the store on the App namespace, because Ember Data doesn't do that by default. Either way, you're failing to define the type you want to find after you create the record.
var currentUser = controller.store.find('user', data.user._id);
createRecord returns the record, so there is no point in finding it afterward
var currentUser = controller.store.createRecord('user', data.user);
Also in your example, you are trying to call the function immediately on the type, and not on the instance. You should add that as a method to run on init.
App.UsersCurrentController = Ember.ObjectController.extend({
retrieveCurrentUser: function() {
console.log('hello')
var controller = this;
Ember.$.getJSON('api/users/me', function(data) {
var user = controller.store.createRecord('user', data.user);
controller.set('model', user);
});
}.on('init')
});
http://emberjs.jsbin.com/OxIDiVU/693/edit

LSAdapter store.find(type, id) tries to push a new record?

I'm trying to use LSAdapter (https://github.com/rpflorence/ember-localstorage-adapter) in my ember application. I have only one page which is called index. I use the localstorage to persist the data even when refreshing the page so there will only be one record in the LocalStorage for the index page.
When I try to bind the model to the controller via the index route, I get this error :
Assertion failed: You must include an "id" in a hash passed to "push"
However, if there is a record in the localstorage, everything works fine.
Here is my IndexRoute :
PC.IndexRoute = Em.Route.extend({
model: function(){
var modelId = this.get('store').modelFor(this.routeName);
return this.get('store').find(this.routeName, modelId);
},
setupController: function(controller, model) {
controller.set('model', model);
}
});
How do I get rid of this error ?
Do I need to manually check in the LocalStorage without using the LSAdapter ? But that would defeat the purpose of the adapter.
I ran into this issue and ended up patching the adapter (https://github.com/musicist288/ember-localstorage-adapter/commit/60313970d6591be51cd29c6137367721465294fc). In my application I needed a find or create behavior so I ended up with the following:
App.Route = Em.Route.extend({
model: function (params) {
var store = this.get('store');
return new Ember.RSVP.Promise(function (resolve, reject) {
store.find("school", params.school_id).then(function (model) {
resolve(model);
}).catch(function () {
resolve(store.push("school", App.SchoolFixtures.findBy('id', params.school_id)));
});
});
}
});
Not sure if this is the best solution, but it works for now.
This fix has been merged in the main branch of LSAdapter.
https://github.com/rpflorence/ember-localstorage-adapter/pull/66
It now works out of the box from the official repo at https://github.com/rpflorence/ember-localstorage-adapter

How to Add Child Record to Existing Parent Record?

I've been googling and scouring Stack Overflow for some sort of hint on this subject but the information is scattered at best.
I'm trying to Create a new Child Record (Comment) and save it to an existing Parent Record (Post). I am using Ember-Model, rather than Ember-Data, but any tips or pointers would be greatly appreciated.
At the moment, I've been successful creating a new, embedded Comment but only when it is created with a new Post record. So:
How do I go about loading/retrieving the currently loaded Post(parent record) in order to apply Comments (child records) to it?
I've been reading up on controller dependencies, using needs: and this.controllerFor and this.modelFor in order to have access to another controller/model's content but have been unable to wire these things together into something meaningful.
Anyway, here is what I've whittled my application code down to, in the hopes I might be able to stumble into the proper way of doing this...
Routes
App.Router.map(function() {
this.resource('post', { path: '/:post_id' }, function() {
this.resource('comments', { path: '/comments'} );
});
});
I removed all the other resources & routes, so I'm left with App.Post, App.PostIndex, and App.Comments. I think my routes are the issue here, I assume I'm not properly implementing the methods to use the loaded Post record in my Comments route.
App.IndexRoute = Ember.Route.extend({
model: function() {
return App.Post.find();
},
setupController: function(controller, model) { // I'm not certain if this
controller.set('content', model); // setupController is needed?
}
});
App.PostRoute = Ember.Route.extend({
model: function(params) {
return App.Post.find(params.post_id);
},
setupcontroller: function( controller, model) { // again, unsure if this
this.controllerFor('post').get('comments'); // is correct.
controller.set('content', comments);
}
});
App.CommentsRoute = Ember.Route.extend({
afterModel: function() {
this.set('post', this.modelFor('post'));
},
setupcontroller: function( controller, model) {
this.controllerFor('post').get('comments');
controller.set('content', comments);
}
});
Controller
App.CommentsController = Ember.ArrayController.extend({
needs: "post",
actions: {
addComment: function() {
var post = App.Post.create({
title: 'static post title'
});
post.get('comments').create({
message: 'static message'
});
post.save();
}
}
});
This is my current Comments Controller, which can create a new Post with an embedded Comment. I've found and been given numerous examples in which to create the Comment, but none seem to work for me. Basically, I'm struggling with defining the var post = ... as the currently loaded record. I've implemented various approaches in an attempt at trial & error. Thus far I have attempted:
var post = App.Post.create();, returns property undefined, as this would create a new record. However, I gave it a shot as every example i saw related to this defined their record as such.
var post = this.get('post');, returns a cannot call 'get' on undefined. I've tried using this method of defining my current post on both the Comments controller and Post controller.
var post = this.get('controllers.post.content);, returns a 'cyclic error' from the backend I'm using.
var post = App.Post.find();, returns a cannot call 'get' on undefined.
var post = App.Post.find(1);, Again, returns a cannot call 'get' on undefined. Figured I'd give it a shot because this is one of those recurring examples people provide. The backend I use applies its own ID to each record, and I'm unsure if I would be able to/how to have the .find() method use a dynamic ID value and retrieve only the model I just loaded.
I'm guessing that I'm not properly setting up my Routes and Controller dependencies?
If anyone has a suggestion, relevant link, or fix I would be very grateful.
This one (seemingly simple) issue/use case has me at wit's end at this point.
Try this (works pre beta 2):
App.CommentsController = Ember.ArrayController.extend({
actions: {
addComment: function() {
this.content.createRecord({
message: 'static message'
});
}
}
});
Ember Data Beta 2 and later:
App.CommentsController = Ember.ArrayController.extend({
needs: ["post"],
actions: {
addComment: function() {
var post = this.get('controllers.post');
var comment = this.get('store').createRecord('comment', {
message: 'static message',
post: post
});
comment.save().then(function() {
post.addObject(comment);
// You may or may not need to save your post, too. In my case my backend handles
// the inverses of relationships (if existing), so there's no need. We still need
// to do this for Ember, though
});
}
}
});

Error retrieving a different model inside a route's setupController

EDIT: I think I have found a solution. As I say in my question, the variable profiles is a promise so I've tried the following and it works:
...
setupController: function(controller, model) {
controller.set('model', model);
var profiles = App.Profile.findAllByMaster(model.get('id'));
profiles.then(function(data) {
controller.set('profiles', data);
});
}
...
END EDIT
I'm having the error: Assertion failed: an Ember.CollectionView's content must implement Ember.Array. You passed [object Object] when I try to get data from another model in the setupController hook.
The route is MastersMaster which associated model is Master and I try to get the Profiles models that belong to the current Master.
I'm not using Ember Data or something similar. It's just pure jQuery with $.ajax calls.
It's difficult to explain so here is the code excerpt:
App.MastersMasterRoute = Ember.Route.extend({
model: function(params) {
return App.Master.find(params.master_id);
},
setupController: function(controller, model) {
controller.set('model', model);
// if I comment these two lines it works but I don't get the profiles (obviously)
var profiles = App.Profile.findAllByMaster(model.get('id'));
controller.set('profiles', profiles);
}
});
App.Profile = Ember.Object.extend({
id: null,
name: '',
master_id: null
});
App.Profile.reopenClass({
findAllByMaster: function(master_id) {
var profiles = Ember.A();
return $.ajax({
url: 'ajax/get.profiles.php',
type: 'GET',
dataType: 'json',
data: { master_id: master_id }
}).then(function(response) {
$.each(response, function(i, item) {
profiles.pushObject(App.Profile.create(item));
});
return profiles;
});
}
});
If I console.log the variable profiles before doing the controller.set I see that it's a promise and not the array of Profile objects expected. I suppose I have to resolve the promise before but I don't have any idea.
P.S.: sorry my english :(
As I've said in the edit, the problem was that the findAllByMaster method returns a promise so it has to be resolved before assigning it to the controller's property.
I suppose there is a more elegant or efficient way of solving it so another solutions are welcome.