Ember data single data extract through browser URL - ember.js

Getting all articles is ok, but when try to retrieve just one article through route url directly, system error - undefined
var articles = Ember.$.getJSON('http://localhost/emberdata/api/articles');
will return:
[{"articles":
[
{
"id":1,
"title":"Ember is the best",
"author":"brk","excerpt":"Programming is awesome"
},
{
"id":2,
"title":"Backbone not a framework",
"author":"krb",
"excerpt":"Server-side controller sucks"
},
{
"id":3,
"title":"Javascript pwned",
"author":"rbk",
"excerpt":"I know right"
}
]
}]
API is created using PHP Slim Rest API
this Route working find, showing all the data in the handlebar template
App.ArticlesRoute = Ember.Route.extend({
model: function() {
return articles;
}
});
However for child view routing, undefined is returned
App.ArticleRoute = Ember.Route.extend({
model: function(params) {
var article = articles.findBy('id', params.article_id);
console.log(article);
return article;
}
});
Directly invoking the child view URL is not working:
http://localhost/emberdata/#/articles/1
However clicking the link of articles, those child view route works:
this.resource('article', { path: ':article_id' });
This is the error:

Ember.$.getJSON() will return a promise (see: http://emberjs.com/api/classes/Ember.PromiseProxyMixin.html). You can't call the findBy() method on a promise.
That being said, you're making it yourself very difficult. I recommend to start using the DS.RESTAdapter. In your case it would be something like this:
App.ApplicationAdapter = DS.RESTAdapter.extend({
namespace: 'emberdata/api'
});
then clear (or remove) ArticlesRoute because you will use convention (instead of configuration):
App.ArticlesRoute = Ember.Route.extend({
});
idem for ArticleRoute. Except, if your backend doesn't support calls like /emberdata/api/article/1 use the following code:
App.ArticleRoute = Ember.Route.extend({
model: function(params) {
var article = this.store.find('article').findBy('id', params.article_id);
console.log(article);
return article;
}
});

Related

Ember.js Route with searchquery causes: UnrecognizedURLError

In my app I have a searchformula with dynamic input fields. The form leads then to the following URL:
/trefferliste/?modulId=1&modus=dokument&identnummer=XXX
my route definition:
this.resource('trefferliste', { 'path' : 'trefferliste/:query' });
until this point it works, but when i refresh the page it says: UnrecognizedURLError
in the trefferliste route I load the data with following statement:
return this.store.find('trefferliste', params.query);
I figured out, that the "?" causes the problem, but I need it for my store find query. So, can someone tell me how to define my route?
UPDATE: Here is a jsbin: http://emberjs.jsbin.com/nesehuxugi
Steps to reproduce the error:
Push the Button > then refresh the page and look into the console!
some additional informations:
DEBUG: Ember : 1.12.1
ember-template-compiler.js:163 DEBUG: Ember Data : 1.0.0-beta.17
ember-template-compiler.js:163 DEBUG: jQuery : 1.11.2
Use query params instead of dynamic segments, so characters with special meaning to URL schema will be escaped and your application routing will work even on refresh.
URL becomes: http://app.com#/trefferliste?query=%3FmodulId%3D1%26modus%3Ddokument%26identnummer%3DXXX, but you have to respect Ember.js and global URL conventions.
Working demo.
Code:
App = Ember.Application.create();
App.Router.map(function() {
this.resource('trefferliste');
});
App.IndexRoute = Ember.Route.extend({
model: function() {
return ['red', 'yellow', 'blue'];
}
});
App.TrefferlisteController = Ember.Controller.extend({
queryParams: ['query'],
query: null
});
App.IndexController = Ember.ObjectController.extend({
actions: {
suche: function() {
var query = "?modulId=1&modus=dokument&identnummer=XXX";
this.transitionTo('trefferliste', { queryParams: { query: query } });
}
}
});

EmberJS: Loading a child URL directly in a master-detail app with an SSE-backed model on the master controller

I'm trying to develop this single-module application with a master-detail relationship between two routes. The master is supposed to have a model which is initially loaded and subsequently updated with a single Server-Side-Events entry point. I have the following code so far:
var App = Ember.Application.create({
rootElement: '#content'
});
App.Router.map(function() {
this.resource('receptores', {path: '/'}, function() {
this.resource('receptor', {path: ':user_id'});
});
});
App.ReceptoresController = Ember.Controller.extend({
init: function() {
var sse = new EventSource('/push');
var controller = this;
sse.addEventListener('update-hhs', function(e) {
controller.set('model', JSON.parse(e.data).receptores);
});
}
});
App.ReceptorRoute = Ember.Route.extend({
model: function(params) {
return this.modelFor('receptores').findBy('id', params.user_id);
}
});
Loading the 'receptores' works and currently the data loads fine. Clicking on a link-to generated link as http://localhost:5003/#/skkkd, for example, will load the 'receptor' route and the detail data as well (the detail is just a subset of the same data loaded on the master).
If I try reloading at a detail url or entering http://localhost:5003/#/skkkd directly I'll get the following exception:
Error while loading route: TypeError: Cannot read property 'findBy' of undefined
at App.ReceptorRoute.Ember.Route.extend.model (http://localhost:5003/monitoreo/static/js/receptores.js:34:43)
at superWrapper [as model] (http://localhost:5003/static/js/ember-1.5.1.js:1292:16)
at Ember.Route.Ember.Object.extend.deserialize (http://localhost:5003/static/js/ember-1.5.1.js:36570:19)
at http://localhost:5003/static/js/ember-1.5.1.js:32972:57
at http://localhost:5003/static/js/ember-1.5.1.js:33464:19
at invokeResolver (http://localhost:5003/static/js/ember-1.5.1.js:9646:9)
at new Promise (http://localhost:5003/static/js/ember-1.5.1.js:9632:9)
at Router.async (http://localhost:5003/static/js/ember-1.5.1.js:33463:16)
at Object.HandlerInfo.runSharedModelHook (http://localhost:5003/static/js/ember-1.5.1.js:32971:16)
at Object.UnresolvedHandlerInfoByParam.getModel (http://localhost:5003/static/js/ember-1.5.1.js:33058:19)
I know the problem is the init hook isn't being called for ReceptoresController. I think what I should do is implement a model hook on either a ReceptoresRoute or the controller and load initial data through a jQuery.get() and have the server-side-events only update. But then where do I initialize the SSE?
Edit:
It turns out I misunderstood how the model hook works on child routes. In my case, I normally view the detail page through a link-to link, so Ember already provides the model for receptor. The model hook is never called in that case. It is only called when trying to access the detail page directly which is where it fails. So my problem remains.
My whole problem boils down to where I should place the SSE initialization so that both routes can have access to the same model regardless of which was loaded.
Alright, this is my solution. Pieced together from a couple questions here. Namely https://stackoverflow.com/a/21988143/410224 and https://stackoverflow.com/a/21752808/410224. Hope it helps someone out.
var App = Ember.Application.create({
rootElement: '#content'
});
App.Router.map(function() {
this.resource('receptores', {path: '/'}, function() {
this.resource('receptor', {path: ':user_id'});
});
});
App.ReceptoresRoute = Ember.Route.extend({
model: function() {
var deferredData = Ember.Deferred.create();
var data = [];
var sse = new EventSource('/push');
sse.addEventListener('update-hhs', function(e) {
var receptores = JSON.parse(e.data).receptores;
receptores.forEach(function(r) {
var item = data.findBy('id', r.id);
if (typeof(item) != 'undefined') {
data.replace(data.indexOf(item), 1, [r]);
} else {
data.pushObject(r);
data.sortBy('full_name');
}
});
deferredData.resolve(data);
});
return deferredData;
}
});
App.ReceptorRoute = Ember.Route.extend({
model: function(params) {
return this.modelFor('receptores').findBy('id', params.user_id);
}
});

How to Add Child Record to Existing Parent Record?

I've been googling and scouring Stack Overflow for some sort of hint on this subject but the information is scattered at best.
I'm trying to Create a new Child Record (Comment) and save it to an existing Parent Record (Post). I am using Ember-Model, rather than Ember-Data, but any tips or pointers would be greatly appreciated.
At the moment, I've been successful creating a new, embedded Comment but only when it is created with a new Post record. So:
How do I go about loading/retrieving the currently loaded Post(parent record) in order to apply Comments (child records) to it?
I've been reading up on controller dependencies, using needs: and this.controllerFor and this.modelFor in order to have access to another controller/model's content but have been unable to wire these things together into something meaningful.
Anyway, here is what I've whittled my application code down to, in the hopes I might be able to stumble into the proper way of doing this...
Routes
App.Router.map(function() {
this.resource('post', { path: '/:post_id' }, function() {
this.resource('comments', { path: '/comments'} );
});
});
I removed all the other resources & routes, so I'm left with App.Post, App.PostIndex, and App.Comments. I think my routes are the issue here, I assume I'm not properly implementing the methods to use the loaded Post record in my Comments route.
App.IndexRoute = Ember.Route.extend({
model: function() {
return App.Post.find();
},
setupController: function(controller, model) { // I'm not certain if this
controller.set('content', model); // setupController is needed?
}
});
App.PostRoute = Ember.Route.extend({
model: function(params) {
return App.Post.find(params.post_id);
},
setupcontroller: function( controller, model) { // again, unsure if this
this.controllerFor('post').get('comments'); // is correct.
controller.set('content', comments);
}
});
App.CommentsRoute = Ember.Route.extend({
afterModel: function() {
this.set('post', this.modelFor('post'));
},
setupcontroller: function( controller, model) {
this.controllerFor('post').get('comments');
controller.set('content', comments);
}
});
Controller
App.CommentsController = Ember.ArrayController.extend({
needs: "post",
actions: {
addComment: function() {
var post = App.Post.create({
title: 'static post title'
});
post.get('comments').create({
message: 'static message'
});
post.save();
}
}
});
This is my current Comments Controller, which can create a new Post with an embedded Comment. I've found and been given numerous examples in which to create the Comment, but none seem to work for me. Basically, I'm struggling with defining the var post = ... as the currently loaded record. I've implemented various approaches in an attempt at trial & error. Thus far I have attempted:
var post = App.Post.create();, returns property undefined, as this would create a new record. However, I gave it a shot as every example i saw related to this defined their record as such.
var post = this.get('post');, returns a cannot call 'get' on undefined. I've tried using this method of defining my current post on both the Comments controller and Post controller.
var post = this.get('controllers.post.content);, returns a 'cyclic error' from the backend I'm using.
var post = App.Post.find();, returns a cannot call 'get' on undefined.
var post = App.Post.find(1);, Again, returns a cannot call 'get' on undefined. Figured I'd give it a shot because this is one of those recurring examples people provide. The backend I use applies its own ID to each record, and I'm unsure if I would be able to/how to have the .find() method use a dynamic ID value and retrieve only the model I just loaded.
I'm guessing that I'm not properly setting up my Routes and Controller dependencies?
If anyone has a suggestion, relevant link, or fix I would be very grateful.
This one (seemingly simple) issue/use case has me at wit's end at this point.
Try this (works pre beta 2):
App.CommentsController = Ember.ArrayController.extend({
actions: {
addComment: function() {
this.content.createRecord({
message: 'static message'
});
}
}
});
Ember Data Beta 2 and later:
App.CommentsController = Ember.ArrayController.extend({
needs: ["post"],
actions: {
addComment: function() {
var post = this.get('controllers.post');
var comment = this.get('store').createRecord('comment', {
message: 'static message',
post: post
});
comment.save().then(function() {
post.addObject(comment);
// You may or may not need to save your post, too. In my case my backend handles
// the inverses of relationships (if existing), so there's no need. We still need
// to do this for Ember, though
});
}
}
});

Binding to URL parameters

I have the following route:
this.resource('activities', { path: '/activities' }, function() {
this.route('on_date', {path: '/:user_id/:on_date'});
});
And I'd like to be able to have easy access to the variables :user and :on_date in my router and controller. I have figured out a way to get access to this but it's very much a hack. In my controller I can do this:
App.ActivitiesByDateRoute = Ember.Route.extend({
model: function() {
var params = this.router.location.location.hash.split('/');
// note: location hash is api/activities/:user_id/:on_date
return App.Activity.find({id:params[2], on_date: params[3]});
},
});
While I'm happy this works, it's clearly not a good solution. Any pointers to achieving what must be a pretty common use-case would be greatly appreciated.
There is a feature to retrieve directly params on dynamic models.
App.ActivitiesByDateRoute = Ember.Route.extend({
model: function(params) {
return App.Activity.find({params.user_id, params.on_date});
}
});
It should work.
ref : http://emberjs.com/guides/routing/specifying-a-routes-model/#toc_dynamic-models

Ember Router rootURL option (Uncaught Error: No route matched the URL '/admin')

I'm trying to start to build a admin system that will run on a /admin/ prefix.
Here is my routes file
App.Router.reopen
location: 'history'
rootURL: '/admin'
App.IndexRoute = Ember.Route.extend
setupController: (controller, model) ->
#controllerFor('application').set('currentRoute', 'home')
When I go to /admin I get the following error:
Uncaught Error: No route matched the URL '/admin'
I'm just starting with emberjs, and my code is based on this serie
Ember version: v1.0.0-pre.4
Ember-data current api revision:: 11
In old-router the 'rootURL' property would have been ignored when resolving routes. In the latest version of ember, rootURL only seems to be used when constructing links. Not sure if this is a bug or oversight. As a workaround, try this instead:
App.Router.map(function() {
this.resource("admin", { path: "/admin" }, function() {
this.route("other");
});
});
App.IndexRoute = Ember.Route.extend({
redirect: function() {
this.transitionTo('admin');
}
});
When talking about routing in emberjs, it depends which version you are using. There was a big API change between 1.0pre2 and 1.0pre3. The docu on www.emberjs.com is already up-to-date for the new API and and easy to understand.
Below a really small example that shows
IndexRoute that automatically redirects to the overview of all members at '/members'.
Dynamic routing based on an ID
Serialization/Deserialization in case that the parameter is not 'id' but something else. In the example below, it is 'refId' (stands for reference ID).
Well, the examle does not really show more than the official documentation. but add-on information is always nice.
So, hope this helps. cheers.
App.Router.map(function() {
this.resource("members", { path: '/members' });
this.resource("member", { path: "/members/:refId" }, function() {
this.route("delete");
});
});
App.IndexRoute = Ember.Route.extend({
redirect: function() {
this.transitionTo('members');
}
});
App.MembersRoute = Ember.Route.extend({
model: function() {
return App.Member.findAll();
}
});
App.MemberRoute = Ember.Route.extend({
model: function(params) {
return App.Member.find(params.refId);
},
// overwrite default serializer (defaults to 'id', member has 'refId')
serialize: function(model) {
return { refId: model.refId };
}
});