How to carry some data between page using model in Ember? - ember.js

I am trying to carry some data by updating the ( adding ) some properties to existing model. But it's not carried to next page. so i tried like this:
combineArray:Ember.computed(function(){
let trans = Ember.A();
let index = 0;
var that = this;
this.get('model.ccList').map(function(card,num){
let name = card.get('cardName');
let numb = card.get('cardNum');
card.get('cardtransactions').map(function(transaction){
console.log( 'transaction', JSON.stringify(transaction) )
let temp = {};
temp = JSON.parse(JSON.stringify( transaction ));
temp.cardName = name;
temp.cardNum = numb;
temp.selected = false;
temp.handlingFee = that.setHandlingFee( transaction.get('localCurrencyAmount') );
trans.push( Ember.Object.create().setProperties(temp) );
})
});
this.model.set('processedTrans', trans );
console.log( this.model.get('processedTrans').get('firstObject'));
return this.model.get('processedTrans');
}),
Using the above approach I am finding that, some of data's are missing. so what is the correct way to carry some data between page?
Using service not sets for me. because I have no.of pages. I am looking to update a model with required datas.

I would recommend that you begin thinking in terms of route rather than page. Ember Routes are a hierarchy, so you would have parent routes and child routes.
As an example, consider the following in your router configuration:
this.route('post', {
path: '/post/:post_id'
}, function() {
this.route('edit');
});
In this case, there is a parent (post) and a child (post.edit).
In your Route for post, you would have:
export default Route.extend({
model(params) {
return this.store.findRecord('post', params.post_id);
}
});
For the Route for post.edit, you would have:
export default Route.extend({
model(params) {
return this.modelFor('post');
}
});
So here, the child and the parent are using the same model. If you need additional stuff in your child route, you can do that in the model hook (again, this is the child route):
export default Route.extend({
model(params) {
let post= this.modelFor('post');
return post.get('someOtherProperty');
}
});
In this case, the child's model will be the value of the parent's model's someOtherProperty attribute.
Hope this helps you think about your problem in a different way.

Related

Ember return length of a model created today

I am trying to do this: I have a model called 'trip', and inside trip, an attribute called 'createdToday', which returns the date when a trip is created. What I want is to return a list of trips that were made today.
Here is my trip model:
import DS from 'ember-data';
export default DS.Model.extend({
driver: DS.belongsTo('driver', {
async: true,
inverse: 'trip'
}),
..... etc .......
createdAt: DS.attr('string', {
defaultValue() {
return new Date();
}
}),
isBookedToday: function(trip) {
var today = new Date().toDateString();
return (today === trip.get('createdAt').toDateString);
},
getTripsToday: Ember.computed('trip.#each.createdAt', function() {
var tripsToday = this.get('trip');
return tripsToday.filterBy('isBookedToday', true).get('length');
})
});
In my isBookedToday, I'm trying to see if an individual trip's created time is the same as todays time, and in getTripsToday, I am trying to loop through all the trips and filtering by isBookedToday.
And in my .hbs file, I'm saying: {{trips.getTripsToday}}, which won't render anything, so something's wrong.
I guess I am most confused at Ember's #each and exactly how it works.
Thanks for any feedback.
First you have to understand that your Trip Model instances represents a single Trip! Its absolutely not the right place to put a function that gives you a filtered list of trips!
Next isBookedToday is a normal function not a Computed Property. So you can't filterBy on it.
You may want to implement a isBookedToday on your trip, but you definitely have to filter your trips on the same place where you fetch them! Probably in a model() hook or a Computed Property on a component or a controller.
So you could do but don't need to do in your models/trip.js:
...
isBookedToday: Ember.computed('createdAt', {
get() {
let now = new Date();
let created = get(this, 'createdAt');
return now.getFullYear() === created.getFullYear() &&
now.getMonth() === created.getMonth() &&
now.getDate() === created.getDate();
}
})
...
And then in your model hook:
model() {
return this.store.findAll('trip').then(trips => trips.filterBy('isBookedToday'));
}
Or in a Computed Property in a controller or a component:
tripsToday: Ember.computed('trips.#each.isBookedToday', {
return get(this, 'trips').filterBy('isBookedToday');
})
Be careful. This will result in confusing things if you leave the page open overnight! when your date changes the Computed Properties will not recompute automatically!

How to avoid too many empty records?

Ember : 1.5.0-beta.2
Ember Data : 1.0.0-beta.7
I have the following router:
App.Router.map(function() {
this.resource('posts', function() {
this.route('new');
});
});
My PostsNewRoute creates a new record in the model hook:
App.PostsNewRoute = Ember.Route.extend({
model: function() {
return this.store.createRecord('post');
}
});
Since I don't want transient record to be visible, I filter them out in my PostsRoute:
App.PostsRoute = Ember.Route.extend({
model: function() {
this.store.find('post');
return this.store.filter('post', function(post) {
return !post.get('isNew');
});
}
});
This works as expected, but every transition to posts.new add a new record to the store, which is something I would like to avoid. So, instead of calling createRecord every time the model hook is called, I filter the store for an empty record and return this if there is one found:
App.PostsNewRoute = Ember.Route.extend({
model: function() {
var route = this;
return this.store.filter('post', function(post) {
return post.get('isNew');
}).then(function(result) {
return result.get('firstObject') || route.store.createRecord('post');
);
});
This gives me at the most one empty record.
My question: is there a better way to avoid my store being populated with (many) empty records ?
UPDATE:
Instead of filtering on the isNew attribute, I can probably use currentModel:
model: function() {
this.get('currentModel') || this.store.createRecord('post');
};
You can use this addon https://github.com/dockyard/ember-data-route to clean up when you leave a /new route. It hooks into the willTransition action hook that gets called on the route whenever a transition occurs.
The source code is a short read: https://github.com/dockyard/ember-data-route/blob/master/addon/mixins/data-route.js.
The alternative would be to not create a new record in the model hook, but according to a comment of yours it doesn't seem to be an option.

Custom Dynamic Segment (NOT ID) - EmberJS

I want to have a dynamic segment path in Ember without using the :id attribute
As per the Ember Guides, I'm using the serialize method to achieve this.
Heres my Router:
App.Router.map(function() {
this.resource("orders", function(){
this.resource('order', { path: ':order_sequence'}, function(){
this.route('edit');
})
});
});
And my Route:
var OrderRoute = Ember.Route.extend({
model: function(params) {
return this.store.find('order', params.order_sequence)
},
serialize: function(model) {
return { order_sequence: model.get('sequence') };
}
});
module.exports = OrderRoute;
However, my URL's still behave using the id attribute in the path instead of the sequence attribute..
Any ideas?
Is your browser caching something, because that's correct. Are you passing in the id instead of the sequence/model in any of your transitionTo/transitionToRoute/link-to?
Oh, you aren't talking about the slug in the url, nor the route, you are talking about the id of your model. You need to create a serializer for that particular model and override the primary key
App.OrderSerializer = DS.RESTSerializer.extend({
primaryKey: 'sequence'
});
The Fixture Adapter has a constraint on defining the id, but you can lazily get around it by extending the fixture adapter and overriding a single method
App.OrderAdapter = DS.FixtureAdapter.extend({
fixturesForType: function(type) {
if (type.FIXTURES) {
var fixtures = Ember.A(type.FIXTURES);
return fixtures.map(function(fixture){
// aka we massasge the data a bit here so the fixture adapter won't whine so much
fixture.id = fixture.sequence;
var fixtureIdType = typeof fixture.id;
if(fixtureIdType !== "number" && fixtureIdType !== "string"){
throw new Error(fmt('the id property must be defined as a number or string for fixture %#', [fixture]));
}
fixture.id = fixture.id + '';
return fixture;
});
}
return null;
},
});

Set controllers content without model hook

I'm running RC-3 and want to setup the content of an arraycontroller without the model hook. This is because I need to add some filtering and don't want to reload the content with every transition.
I found that this.get('content') is sometimes undefined. I'm not sure why this is. Here's the code:
App.StockRoute = Em.Route.extend({
setupController: function(controller) {
if (controller.get('content') === undefined) {
controller.set('content', App.Stock.find());
}
}
});
What is the equivalent code in the setupController for the model hook?
Update
I've included this as a fuller description.
I took the ember guide of the todo app, and built off that. Currently I'm building a screen to mangage/view stock levels. What I'm trying to do is have a screen on which I can toggle all/specials/outofstock items (as per the todo, each has its own route), but then on the screen I need to filter the list eg by name or by tag. To add a challenge, I display the number of items (all, on special and out of stock) on the screen all the time, based on the filter (think name or tag) but not on the toggle (think all/on special/ out of stock)
Since its essentially one screen, I've done the following in the route code
App.StockIndexRoute = Em.Route.extend({
model: function() {
return App.Stock.find();
},
setupController: function(controller) {
// if (controller.get('content') === undefined) {
// controller.set('content', App.Stock.find());
// }
// sync category filter from object outside controller (to match the 3 controllers)
if (controller.get('category') != App.StockFilter.get('category')) {
controller.set('category', App.StockFilter.get('category'));
controller.set('categoryFilter', App.StockFilter.get('category'));
}
// a hack so that I can have the relevant toggle filter in the controller
if (controller.toString().indexOf('StockIndexController') > 0) {
controller.set('toggleFilter', function(stock) { return true; });
}
}
});
App.StockSpecialsRoute = App.StockIndexRoute.extend({
setupController: function(controller) {
this._super(controller);
controller.set('toggleFilter', function(stock) {
if (stock.get('onSpecial')) { return true; }
});
}
});
App.StockOutofstockRoute = App.StockIndexRoute.extend({
setupController: function(controller) {
this._super(controller);
controller.set('toggleFilter', function(stock) {
if (stock.get('quantity') === 0) { return true; }
});
}
});
You'll see that the only difference in the routes is the definition of the toggle filter, which needs to be applied to the model (since stock is different to stock/special or to stock/outofstock)
I haven't yet figured out how to link one controller to multiple routes, so I have the following on the controller side
App.StockIndexController = Em.ArrayController.extend({
categoryFilter: undefined,
specialCount: function() {
return this.get('content').filterProperty('onSpecial', true).get('length');
}.property('#each.onSpecial'),
outofstockCount: function() {
return this.get('content').filterProperty('quantity', 0).get('length');
}.property('#each.quantity'),
totalCount: function() {
return this.get('content').get('length');
}.property('#each'),
// this is a content proxy which holds the items displayed. We need this, since the
// numbering calculated above is based on all filtered tiems before toggles are added
items: function() {
Em.debug("Updating items based on toggled state");
var items = this.get('content');
if (this.get('toggleFilter') !== undefined) {
items = this.get('content').filter(this.get('toggleFilter'));
}
return items;
}.property('toggleFilter', '#each'),
updateContent: function() {
Em.debug("Updating content based on category filter");
if (this.get('content').get('length') < 1) {
return;
}
//TODO add filter
this.set('content', content);
// wrap this in a then to make sure data is loaded
Em.debug("Got all categories, lets filter the items");
}.observes('categoryFilter'),
setCategoryFilter: function() {
this.set('categoryFilter', this.get('category'));
App.StockFilter.set('category', this.get('category'));
}
});
// notice both these controllers inherit the above controller exactly
App.StockSpecialsController = App.StockIndexController.extend({});
App.StockOutofstockController = App.StockIndexController.extend({});
There you have it. Its rather complicated, perhaps because I'm not exactly sure how to do this properly in ember. The fact that I have one url based toggle and a filter that works across those 3 routes is, I think, the part that makes this quite compicated.
Thoughts anybody?
Have you tried to seed your filter with some data?
App.Stock.filter { page: 1 }, (data) -> data
That should grab the materialized models from the store, and prevent making any more calls to the server.

Can a nested ember.js route use a different model and still retain controller context?

I have a basic person object
PersonApp.Person = DS.Model.extend({
username: DS.attr('string')
});
I have a route to find all people
PersonApp.Router.map(function(match) {
this.resource("person", { path: "/" }, function() {
this.route("page", { path: "/page/:page_id" });
this.route("search", { path: "/search/:page_term" });
});
});
In my route I'm looking at the params coming in
PersonApp.PersonRoute = Ember.Route.extend({
selectedPage: 1,
filterBy: '',
model: function(params) {
if (get(params, 'page_id') !== undefined) {
this.selectedPage = get(params, 'page_id');
} else {
this.selectedPage = 1;
}
if (get(params, 'page_term') !== undefined) {
this.filterBy = get(params, 'page_term');
} else {
this.filterBy = '';
}
console.log(this.selectedPage);
console.log(this.filterBy);
return PersonApp.Person.find();
}
});
My nested routes are using a different model (not person directly) as they contain data that isn't persisted (and really only let me flip a bit on the controller)
Yet when I manually put something on the url or click a link that does a full blown transition the "params" coming into my model hook above are always empty.
Here is the basic page model I'm using (w/ search support)
PersonApp.Page = Ember.Object.extend({
term: ''
});
When a user does a search I have a view that invokes transitionTo
PersonApp.SearchField = Ember.TextField.extend({
keyUp: function(e) {
var model = PersonApp.Page.create({term: this.get('value')});
this.get('controller.target').transitionTo('person.search', model);
}
});
Any way I can pass this "page" model to a nested view and still retain the basic "person" controller context (ie- so I can manipulate the view around this array of model objects)