Query-params-new nested routes strange error - ember.js

In an application I use the latest canary versions for Ember and Ember Data. I have the following router:
this.resource('articles', {path: '/articles'}, function() {
this.resource('article', {path: '/:article_id'});
});
In the ArticlesController I specify some queryParams:
queryParams: ['category', 'search'],
category: '1', // defaults to 1
searchTerm: "",
In my ArticlesRoute I specify a model refresh and the model:
queryParams: {
category: {
refreshModel: true
}
},
model: function(params) {
// here I do use the params to return articles based on category and/or searchTerm
}
So far so good, all code above works perfect. However when I do a this.transitionTo('article', articleObject) or this.transitionToRoute('article', articleObject) in my application I get the following error:
Error: You didn't provide enough string/numeric parameters to satisfy all of the dynamic segments for route article
at Object.__exports__.default.subclass.createParamHandlerInfo (http://localhost:8000/vendor/ember/index.js:44242:21)
at Object.__exports__.default.subclass.applyToHandlers (http://localhost:8000/vendor/ember/index.js:44121:37)
at Object.__exports__.default.subclass.applyToState (http://localhost:8000/vendor/ember/index.js:44088:21)
at Object.Router.transitionByIntent (http://localhost:8000/vendor/ember/index.js:43312:33)
at Object.Router.refresh (http://localhost:8000/vendor/ember/index.js:43459:21)
at EmberObject.extend.refresh (http://localhost:8000/vendor/ember/index.js:22616:35)
at EmberObject.extend._actions.queryParamsDidChange (http://localhost:8000/vendor/ember/index.js:22328:22)
at Object.triggerEvent (http://localhost:8000/vendor/ember/index.js:24563:38)
at trigger (http://localhost:8000/vendor/ember/index.js:44812:16)
at fireQueryParamDidChange (http://localhost:8000/vendor/ember/index.js:43612:9) index.js:14220
Uncaught Error: Assertion Failed: Error: You didn't provide enough string/numeric parameters to satisfy all of the dynamic segments for route article index.js:3658
This strange error only happens when I first clicked a Category so the queryParam category is changed, and then fire a transitionTo to an article.
I have tried to use the debugger; statement to get the source of the error. However it seems that is an event that calls this error. When searching the sourcecode I found that the error originates from line 44242 of ember.js.
Does anyone know why this error happen after I have transitioned to a non query-params-new route?
Edit: now in Github too: https://github.com/emberjs/ember.js/issues/5070 (comment on Github)
JSBin: http://emberjs.jsbin.com/yiquyupa

I ran into almost the same issue in an afterModel callback where the parent route/controller has queryParams.
I found that if you just pass the queryParams from the transition argument (not the queryParams argument which is null/undefined) into Route.transitionTo / Route.replaceWith then the transition completes.
Example:
afterModel: function(model, transition, queryParams) {
// FIXME: unresolved Ember issue https://github.com/emberjs/ember.js/issues/5070
this.replaceWith('another.route', model, { queryParams: transition.queryParams});
}
I don't know why this happens, but queryParams is still a relatively new feature and still has some rough edges.

Related

Routing error with ember-data 2.0 and emberjs 2.0.1

Cross-posting from discuss.ember. I am using Ember 2.0.1 with Ember-data 2.0 and default the default RESTSerializer generated by ember-cli. I know this question has been asked to many places before (which none have real answers) but no solutions have been working for me yet.
I have this model hook for a user model :
export default Ember.Route.extend({
model() {
return this.store.findAll('user');
}
});
Router is the following :
Router.map(function() {
this.route('users', { path: '/' }, function() {
this.route('user', { path: '/:user_id' }, function(){
this.route('conversations', { path: '/'}, function(){
this.route('conversation', { path: '/:conversation_id' });
});
});
});
});
For example, going to /conversations/4 transitions to users.user.conversations. My relations are defined in my models. In the user model I have a DS.hasMany('conversation') conversations attribute set with { embedded: 'always' }. Returned JSON looks like this :
{"conversations":[
{
"id":183,
"status":"opened",
"readStatus":"read",
"timeAgoElement":"2015-08-20T16:58:20.000-04:00",
"createdAt":"June 16th, 2015 20:00",
"user":
{
"id":4
}
}
]}
The problem I get is that Ember-data is able to add my data to the store but I get this error :
Passing classes to store methods has been removed. Please pass a dasherized string instead of undefined
I have read these posts : #272 and #261
Is it a problem with the JSON response?
Thank you. I have been using ember-data for quite a bit of time and never encountered this error before switching to ember 2.0.1 and ember-data 2.0.0
EDIT : I am now sure it is related to the embedded conversations because in ember inspector, if I try to see the conversations of a user (and the conversations are loaded into the store), it returns me a promiseArray which isn't resolved.
Try not to push objects to store directly. Possible use-case of .push() :
For example, imagine we want to preload some data into the store when
the application boots for the first time.
Otherwise createRecord and accessing attributes of parent model will load objects to the store automatically.
In your case UserController from backend should return JSON:
{"users" : [ {"id":1,"conversations":[183,184]} ]}
Ember route for conversation may look like:
export default Ember.Route.extend({
model: function(params) {
return this.store.find('conversation', params.conversation_id);
}
}
User model:
export default DS.Model.extend({
conversations: DS.hasMany('conversation', {async: true})
});
You don't have to always completely reload model or add child record to store. For example you can add new conversation to user model:
this.store.createRecord('conversation', {user: model})
.save()
.then(function(conversation) {
model.get('conversations').addObject(conversation);
});
P.S. Try to follow Ember conventions instead of fighting against framework. It will save you a lot of efforts and nervous.
Your conversation route has URL /:user_id/:conversation_id. If you want it to be /:user_id/conversations/:conversation_id, you should change this.route('conversations', { path: '/'}, function(){ to this.route('conversations', function(){ or this.route('conversations', { path: '/conversations'}, function(){

Cannot read property 'match' of undefined at Ember.DefaultResolver.extend.podBasedComponentsInSubdir

I'm getting a really opaque error message (opaque in the sense I have no point of reference for my own source) from console, I'm not entirely sure where to look, I feel it's likely an error in library code but before posting this on github I'll just double check it's not my own fault.
The Problem
The Problem is simple, I'm calling this.store.find('player'), in hopes to get a list of all players, and then display them in some kind of list, but I'm not even getting past the loading part. The data is pulled from the server and looks properly formatted, but something seems to be failing after the route.model method call. And the error message seems to be somewhere in the ember.js library code with nothing pointing back to my own code.
Server Response
The content type is of course application/json, and note the id property is actually _id.
[
{
"_id":"55405a5102b4ed623c225e87",
"alias":"mikeTest",
"__v":0,
"scans":[],
"createdAt":"2015-04-29T04:13:05.223Z"
}
]
Error message
Note there is part of the stack trace pointing to my source, only Ember source. Which has made this a pain to debug.
Error while processing route: leader Cannot read property 'match' of undefined TypeError: Cannot read property 'match' of undefined
at Ember.DefaultResolver.extend.podBasedComponentsInSubdir (http://localhost:4200/assets/vendor.js:60138:76)
at http://localhost:4200/assets/vendor.js:60190:34
at Array.exports.default.mixin.Mixin.create.find (http://localhost:4200/assets/vendor.js:39572:30)
at Ember.DefaultResolver.extend.findModuleName (http://localhost:4200/assets/vendor.js:60188:44)
at resolveOther (http://localhost:4200/assets/vendor.js:60051:37)
at superWrapper (http://localhost:4200/assets/vendor.js:28141:20)
at exports.default.EmberObject.default.extend.resolve (http://localhost:4200/assets/vendor.js:15454:35)
at Object.resolve [as resolver] (http://localhost:4200/assets/vendor.js:15217:23)
at resolve (http://localhost:4200/assets/vendor.js:12792:29)
at Object.Registry.resolve (http://localhost:4200/assets/vendor.js:12336:21)
Source
This ember app is very young, so there is very little source at the moment, but this is all the relevant source at the moment.
Routes
import Ember from 'ember';
import config from './config/environment';
var Router = Ember.Router.extend({
location: config.locationType
});
export default Router.map(function() {
this.resource('leader');
this.resource('profile');
this.route('loading');
});
Leader route
Leader has a template and a controller, but they are basically empty right now.
import Ember from 'ember';
export default Ember.Route.extend({
model: function () {
return Ember.RSVP.hash({
players: this.get('store').find('player')
});
},
});
Player Model
import DS from 'ember-data';
export default DS.Model.extend({
alias: DS.attr('string'),
createdAt: DS.attr('date'),
scans: DS.hasMany('scan'),
});
Application Adapter
import DS from 'ember-data';
export default DS.RESTAdapter.extend({
namespace: ''
});
Application Serialiser
import DS from 'ember-data';
export default DS.RESTSerializer.extend({
primaryKey: function (type) {
return '_id';
},
serializeId: function(id) {
return id.toString();
}
});
Versions
I'm not sure if any of the versions here are particularly important
ember-cli is 0.2.3
ember-data is 1.0.0-beta.16.1
ember is 1.11.1
Things I've tried
removing properties from the model, in the event the relationships seemed to be the problem (nothing changed)
tried setting up a serialiser and adapter for the application (included above), nothing changed.
the serialiser in the event that the id field in the response is actually _id.
tried updating ember data, nothing changed.
Okay I figured out what was being done wrong... I forgot to check if the data being returned by the server abides to the convention/protocol required to use ember data. The JSON returned by the server looks like this.
[
{
"_id":"55405a5102b4ed623c225e87",
"alias":"mikeTest",
"__v":0,
"scans":[],
"createdAt":"2015-04-29T04:13:05.223Z"
}
]
It should actually look like this
{
"players": [
{
"_id":"55405a5102b4ed623c225e87",
"alias":"mikeTest",
"__v":0,
"scans":[],
"createdAt":"2015-04-29T04:13:05.223Z"
}
]
}
So yes this was me being dumb and missing something.
Why is this Required
Ember data expects JSON returned from the server to meet the JSON API Standard, which is a standard that specifies the formatting of the JSON returned from a server. In this case, the data didn't meet the JSON API standard, as I forgot to put the array of players under a key called players. There are some more examples of this in the Ember v1.10.0 guide to models.
The reason Ember Data expects this is so Ember Data can make the certain assumptions about the data returned from the server.

Ember dynamic segment with parameters

I have a dynamic segment route like this -
#resource 'owners', { path: "/:owner_id"}
#resource 'product', { path: "products/:product_id" }
Product route needs information from this route, and needs to load after some product params are loaded
Market.ProductRoute = Ember.Route.extend({
model: function(params) {
return this.store.find('product', params.product_id);
},
afterModel: function(model){
this.store.find('owner', model.get('id'), { 'owner_type':model.get('owner_type')});
},
});
And I get the following errors:
Error while processing route: product Assertion Failed: metaForProperty() could not find a computed property with key 'owner_type'. Error: Assertion Failed: metaForProperty() could not find a computed property with key 'owner_type'
Error: More context objects were passed than there are dynamic segments for the route: error
Uncaught Error: Assertion Failed: Error: More context objects were passed than there are dynamic segments for the route: error
Looking at your code, I think your intent is to load the associated owner after you load the product. I'm also assuming that you want to send the product id and owner_type to your server because this is a polymorphic relationship.
You're getting the error about owner_type error because you're passing something really weird as the third argument to find which is reserved for indicating data and relationships that you know are already preloaded -- probably not what you want. I can't help but notice the mix of CoffeeScript and JavaScript. It makes me think that you're mistaken about how find works because you're used to having CoffeeScript gather all the key-value pairs that you pass to a function into one object literal.
The second error More context objects were passed... is probably because you have a link where you're passing objects to a {{link-to}} helper when there isn't a dynamic segment (or not enough dynamic segments) in your router path. This is hard to tell from just the posted code.
Here is what I think you want to do in your product route:
Market.ProductRoute = Ember.Route.extend({
model: function(params) {
return this.store.find('product', params.product_id);
},
afterModel: function(model) {
this.store.find('owner', {
owner_id: model.get('id'),
owner_type: model.get('owner_type')
});
},
});
If you have control over your API it might be nice to just include the owner when you search for the product. I've had applications where sometimes I want associations and sometimes I don't. I often end up with routes that look like this:
Market.ProductRoute = Ember.Route.extend({
model: function(params) {
return this.store.find('product', {id: params.product_id, include: ['owner']});
}
});
At that point your server would take this {include: 'owner'} data to mean that it should also return the owner as side-loaded data.
Hope something in there helps!

Implement Routing With EmberFire?

However I find myself still unclear on the prospect of getting some of the functionality as Model. Right now I'm trying to utilize the new emberFire library, which provides some base Object types for interacting with the Firebase service.
I'm able to create new objects and arrays of objects, however I'm unable to get Routes setup properly.
Am I able to extend my base App.Model as one of the EmberFire objects in order to utilize the more standard approaches to retrieving and manipulating data?
Edit
When I've tried using the suggestion in Answer 2, I've gotten this error:
Uncaught TypeError: Cannot read property 'id' of undefined
So I tried adding in:
App.Post = EmberFire.Object.extend({
id: null,
body: null
});
To perhaps define the Object, however I feel I'm going about that the wrong way as well?
Edit 2
Here's my current stuff:
App = Ember.Application.create();
App.Router.map(function() {
this.resource('post', { path: '/:post_id' }, function() {
this.route('edit');
});
});
App.Post = EmberFire.Object.extend({
id: null,
title: null
});
As I mentioned above, I've tried defining my object as both an EmberFire.Object and EmberFire.Array, and attempted plugging App.Post.create in my Route.
App.IndexRoute = Ember.Route.extend({
model: function() {
return EmberFire.Array.create({
ref: new Firebase("https://embertest2.firebaseio.com/posts/")
});
}
});
App.PostRoute = Ember.Router.extend({
model: function(params) {
return EmberFire.Object.create({
ref: new Firebase("https://embertest2.firebaseio.com/posts/" + params.post_id)
});
}
});
I'm also wondering if perhaps I shouldn't be using the EmberFire.Array in my IndexRoute to generate essentially the list of links for each post.
App.IndexController = Ember.ArrayController.extend({
title: "",
actions: {
addPost: function() {
this.pushObject(this.get('title'));
}
}
});
My aim currently is to create each Post record, have it populate on the list, have links to each Post, and the ability to edit each Post record on the Post page.
Here's the current error I've been getting:
Uncaught TypeError: Cannot read property 'id' of undefined ember.js:30274
serialize ember.js:30274
paramsForHandler ember.js:29636
Router.generate ember.js:29457
Ember.Router.Ember.Object.extend.generate ember.js:30524
(anonymous function) ember.js:32438
ComputedPropertyPrototype.get ember.js:4446
get ember.js:1937
(anonymous function) ember.js:20674
Ember.EnumerableUtils.forEach ember.js:1805
Ember.View.Ember.CoreView.extend._applyAttributeBindings ember.js:20655
Ember.View.Ember.CoreView.extend.applyAttributesToBuffer ember.js:21128
Ember.View.Ember.CoreView.extend.beforeRender ember.js:21107
Ember.CoreView.Ember.Object.extend._renderToBuffer ember.js:19458
Ember.View.Ember.CoreView.extend._renderToBuffer ember.js:21096
superWrapper ember.js:1239
(anonymous function) ember.js:19440
Ember.Instrumentation.instrument ember.js:1683
Ember.CoreView.Ember.Object.extend.renderToBuffer ember.js:19439
Ember.merge.appendChild ember.js:21941
Ember.View.Ember.CoreView.extend.appendChild ember.js:21291
EmberHandlebars.ViewHelper.Ember.Object.create.helper ember.js:25821
(anonymous function) ember.js:25999
(anonymous function) ember.js:32685
program1
program handlebars-1.0.0.js:2251
Ember.View.Ember.CoreView.extend.render ember.js:20522
Ember.CoreView.Ember.Object.extend._renderToBuffer ember.js:19459
Ember.View.Ember.CoreView.extend._renderToBuffer ember.js:21096
superWrapper ember.js:1239
(anonymous function) ember.js:19440
Ember.Instrumentation.instrument ember.js:1683
Ember.CoreView.Ember.Object.extend.renderToBuffer ember.js:19439
Ember.merge.renderToBufferIfNeeded ember.js:21887
Ember.View.Ember.CoreView.extend.renderToBufferIfNeeded ember.js:21103
Ember.merge.ensureChildrenAreInDOM ember.js:22563
Ember.ContainerView.Ember.View.extend._ensureChildrenAreInDOM ember.js:22528
DeferredActionQueues.flush ember.js:5484
Backburner.end ember.js:5568
(anonymous function) ember.js:5822
I figure I'm doing something silly here, and will continue to muck about until I stumble over what I did incorrectly.
The README on the emberFire page that you linked details how to create your custom objects in your Route. If you're talking about the Router (which is different than a Route), I don't think it should be any different than normal (with Ember Data). If you're having trouble with it you should post the code that you've tried to use and any errors that you're getting. If you can post a JSBin illustrating the problem it would be even better.
You can attach EmberFire.Object to a specific URL that is associated with the post. You'll need the post_id to do that:
App.PostRoute = Ember.Router.extend({
model: function(params) {
return EmberFire.Object.create({
ref: new Firebase("https://embertest2.firebaseio.com/posts/" + params.post_id)
});
}
});

Emberjs: cross-controller binding failing because 'content' doesn't exist yet

I'm trying to use the 'needs' feature to allow one controller to obtain a value from another. Here's a JSFiddle that shows a stripped-down version of my app before binding a value: http://jsfiddle.net/kevinwh/WRxnE/4/
App.ApplicationController = Ember.ObjectController.extend({
init: function() {
this._super();
},
dishClicked: function() {
console.log('clicked');
this.incrementProperty('clickCount');
}
});
App.DishController = Ember.ObjectController.extend({
needs: ['application'],
init: function() {
this._super();
},
//clickCountBinding: 'controllers.application.clickCount'
});
Basically, my ApplicationController has a clickCount property that is updated (by an action) whenever one of the Dish links is clicked. Clicking on a link also activates the DishRoute via linkTo.
Now I'd like the contained DishController to also have access to ApplicationController's clickCount. So I add the 'needs' property and a clickCountBinding property (which will have to be uncommented in the JSFiddle). Then, when I click on a link I get a complaint:
assertion failed: Cannot delegate set('clickCount', 0) to the 'content' property of object proxy : its 'content' is undefined.
Apparently the binding is being activated before the model content is set on the controller. Since the controller is being set up by the linkTo, my DishRoute.model() and DishRoute.setupController() methods are not invoked. Also, the DishController.init() method isn't even called before the binding error happens.
I considered the possibility that I should just stick a content member object into the class (commented out in the JSFiddle), but doing that gives a bizarre result: the click count is incremented separately for the different links. Interesting, but not what I'm after.
So - how do I share the clickCount value across these controllers? Is there some other way to set up the content in the DishController so that the binding will work?
You've just slightly misunderstood the error message.
The issue is that you've subclassed the ApplicationController from ObjectController even though it doesn't have an underlying content object to proxy to, you should just user Ember.Controller in this case.
That being said, if you have a counter you should probably default it to zero anyway.
App.ApplicationController = Ember.Controller.extend({
clickCount: 0,
dishClicked: function() {
console.log('clicked');
this.incrementProperty('clickCount');
}
});
App.DishController = Ember.ObjectController.extend({
needs: ['application'],
clickCountBinding: 'controllers.application.clickCount'
});