Ember deserialization breaking URL with null - javascript

I have a basic router for posts index and show action. If I navigate to a single post, it renders the page correctly and sets the URL to /#/posts/foo. But if I copy the URL and paste it into a new tab, it will load the page, but the url will change to /#/posts/null. Other than that the page is rendered properly and no errors are shown
show: Em.Route.extend({
route: "/post/:id",
serialize: function(router, context) {
return { id: context.get("id") };
},
deserialize: function(router, context) {
return App.get("store").find(App.Post, context.id);
},
connectOutlets: function(router, context) {
router.get("applicationController").connectOutlet("body", "post", context);
}
})
with a simple model
App.Post = DS.Model.extend({
id: DS.attr("string"),
title: DS.attr("string"),
content: DS.attr("string"),
image: DS.attr("string")
});
and the log looks like this
STATEMANAGER: Entering root ember.js:17420
STATEMANAGER: Sending event 'navigateAway' to state root. ember.js:17172
STATEMANAGER: Sending event 'unroutePath' to state root. ember.js:17172
STATEMANAGER: Sending event 'routePath' to state root. ember.js:17172
STATEMANAGER: Entering root.show
and a router
App.Store = DS.Store.extend({
revision: 4,
adapter: DS.RESTAdapter.create({
bulkCommit: false
})
});

Your route should be '/post/:post_id' instead of 'post/:id'. The parameter name is composed of the decapitalized model name, an underscore and the attribute name.
Doing this way you don't need serialize/deserialize method, Ember.js will do the job for you

The issue was specifying id as an attrirbute. You should never do that and let Ember Data take care of it automatically.
App.Post = DS.Model.extend({
title: DS.attr("string"),
content: DS.attr("string"),
image: DS.attr("string")
});

Related

ember js params is exists

So I need to do so that clicking on the store would stop the page with the goods of this store. When passing the store's id through the link URL changes but in the product's route model(params) the params is empty
Model name (product?)
import DS from 'ember-data';
import { empty } from '#ember/object/computed';
export default DS.Model.extend({
name: DS.attr('string'),
quantity: DS.attr('string'),
price: DS.attr('string'),
shops: DS.belongsTo('shop', {asynq: true}),
isNotValid: empty('name'),
});
Model name (shop?)
import DS from 'ember-data';
export default DS.Model.extend({
name: DS.attr('string'),
address: DS.attr('string'),
phone: DS.attr('string'),
products: DS.hasMany('product',{asynq: true}),
});
Controller name (?)
import Controller from '#ember/controller';
export default Controller.extend({
isNew: false,
actions: {
newProduct() {
this.toggleProperty('isNew');
},
cancelNewProducts() {
this.set('isNew', false);
},
addNewProduct() {
const name = this.get('name');
const quantity = this.get('quantity');
const price = this.get('price');
let shop = this.get('store').peekRecord('shop', );
let product = this.get('store').createRecord('product', { name,quantity,price });
shop.get('products').pushObject(product);
product.save().then( function() {
shop.save();
});
product.save().then( ()=> this.set('isNew',false));
},
},
});
Route name (?)
import Route from '#ember/routing/route';
export default Route.extend({
model(params) {
console.log(params.shop_id);
return this.store.query('product', {shops:params.shop_id});
},
actions: {
deleteProduct(product) {
let confirmation = confirm('Are you sure?');
if (confirmation) {
product.destroyRecord();
}
},
editProducts(product) {
console.log(id)
product.set('isEditing', true);
},
cancelProductsEdit(product) {
product.set('isEditing', false);
product.rollbackAttributes();
},
saveProducts(product) {
if (product.get('isNotValid')) {
return;
}
product.set('isEditing', false);
product.save();
},
},
});
Router
import EmberRouter from '#ember/routing/router';
import config from './config/environment';
const Router = EmberRouter.extend({
location: config.locationType,
rootURL: config.rootURL
});
Router.map(function() {
this.route('shops', function() {
this.route('new');
this.route('edit', { path: '/:shop_id/edit' });
});
this.route('products', { path: '/:shop_id/products' }); // this should be in the map, right?
}); // ?
export default Router;
My problem is that I can not make a request to the server and get the goods only from the store with the available id.But when I click on any store displays all the goods. AND i can't access params(shop_id) from shops in my controller,
I just did a pretty invasive reformatting of your program. Take note of the router. Looks like there are some mistakes in there. Also, you don't provide an id to 'peek' with. In your controller. We also don't know how those files are connected or what their names are. You should edit on top of my formatting to help clarify. {async: true} is spelled with a q in your program.
As far as your question... I'll try and reword it. The word 'store' is confusing... because of the data 'store' that we are used to talking about. I think you mean that you have a 'shop' resource and that you want to 'click' on the shop... (likely a component in an each loop) and then you say you want to 'stop' the page with the goods(products) - so... maybe you mean 'stock' or 'show' the products for that shop. This could be in the component (if only a few) - or you could shoot over to a 'detail' page for the shop - that displayed all of the products for that shop. Because you mention params and ID, I think you mean to go the detail route.
This is my best guess at your question: "I have resources for 'shop' and 'product.' I'm building a UI where shops are listed. I would like to make the shops clickable and when clicked, transition to the shop detail page - where I can list all associated products. My link-to helper(not shown here) takes in a shop ID - but the transition is not successful and the params isn't recognized. What am I doing wrong?"
For this question, you could likely create a more simplified version in an ember-twiddle to get to the bottom of things. We don't really need most of those actions to get to the source of the confusion.
It's admitedly hard to show these things / when you have a server - or a mirage server or whatever your setup is. Here's an example of the routing I would suggest - with some basic dummy data - in an embertwiddle. The data isn't real ember objects / but see the link-to and the shop detail route for what you'd likely use. Good luck!
Other notes:
ember-data uses an attribute called isNew for records - so, you may want to think of a different name for what you're doing /

Save associated record in Ember

I am a beginner in Ember and trying to implement a simple post and comment app.
I have a rails background and hence i'm using Rails API for this.
I have followed a tutorial and i'm able to save a post, fetch all its comments and delete the post. However i'm having issues in saving comment related to the post.
Following is the code for models
post.js
import DS from 'ember-data';
export default DS.Model.extend({
title: DS.attr('string'),
body: DS.attr('string'),
comments: DS.hasMany('comment')
});
comment.js
import DS from 'ember-data';
export default DS.Model.extend({
author: DS.attr('string'),
body: DS.attr('string'),
post: DS.belongsTo('post')
});
routes/post/comment/new.js
import Ember from 'ember';
export default Ember.Route.extend({
model() {
return {};
},
renderTemplate() {
this.render('post.comment.new', { into: 'application' });
},
actions: {
save() {
const post = this.modelFor('post');
const newComment = this.get('store').createRecord('comment', this.currentModel);
newComment.set('post', post);
newComment.save().then(() => {
this.transitionTo('post', post);
});
},
cancel() {
this.transitionTo('post', this.modelFor('post'));
}
}
});
router.js
import Ember from 'ember';
import config from './config/environment';
const Router = Ember.Router.extend({
location: config.locationType,
rootURL: config.rootURL
});
Router.map(function() {
this.route('posts');
this.route('post.new', { path: 'posts/new' });
this.resource('post', { path: 'posts/:post_id' }, function() {
this.route('comment.new', { path: 'comments/new' });
});
});
export default Router;
Saving the comment is where i'm facing an issue. This is really strange but while saving the comment, the params passed to the server looks like
Parameters: {"comment"=>{"author"=>"dsa", "body"=>"asd", "post"=>"9"}}
Unpermitted parameter: post
From what i understand, the parameter should be post_id and not post. If post is being passed, then it should be object. I may be wrong of course because i don't have a clear understanding in Ember yet.
On randomly fiddling with the code, i found that if i replace the relationship in comments model from
post: DS.belongsTo('post')
to
post_id: DS.belongsTo('post')
the params passed to server are
Parameters: {"comment"=>{"author"=>"fg", "body"=>"dfs", "post_id"=>nil}}
This however doesn't actually pass the post_id as its nil.
This might be absolutely wrong and not how its supposed to work but i'm clueless.
Thanks for any help.
Create comment serializer and override keyForRelationship method like below :
keyForRelationship(key/*, relationship, method*/) {
if(key === 'post') return 'post_id';
return this._super(...arguments);
}
and the post relation should be :
post: DS.belongsTo('post')

how to read model in afterModel in ember

Server returning this json
{"auths":[{"id":0,"email":"abc","password":"","logged":false}]}
In ember debugger for chrome I can see the model filled.
EMSystem.Auth = DS.Model.extend({
email: DS.attr('string'),
password: DS.attr('string'),
logged: DS.attr('boolean')
});
EMSystem.HomeRoute = Ember.Route.extend({
model: function() {
return this.store.findAll('auth');
},
afterModel: function(model) {
console.log(model.get('logged'));
//logic to change the route if user is logged
}
});
But for console.log I am getting undefined. How to access the model in after model?
findAll('type') and find('type') are synonymous and both return a collection. If you'd like to print out the logged value from each item you can use forEach/for to iterate over the collection.
afterModel: function(model) {
model.forEach(function(record){
console.log(record.get('logged'));
//logic to change the route if user is logged
});
}

Reloading ember data from server

I'm trying to reload store data from the server after transitioning to a page.
The transition i'm referring in this case, is from an index page, to a specific page by id.
here is my code:
App.Board = DS.Model.extend({
title: DS.attr('string'),
boardItems: DS.hasMany('BoardItem'),
});
App.BoardItem = DS.Model.extend({
title: DS.attr('string'),
board: DS.belongsTo('Board')
});
App.BoardIndexRoute = Ember.Route.extend({
model: function() {
return {
title: 'Boards List',
boardItems: this.store.find('board')
}
}
});
App.BoardShowRoute = Ember.Route.extend({
model: function(params) {
// this.store.reloadRecord('BoardItem'); - tried this, didn't work :(
var boardData = this.store.findById('board', params.board_id);
return boardData;
}
});
what happens is:
Index - loads a list of boards, with empty boardItems array (I don't want to load all of the data on the index)
Then clicking a link to a specific board, transitions to it, but the data is empty and no requests made to the server.
I tried various ways of reloading it, but all fails...
here is the debug info if it might help:
DEBUG: Ember : 1.5.1 ember.js:3521
DEBUG: Ember Data : 1.0.0-beta.7.f87cba88 ember.js:3521
DEBUG: Handlebars : 1.1.2 ember.js:3521
DEBUG: jQuery : 2.1.0
Thanks!
Finding Records: If you provide a number or string as the second argument to store.find(), Ember Data will attempt to retrieve a record of that with that ID. This will return a promise that fulfills with the requested record:
App.BoardShowRoute = Ember.Route.extend({
model: function(params) {
// Providing both the model name, and board identifier
// Make sure the parameter exists.
// console.debug('My board identifier is', params.board_id');
return this.store.find('board', params.board_id); // => GET /boards/:board_id
}
});

Ember.js: How to use computed property as a route

I'm pretty new to Ember.js and am building an app to pick up some Ember chops. I wanted to use a computed property in one of my models as a route but it seems something isn't working correctly. I'm using FIXTURES by the way.
What I'm trying to achieve is /peeps/john-smith instead of /peeps/1
I've got my model setup like this:
App.Peep = DS.Model.extend({
firstName: DS.attr('string'),
lastName: DS.attr('string'),
slug: function(){
this.get('firstName').toLowerCase() + '-' + this.get('lastName').toLowerCase();
}.property('firstName', 'lastName')
});
My router setup is like this:
App.Router.map(function(){
this.resource('peep', { path: '/peeps/:peep_slug'});
});
App.PeepRoute = Ember.Route.extend({
model: function(params){
return this.store.find('peep', params.peep_slug);
},
serialize: function(model){
return { peep_slug: model.get('slug') };
}
});
When I navigate to /peeps/john-smith in the browser, I get this warning in my console You made a request for a peep with id john-smith.
Is there something I'm missing?
By default it searches by id param, so you could either change the adapter to make it search by slug or try to add id as Ember.computed.alias('slug').

Categories