Emberjs call a method from an other object - ember.js

This might be a silly question, but I can't find out anything about it anywhere...
I create a method in one of my controller to verify if the user session is still good, and I'm using this method in almost every page of my app in my beforeModel. But the thing is that I don't want to copy/paste the code every time in every route, this will be dirty and I really don't like it.
Lets say I have this controller :
App.LoginController = Ember.ObjectController.extend({
...
isSession: function() {
var session = this;
Ember.$
.get(host + '/session', function(data) {
console.log('DEBUG: Session OK');
})
.fail(function() {
console.log('DEBUG: Session FAIL');
session.transitionToRoute('login');
});
}
});
How can I call it in this router :
App.HomeRoute = Ember.Route.extend({
beforeModel: function(transition) {
//Here
},
model: function() {
return this.store.all('login');
}
});
I've tried this this.get('loginController').isSession(); but I receive this error Error while loading route: TypeError: Cannot call method 'isSession' of undefined
Thanks for the help !
[edit]
I don't have much to show but this :
My map
App.Router.map(function() {
this.route('login', { path: '/' });
this.route('home');
this.resource('enquiries', function() {
this.route('enquiry', { path: '/:enquiry_id' }, function() {
this.route('update');
});
});
});
Most likely I only Have a LoginController and my HomeRoute. (its the beginning of the app)
I don't need to create a Route for my Login because I have an action helper in my login template and I'm redirected to my Home template after that.

You need to use controllerFor() method in order to call method on controller from router. If method is an action you need to use send() method, like this.controllerFor('login').send('isSession')
App.HomeRoute = Ember.Route.extend({
actions: {
willTransition: function(transition) {
transition.abort();
this.controllerFor('login').isSession()
}
});

If you don't need a return value from isSession you might consider making it an action on a top-level route. The router.send method in the docs has a pretty good example of how you declare actions as well as how you call them. Note that send is also a method you can call on a controller. Actions bubble up from a controller, to the parent route, and then all the way up the route hierarchy, as shown here

Related

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
});
}
}
});

Ember.js setting application property on load

I'm trying to fetch the current logged in user via my REST API and then set it as a property of the ApplicationController. This is how I'm trying to do it:
App.ApplicationController = Ember.Controller.extend({
init: function() {
this._super();
var self = this;
App.User.findCurrent().then(function(user) {
self.set('currentUser', user);
});
}
});
App.User = Ember.Object.extend({});
App.User.reopenClass({
findCurrent: function() {
return $.getJSON('/api/v1/users/current').then(
function(response) {
return response.user;
}
);
}
});
When I check the Chrome network tab, I see there's a call to the API and the JSON is returned, but when I try to access e.g. {{currentUser.name}} in my application template (or a partial of it), it doesn't return the name. No errors are given as well.
But in the application template it doesn't return it.
What am I missing?
Thanks!
Edit
When I create another controller, e.g. HelpController and visit /help, then {{currentUser.name}} does return the username:
App.HelpController = Ember.Controller.extend({
needs: ['application'],
currentUser: Ember.computed.alias('controllers.application.currentUser')
});
Edit 2
Sorry, I forgot to mention that I'm actually trying to use {{currentUser.name}} from a partial ({{partial 'sidebar'}}), but that shouldn't change anything, because that's the same scope, right?
Edit 3
I noticed something very strange. When I call {{currentUser.name}} in my application template (which is not what I want btw), then it also works in the {{partial 'sidebar'}}.
Edit 4
As per request:
DEBUG: Ember.VERSION : 1.0.0-rc.6 ember.js?body=1:361
DEBUG: Handlebars.VERSION : 1.0.0-rc.4 ember.js?body=1:361
DEBUG: jQuery.VERSION : 1.10.0
This isn't the correct place to put this logic. You can use the route hooks model and afterModel on the ApplicationRoute, to do this easily. In general in ember loading of data is done in the routes hooks. This allows the router pause while loading so by the time your controller and templates come into play, they are working with loaded data.
App.ApplicationRoute = function() {
model: function() {
return App.User.findCurrent();
},
afterModel: function(model) {
App.set('currentUser', model)
}
}

Ember.js RC1 - controller 'needs' another that does not yet exist

My routing structure:
App.ready = function() {
App.Router.map(function() {
this.resource('contacts', function() {
this.resource('contact', function() {
});
});
});
}
Now in my contactsController I respond to and add action that transitions to the contact route. I would then like to call the add method on my contactController.
I have placed the needs: ['contact'] on my ContactController but then I get this message:
<App.ContactsController:ember197> needs controller:contact but it does not exist
When I use controllerFor (which is deprecated) I also get an error:
this.controllerFor('contact').add();
So Ember.js RC1 appears to only create the controllers (and other related instances) once one actually transitions to the appropriate route.
Is there a way around this.
So Ember.js RC1 appears to only create the controllers (and other related instances) once one actually transitions to the appropriate route.
Interesting - I had thought ember generated controllers earlier but guess not.
Is there a way around this?
Workaround is to define App.ContactController manually. Something like this will work:
App = Ember.Application.create({});
App.Router.map(function() {
this.resource('contacts', function() {
this.resource('contact', function() {
});
});
});
App.ContactController = Ember.Controller.extend({
add: function() {
alert('App.ContactController.add() was called!');
}
});
App.ContactsController = Ember.Controller.extend({
needs: ['contact'],
add: function() {
this.get('controllers.contact').add();
}
});
http://jsbin.com/osapal/1/edit

How to manually invoke a route in ember.js RC1

I have the following controller and I'd like to bubble up an event using send
App.PersonController = Ember.ObjectController.extend({
page: function(page) {
var model = PersonApp.Page.create({id: page});
this.send("person.page", model); //should bubble up ...
}
});
here is my route setup
PersonApp.Router.map(function(match) {
this.resource("person", { path: "/" }, function() {
this.route("page", { path: "/page/:page_id" });
});
});
here is the simple page model (shim basically)
PersonApp.Page = Ember.Object.extend({
});
although I'm using the route "person.page" and I'm passing a valid model I get the following error (seemingly the router does not have this route?)
Uncaught Error: Nothing handled the event 'person.page'.
If it helps debug the controller / router relationship I noticed inside my controller if I dump this.get('target') ...
_debugContainerKey: "router:main"
and if I dig further ... and print this
this.get('target').get('router')
I see a router w/ my route under the currentHandlerInfos array ... not sure if I should be this deep though
... another slight update
If I do this (full blown) it seems to modify the window.location but my model/setupController hooks on the route are never hit
this.get('target').get('router').transitionTo(route, model);
I think, send is just used for events of a route. Assuming your controller would call send like this:
//in the controller
this.send("personPage", model);
// a matching Route
App.PersonRoute = Ember.Route.extend({
events : {
personPage : function(page){
// this should be called
}
}
});
For your case you need to leverage transitionTo (your access on the router property was too much, i think. The router instance of Ember.Router has again a router property. Pretty confusing :-)).
this.get("target").transitionTo("person.page", model);

Ember js save data before window unload

I want to save user progress, before user leaves a page. What is the best way to do this in Ember.js (v 1.0.0-pre.4)?
In pure JQuery it will look like:
$(window).unload(function() {
ajaxSaveUserProgress();
return true;
});
In Ember I am trying to do something like this:
Exam.TestView = Ember.View.extend({
unload: function(event){
controller.ajaxSaveUserProgress(); // call controller method
console.log('UNLOADED'+get(this, 'controller.test'));
}
});
Personally I'd put this code in the ApplicationRoute, as I believe the ApplicationRoute's setupController is only executed the once when the application is first initialised. You'll have to double-check this, but that's my understanding of it.
I've commented out the code you'll want because I've also demonstrated how the AJAX request needs to be set to synchronous, otherwise the window will close and your AJAX request won't have finished. We naturally need to wait for it to finish before the window is closed.
App.ApplicationRoute = Ember.Route.extend({
setupController: function() {
// var controller = this.controllerFor('foo');
// controller.ajaxSaveUserProgress();
jQuery(window).on('unload', function() {
jQuery.ajax({ type: 'post', async: false, url: 'foo/bar.json' });
});
}
});
Please ignore my jQuery instead of $ (Personal preference!)
Ember's got a standard way of handling this now. From the docs:
App.FormRoute = Ember.Route.extend({
actions: {
willTransition: function(transition) {
if (this.controller.get('userHasEnteredData') &&
!confirm("Are you sure you want to abandon progress?")) {
transition.abort();
} else {
// Bubble the `willTransition` action so that
// parent routes can decide whether or not to abort.
return true;
}
}
}
});