I'm trying to change my URLs in Ember to use a property on a model (title), instead of the ID. I can get everything to work if I click on a link-to, but when I do a fresh reload of the models route, everything seems to fall apart. Within queryFixtures I can get return the desired item, and logs to the console by logging 'experiment' to the console in the model hook.
App.ExperimentRoute = Ember.Route.extend({
serialize: function(experiment, params) {
return {
experiment_title: experiment.get('urlFriendlyName')
}
},
model : function(params) {
experiment = this.get('store').find('experiment', { title: params.experiment_title });
return experiment;
}
});
My store:
App.Store = DS.Store.extend({
adapter: DS.FixtureAdapter.extend({
queryFixtures: function(fixtures, query, type) {
function urlFriendlyTitle(title) {
var ret = title.replace(/ /g,"-"); // replace spaces
// do other replacements that make sense in your case, e.g.:
ret = ret.replace(/&/g,"and");
//... and so on and so forth
// encode the remaining characters
ret = ret.toLowerCase();
ret = encodeURIComponent(ret);
return ret;
}
return fixtures.filter(function(item) {
if(urlFriendlyTitle(item.title) == query.title) {
// console.log(item);
return item;
}
});
}
})
});
UPDATE:
App.ExperimentRoute = Ember.Route.extend({
model : function(params) {
experiment = this.get('store').find('experiment', { });
console.log(Ember.inspect(experiment))
return experiment;
}
});
Running the above outputs '<DS.PromiseArray:ember325>' in the console
App.Router.map(function () {
// Add your routes here
this.resource('category', { path: '/:category_id'}, function() {
this.resource('experiment', { path: '/:experiment_title' }, function() {
this.resource('device', { path: '/:device' });
});
});
});
App.ExperimentRoute = Ember.Route.extend({
setupController: function(controller, model) {
console.log(Ember.inspect(model))
console.log(Ember.inspect(controller))
}
})
This route outputs <App.ExperimentController:ember388> <DS.AdapterPopulatedRecordArray:ember326>
Related
I have a small app which reads parameters from the URL.
Example: http://localhost:4200/flights?from=FRA&to=JFK
I'd like to offer the user a Kayak like URL like:
http://localhost:4200/flights/FRA-JFK
Can this be done with Ember without doing the mapping in the webserver?
app/controllers/flights.js
import Ember from 'ember';
export default Ember.Controller.extend({
queryParams: ['from','to'],
from: null,
to: null,
filteredFromFlights: function() {
var from = this.get('from');
var flights = this.get('model');
if (from) {
return flights.filterBy('from', from);
} else {
return flights;
}
}.property('from', 'to', 'model'),
filteredFlights: function() {
var to = this.get('to');
var flights = this.get('filteredFromFlights');
if (to) {
return flights.filterBy('to', to);
} else {
return flights;
}
}.property('from', 'to', 'model')
});
You could add nested route (say from-to), so flights route is responsible for finding flights, from-to route is responsible for local filtering flights by param.
//router
this.route('flights', function() {
this.route('from-to', {path: '/:from_to'});
});
//flights route
model: function() {
return this.store.find('flight');
}
//from-to route
model: function(params) {
var splited = params.from_to.split('-');
return {
from: splited[0],
to: splited[1],
model: this.modelFor('flights');
};
},
setupController: function(controller, models) {
controller.setProperties(models);
}
//from-to controller
filteredFlights: function() {
//...
}.property('from', 'to', 'model.[]'),
filteredFromFlights: function() {
//...
}.property('from', 'to', 'model.[]'),
I am trying to set data from two models (that has hasMany & belongsTo relationship) and save them to firebase.
'list' data ends up being saved to firebase but not user data.
I think I'm doing something wrong at step 3. I'd appreciate your help!
import Ember from 'ember';
export default Ember.Route.extend({
model: function() {
return this.store.find('list');
},
actions: {
createList: function() {
var newListTitle = this.controllerFor('lists').get('newListTitle');
var username = this.get('session.user.displayName');
alert(this.get('session.user.displayName'));
if (Ember.isBlank(newListTitle)) { return false; }
//1
var list = this.store.createRecord('list', {
title: newListTitle,
user: username,
});
//2
this.controllerFor('lists').set('newListTitle', '');
var _this = this;
//3
list.save().then(function(list) {
user.get('lists').addObject(list);
user.save();
_this.transitionTo('lists.show', list); //4
});
}
}
});
Restructured your adding logic as well as user defined models, also modified your route, which could look like this in Edit and View mode. Meaning you can have more than one item returned from "model".
// Update models
App.List = DS.Model.extend({
value: DS.attr('string')
});
App.User = DS.Model.extend({
name: DS.attr('string')
});
App.UserLists = DS.Model.extend({
user: DS.belongsTo('user'),
list: DS.belongsTo('list')
});
export default Ember.Route.extend({
LIST:SHOW ROUTE
model: function(params) {
var store = this.get('store');
var userPromise = store.find('user', params.id);
return Ember.RSVP.hash({
user: userPromise,
userList : userPromise.then(function(user) {
return store.find(userList, { WhereUserIdIs : user.get('id') })
});
});
},
actions: {
createList: function() {
var self = this;
var failure = function(reason) {
// handle stuff
};
var list = this.store.createRecord('list', {
title: this.get('title'),
});
var user = this.get('user');
var usersList = store.createRecord('userList', {
'user': user,
'list': list
});
list.save().then(function(list) {
user.save().then(function() {
userList.save().then(function() {
self.transitionTo('lists.show', list.get('id'));
}, failure);
}, failure);
}, failure);
}
});
I have previously discovered it is possible to extend mixins when creating a new mixin like such:
App.SomeNewMixin = Ember.Mixin.create(App.SomeOldMixin, {
someMethod: function() { return true; }
});
Now I am attempting to use two existing mixins, but it seems Mixin.create only supports 2 parameters.
App.SomeNewMixin = Ember.Mixin.create(App.SomeOldMixinOne, App.SomeOldMixinTwo, {
someMethod: function() { // No access to methods defined in SomeOldMixinOne }
});
This seems like a serious limitation of Ember Mixins. The Ember docs have little to no coverage of Ember.Mixin, so I'm not really sure how to proceed. I've tried using Ember.Mixin.apply within the init function of SomeNewMixin, also to no avail.
App.SomeNewMixin = Ember.Mixin.create({
init: function() {
this._super();
this.apply(App.SomeOldMixinOne);
this.apply(App.SomeOldMixinTwo);
}
someMethod: function() { return true; }
});
Any insight on possible solutions would be greatly appreciated!
Creating a mixin which extends multiple other mixins should work fine.
For example look at this:
var App = Ember.Application.create();
App.SomeOldMixin = Ember.Mixin.create({
someOldMethod: function() { return 'old'; },
someOldMethod2: function() { return 'old2'; }
});
App.SomeNewMixin = Ember.Mixin.create({
someNewMethod: function() { return 'new'; }
});
App.SomeNewerMixin = Ember.Mixin.create({
someNewerMethod: function() { return 'newer'; }
});
App.SomeNewestMixin = Ember.Mixin.create(App.SomeOldMixin, App.SomeNewMixin, App.SomeNewerMixin, {
someOldMethod: function() {
return this._super() + ' ' + this.someOldMethod2();
},
someNewestMethod: function() { return 'newest'; }
});
App.ApplicationController = Ember.Controller.extend(App.SomeNewestMixin, {
test: function() {
console.log(this.someOldMethod());
console.log(this.someNewMethod());
console.log(this.someNewerMethod());
console.log(this.someNewestMethod());
}.on('init')
});
In soume routes in my app error action is never triggered and I can't figure out why. On some Routes error action works fine.
This is application route:
Simitu.ApplicationRoute = Ember.Route.extend({
init: function() {
this._super();
Simitu.AuthManager = Simitu.AuthManager.create();
},
model: function() {
if (Simitu.AuthManager.get('session.user'))
return this.store.find('admin', Simitu.AuthManager.get('session.user'));
},
actions: {
error: function(reason, transition) {
if (reason.status === 401) {
Simitu.AuthManager.reset();
this.transitionTo('login');
}
}
}
});
On this route Error is never triggered:
Simitu.PlacesIndexRoute = Ember.Route.extend({
model: function() {
var self = this;
// force adapter request
this.store.find('place');
return this.store.filter('place', function(record) {
// return just places that belongs to this client / application
return record.get('client_id') === self.modelFor('client');
});
},
actions: {
createNew: function() {
var place = this.store.createRecord('place');
// tree structure in places is not implemented yet
//parent = this.store.find('place', params.place_id);
place.set('client_id', this.modelFor('client'));
// open place
this.transitionTo('place', place);
},
error: function(error, transition) {
return true;
}
}
});
And on this Route everything works just fine:
Simitu.ClientsRoute = Ember.Route.extend({
model: function() {
return this.store.find('client');
},
actions: {
error: function() {
return true;
}
}
});
Have anybody some ide why?
The error action is fired on the resource, not an individual route.
http://emberjs.jsbin.com/cayidiwa/1/edit
This is how my router looks like. Maybe it breaks because of the nesting or filter logic in models. I fixed it in beforeModel hook in routes but still have not clue what is wrong with my first solution.
Simitu.Router.map(function () {
this.resource('login');
this.resource('clients');
this.resource('client', { path: 'clients/:client_id'}, function() {
this.resource('places', function() {
this.resource('place', { path: ':place_id' });
});
this.resource('placecategories',{ path: 'places-categories' }, function() {
this.route('new');
});
});
});
I move some of auth handling logic to beforeModel hook.
Simitu.AuthRoute = Ember.Route.extend({
beforeModel: function(transition) {
if (!Simitu.AuthManager.isAutenticated()) {
this.redirectToLogin(transition);
}
},
redirectToLogin: function(transition) {
this.transitionTo('login');
},
actions: {
error: function(reason, transition) {
if (reason.status === 401) {
Simitu.AuthManager.reset();
this.redirectToLogin(transoition);
}
}
}
});
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 });
}
});