ArrayController Not Updating When Deleting Records - ember.js

using ember-data 1.0.0-beta.5 and have the following routes and router
App.Router.map(function () {
this.resource('users', function () {
this.route('new');
});
this.resource('user', { path: '/user/:id' }, function () {
this.route('edit');
});
});
App.UsersIndexRoute = Ember.Route.extend({
model: function(){
return this.store.findAll('user');
},
setupController: function (controller, data) {
this._super(controller, data);
}
});
App.UserEditRoute = Ember.Route.extend({
model: function() {
return this.store.find('user', this.modelFor("user").id);
},
setupController: function (controller, data) {
this._super(controller, data);
},
actions: {
delete: function(){
var router = this;
var model = this.currentModel;
model.destroyRecord().then(function(){
router.transitionTo('users');
});
}
}
});
However when i transition back to the users route the ArrayController still has the deleted object in it. Any ideas as to why this is or how to wait until it is removed before transitioning?

kind of a work around but solves the problem.
in the UsersIndexContoller add a array to store the deleted ids
App.UsersIndexController = Ember.ArrayController.extend({
deleted: []
});
Then just append the id of the deleted model to this array and filter in the setupController method.
App.UsersEditRoute = Ember.Route.extend({
delete: function(){
var router = this;
var model = this.currentModel;
var usersController = this.controllerFor('users.index');
model.destroyRecord().then(function(){
usersController.get('deleted').push(model.id);
router.transitionTo('users');
});
}
}
});
App.UsersIndexRoute = Ember.Route.extend({
setupController: function (controller, data) {
var deleted = this.controller.get('deleted');
var filtered = data.filter(function(user){
return !deleted.contains(user.id);
});
data.set('content', filtered);
this._super(controller, data);
}
});

In your case since you want to refetch all of the users and your server lies to you about deleting the record (or it happens later), you might contemplate transitioning then deleting.
delete: function(){
var model = this.currentModel;
this.transitionTo('users').then(function(){
model.destroyRecord();
});
}

Related

How not to fire observer in controller when model is set in setupController?

I set an observer function for a model's attribute in a controller.
and It fires as soon as I enter the route for that controller.
And I know it's because of controller.set('model', model); in setupController. How can I prevent this?
I want to use observer to make another attribute changed when an attribute is changed.
But because of this behavior my logic leads to a bug.....
Route
MuteAdmin.NewRoute = Ember.Route.extend({
model: function() {
return this.store.createRecord(this.get('articleModelClassName'));
},
setupController: function(controller, model) {
controller.set('model', model);
this.store.find(this.get('categoryModelClassName')).then(function(categories) {
controller.set('categories', categories);
if (model.get('category') == null) {
model.set('category', categories.get('firstObject'));
};
}.bind(this));
},
deactivate: function() {
if(this.controller.get('isDirty')) this.controller.get('model').deleteRecord();
}
});
Controller
MuteAdmin.NewController = Ember.ObjectController.extend(MuteAdmin.Modelable, {
publicChanged: function() {
console.log('How can I prevent this from printing when entering its route?');
}.observes('public'),
actions: {
submit: function() {
var currentUser = this.get('currentUser');
var article = this.get('model');
article.set('author', currentUser);
article.save().then(function() {
this.set("flashSuccess", "Successfully Created.");
this.transitionToRoute('index');
}.bind(this), function() {
});
}
}
});
Probably not the Ember way, but when I needed to manipulate model and controller on setup I used a flag to indicate controller is setting up.
Something like this:
MyRoute = ProtectedRoute.extend({
setupController: function (controller, model) {
controller['settingController'] = true;
controller.setProperties({
'prop1Name' : val1,
'prop2Name': val2,
'propNName': valN
});
controller['settingController'] = false;
// Call _super for default behavior
this._super(controller, model);
}
});
MyController = Ember.ObjectController.extend({
anAfterChangeObserver: function() {
if(controller['settingController']){
return;
}
doSomethings();
}.observes('prop1Name')
});

Why don't nested resources in Ember.js preserve the params hash?

Given the following Ember.js application (using Ember 1.0.0.rc.6.1 and Ember Data 0.13):
App = Ember.Application.create({ LOG_TRANSITIONS: true });
App.Store = DS.Store.extend();
App.Router.map(function() {
this.resource('promotions', function() {
this.resource('promotion', { path: '/:promotion_id' }, function() {
this.resource('entrants', function() {
this.resource('entrant', { path: '/:entrant_id' });
});
});
});
});
App.PromotionRoute = Ember.Route.extend({
model: function() {
return { id: 1, name: 'My Promotion' };
}
});
App.EntrantsIndexRoute = Ember.Route.extend({
model: function(params) {
console.warn('EntrantsIndexRoute', '\nparams:', params, '\nparams.promotion_id:', params.promotion_id, '\narguments:', arguments);
console.log('params should be:', { promotion_id: 1 });
console.log('The queried URL should be:', '/entrants?promotion_id=1');
return App.Entrant.find({promotion_id: params.promotion_id});
}
});
App.Entrant = DS.Model.extend({
name: DS.attr('string')
});
If you enter the url #/promotions/1/entrants, which should be a nested resource, the params is an empty object. How can I access promotion_id there? JSFiddle here, take a look at the console after clicking on "Click me": http://jsfiddle.net/Kerrick/4GufZ/
While you can't access the dynamic segments of the parent route, you still can retrieve the model for the parent route and get its ID, like this:
App.EntrantsIndexRoute = Ember.Route.extend({
model: function() {
var promotion_id = this.modelFor('promotion').id;
return App.Entrant.find({ promotion_id: promotion_id });
}
});
Or, if there is a has-many relation between promotion and entrants, you even might do:
App.EntrantsIndexRoute = Ember.Route.extend({
model: function() {
return this.modelFor('promotion').get('entrants');
}
});
Try this code:
App.EntrantsIndexRoute = Ember.Route.extend({
model: function() {
var promotion_id = this.modelFor('promotion').query.promotion_id;
return App.Entrant.find({ promotion_id: promotion_id });
}
});

Using "needs" to createRecord in router with the need-object as property

I want to know how to create a model in the router with a property taken from the dependency given by the "needs"-function of the controller. I'm using ember-1.0.0-rc.3.
Here is how my application looks now, a little simplified:
App.LeagueAddMatchRoute = Ember.Route.extend({
model: function (params) {
var match = App.Match.createRecord({});
return match;
},
setupController: function (controller) {
controller.set('players', App.Player.find());
}
});
App.LeagueAddMatchController = Ember.ObjectController.extend({
needs: "league",
save: function () {
this.get('model').get('transaction').commit();
return this.transitionToRoute('leagues');
}
});
App.Router.map(function () {
this.resource('leagues', function () {
this.resource('league', { path: ':league_id' }, function () {
this.route('addMatch');
})
});
});
App.LeaguesRoute = Ember.Route.extend({
model: function () {
return App.League.find();
}
});
App.League = DS.Model.extend({
name: DS.attr('string'),
matches: DS.hasMany('App.Match')
});
App.Match = DS.Model.extend({
league: DS.belongsTo('App.League'),
p1: DS.belongsTo('App.Player', {inverse: 'p1matches'}),
p2: DS.belongsTo('App.Player', {inverse: 'p2matches'}),
p1Score: DS.attr('number'),
p2Score: DS.attr('number')
});
This is what I would want to accomplish:
App.LeagueAddMatchRoute = Ember.Route.extend({
model: function (params) {
var match = App.Match.createRecord({league: controller.league });
return match;
},
setupController: function (controller) {
controller.set('players', App.Player.find());
}
});
From inside a route you can access a different controller using:
this.controllerFor("theControllerIWant");
so you can do:
App.LeagueAddMatchRoute = Ember.Route.extend({
model: function (params) {
var match = App.Match.createRecord();
match.set('league', this.controllerFor("league"));
return match;
},
setupController: function (controller) {
controller.set('players', App.Player.find());
}
});
Hope it helps

Ember initializing route model with query

I am trying to initialize a Route's model with a DS query, as follows
App.Router.map(function() {
this.resource('post', { path: '/posts/:post_slug' });
});
App.PostsRoute = Ember.Route.extend({
model: function(params) {
var records = App.Post.find({ slug: params.post_slug });
return records.get('firstObject');
}
});
Here, i find a Post by its slug and set the first result as the route model. but since records is populated asynchronously, the model data is not set properly. What is the correct way to do this?
Solved this with Deferred pattern.
App.PostsRoute = Ember.Route.extend({
model: function(params) {
var records = App.Post.find({ slug: params.post_slug });
var promise = Ember.Deferred.create();
records.addObserver('isLoaded', function() {
promise.resolve(records.get('firstObject'));
});
return promise;
}
});
That should do that trick:
App.Router.map(function() {
this.resource('posts');
this.resource('post', { path: '/posts/:post_id' });
});
App.PostsRoute = Ember.Route.extend({
model: function() {
return App.Post.find();
}
});
App.PostRoute = Ember.Route.extend({
model: function(params) {
return App.Post.find(params.post_id);
}
});

How do I use dynamic segments in EmberJS' 2.2 router?

I can't figure out how to create routes with dynamic segments in the new router API for EmberJS. I've spent a week on it and tried many things but it doesn't work. I am really frustrated at myself because I've gone through the docs, API and source code many times and cannot figure out how to make this work. I am dying for assistance.
I am trying to achieve the following routes:
/profile/:userId -> index
/profile/:userId/activity -> activity page
/profile/:userId/...
My router is set up like this
App.Router.map(function() {
return this.resource("profile", function() {
this.route("index", { path: '/:userId' });
this.route("activity", { path: '/:userId/activity' });
});
});
Then, whenever I try to link with the linkTo helper, I receive the following error: Uncaught More objects were passed than dynamic segments
<li>{{#linkTo "profile.index" user}}overview{{/linkTo}}</li>
If I don't include the user object, then I receive another error Uncaught Error: assertion failed: Cannot call get with 'id' on an undefined object. (obviously because there's no object to take the ID of)
If it's any helper, here are my route declarations
App.ProfileIndexRoute = Ember.Route.extend({
model: function(params) {
return Ember.Object.create({
id: 1
});
},
setupController: function(controller, model) {
return controller.set("content", model);
}
});
App.ProfileActivityRoute = Ember.Route.extend({
model: function(params) {
return Ember.Object.create({
id: 1
});
},
setupController: function(controller, model) {
return controller.set("content", model);
}
});
JSBin example
You can structure your routes with a little bit more nesting to get the URLs you desire (and you don't need to have a return statement in your router):
App.Router.map(function() {
this.resource("profile", function() {
this.resource("userprofile", { path: '/:userId' }, function() {
this.route("index", { path: '/' });
this.route("activity", { path: '/activity' });
});
});
});
and then set up your routes like this:
App.IndexRoute = Ember.Route.extend({
model: function(params) {
return [Ember.Object.create({
id: 1
})];
}
});
App.UserprofileIndexRoute = Ember.Route.extend({
model: function(params) {
console.log("userindex route", params);
return Ember.Object.create({
id: 1
});
},
setupController: function(controller, model) {
return controller.set("content", model);
}
});
App.UserprofileActivityRoute = Ember.Route.extend({
model: function(params) {
return Ember.Object.create({
id: 1
});
},
setupController: function(controller, model) {
return controller.set("content", model);
}
});
You can link to the /profile/1 page:
{{#linkTo userprofile.index user}}
or link to the /profile/1/activity page:
{{#linkTo userprofile.activity user}}