Load two emberFire models in one ember.js route - ember.js

I'm trying to load two models in one route and am not having any luck figuring it out. One route to hold all information to dynamically create a form and the other model is the one in which it will push form submission data to. Here is some of what I have so far:
Router Map
App.Router.map(function() {
this.route('about');
this.route('plans');
this.resource('prices', function() {
this.resource('price', { path: '/:price_id' });
});
this.resource('apply', function() {
this.resource('getstarted');
this.resource('addresses');
this.resource('contacts');
this.resource('drivers');
this.resource('equipment');
this.resource('assign');
});
});
For the Route I have tried all three of the following
Option 1
App.GetstartedRoute = Ember.Route.extend({
model: function(){
return Ember.Object.create({
form: function() {
return EmberFire.Array.create({
ref: new Firebase("https://example.firebaseio.com/apply/getstarted")
});
},
data: function() {
return EmberFire.Array.create({
ref: new Firebase("https://example2.firebaseio.com/companies/-JAY7n7gXJeVbFCCDJdH/carriers/")
});
},
});
}
});
Option 2
App.GetstartedRoute = Ember.Route.extend({
model: function(){
return Ember.RSVP.hash({
form: function() {
return EmberFire.Array.create({
ref: new Firebase("https://example.firebaseio.com/apply/getstarted/")
});
},
data: function() {
return EmberFire.Array.create({
ref: new Firebase("https://example2.firebaseio.com/companies/-JAY7n7gXJeVbFCCDJdH/carriers/")
});
}
});
}
});
SOLUTION Option 3 - as suggested by kingpin2k
App.GetstartedRoute = Ember.Route.extend({
model: function(){
return Ember.Object.create({
form: EmberFire.Array.create({
ref: new Firebase("https://moveloaded-ember.firebaseio.com/apply/getstarted/")
}),
data: EmberFire.Array.create({
ref: new Firebase("https://logistek.firebaseio.com/companies/-JAY7n7gXJeVbFCCDJdH/carriers/")
})
});
}
});
FireBase json at getstarted
{
"_type" : "object",
"1" : {
"type" : "text",
"placeholder" : "Type it in here...",
"name" : "carrierName",
"caption" : "What's the name of your carrier?"
}
}
The form is created via recursing through the first model, putting the data into a component that generates the form. I've tried to access the emberFire arrays in the first model using all of the following:
{{model.form.type}}
{{form.type}}
{{#each form}}
{{type}}
{{/each}}
{{#each model.form}}
{{type}}
{{/each}}
{{#each}}
{{form.type}}
{{/each}}
But it is not working...
Any ideas?
Update 1:
The fix was using option 3 as suggested by kingpin2k
also, I had to make the following change to my GetstartedController:
from:
App.GetstartedController = Ember.ArrayController.extend
to:
App.GetstartedController = Ember.ObjectController.extend
Then accessing the form model was as simple as:
{{#each form}}
{{type}}
{{/each}}

looking at the firebase code it doesn't look like it exposes any promises (so Ember.RSVP.hash won't do you any good). That being said you'll essentially just create a hash with 2 fields and return that.
return Ember.Object.create({
form: EmberFire.Array.create({
ref: new Firebase("https://example.firebaseio.com/apply/getstarted")
}),
data: EmberFire.Array.create({
ref: new Firebase("https://example2.firebaseio.com/companies/-JAY7n7gXJeVbFCCDJdH/carriers/")
})
});

Related

How to get List for hasMany relation in Fixture adapter in ember-data

I am new to ember.. I have 2 models..
Music.Artist = DS.Model.extend({
name: DS.attr('string'),
dob : DS.attr('date'),
songs : DS.hasMany('song',{async:true})
});
Music.Artist.FIXTURES=[
{
id:1,
name:'John',
dob:new Date(),
songs:['1','2']
},
{
id:2,
name:'Robbin',
dob:new Date(),
songs:['1','2']
}
];
Music.Song = DS.Model.extend({
title:DS.attr('string'),
artists:DS.hasMany('artist',{async:true})
});
Music.Song.FIXTURES = [
{
id:1,
title:'A day to remember',
artists:[1,2]
},
{
id:2,
title:'Cant live without you',
artists:[1,2]
}
];
I want for url "/songs/id"... I get all the songs that has an artist with the given id.
Music.Router.map(function(){
this.resource('songs',{path:'/songs/:id'});
});
Music.SongsRoute = Ember.Route.extend({
model:function(param){
var artist = this.store.find('artist',param.id);
return artist.get('songs');
}
});
But it returns undefined... How to get the list of songs that are related to the Artist.
Is there any way i can achieve this by using only routes.
How to read the array of songs, if not through get.
Based on the current versions of Ember (1.6.1) and Ember-Data (1.0.0-beta.9), here's how I got your example working. I changed your route naming, I think you really want something like /artists/:artist_id which will list the artist's data, including all his songs.
Your Artist and Song model declarations seem fine, but I declared the fixtures like so:
Music.Artist.reopenClass({
FIXTURES: [
{
id:1,
name:'John',
dob:new Date(),
songs:['1','2']
},
{
id:2,
name:'Robbin',
dob:new Date(),
songs:['1','2']
}
]
});
Music.Song.reopenClass({
FIXTURES: [
{
id:1,
title:'A day to remember',
artists:[1,2]
},
{
id:2,
title:'Cant live without you',
artists:[1,2]
}
]
});
For the router:
Music.Router.map(function() {
this.resource('artists');
this.resource('artist', { path: '/artists/:artist_id' });
});
For the routes:
var Music.ArtistsRoute = Ember.Route.extend({
model: function() {
return this.store.find('artist');
}
});
var Music.ArtistRoute = Ember.Route.extend({
model: function(params) {
return this.store.find('artist', params["artist_id"]);
}
});
For your templates:
// artists.hbs
<ul>
{{#each}}
<li>{{#link-to 'artist' this}}{{name}}{{/link-to}}</li>
{{/each}}
</ul>
// artist.hbs
<h1>{{name}}</h1>
<hr>
<h2>Songs</h2>
<ul>
{{#each songs}}
<li>{{title}}</li>
{{/each}}
</ul>
Hope this helps!

Implementing model filter

I have set up the following scaffolding for my Ember application.
window.App = Ember.Application.create({});
App.Router.map(function () {
this.resource('coaches', function() {
this.resource('coach', {path: "/:person_id"});
});
});
App.ApplicationAdapter = DS.FixtureAdapter.extend({});
App.Person = DS.Model.extend({
fname: DS.attr('string')
,lname: DS.attr('string')
,sport: DS.attr('string')
,bio: DS.attr('string')
,coach: DS.attr('boolean')
,athlete: DS.attr('boolean')
});
App.Person.FIXTURES = [
{
id: 10
,fname: 'Jonny'
,lname: 'Batman'
,sport: 'Couch Luge'
,bio: 'Blah, blah, blah'
,coach: true
,athlete: true
}
,{
id: 11
,fname: 'Jimmy'
,lname: 'Falcon'
,sport: 'Cycling'
,bio: 'Yada, yada, yada'
,coach: false
,athlete: true
}
];
I am trying to set up a route to filter the person model and return only coaches. Just to make sure I can access the data, I have simply used a findAll on the person model.
App.CoachesRoute = Ember.Route.extend({
model: function() {
return this.store.findAll('person');
}
});
Now though, I am trying to implement the filter method detailed on the bottom of the Ember.js Models - FAQ page.
App.CoachesRoute = Ember.Route.extend({
model: function() {
var store = this.store;
return store.filter('coaches', { coach: true }, function(coaches) {
return coaches.get('isCoach');
});
}
});
The coaches route is not working at all with the new route implemented and the old one commented out. I am using the Ember Chrome extension and when using the filter route the console responds with, Error while loading route: Error: No model was found for 'coaches'. Apparently the route is not working, specifically the model. No kidding, right? What am I missing in my filter model route?
Thank you in advance for your help.
The error message is spot on- there is no CoachModel. I think you need to do this:
App.CoachesRoute = Ember.Route.extend({
model: function() {
var store = this.store;
return store.filter('person', { coach: true }, function(coaches) {
return coaches.get('isCoach');
});
}
});

Ember JS cannot createRecord with new ember-data syntax

I am trying to use the new ember-data syntax like explained here: https://github.com/emberjs/data/blob/master/TRANSITION.md (read from Transaction is Gone: Save Individual Records ).
When I hit the save button I get the error Uncaught TypeError: Cannot call method 'save' of undefined in the console. Also in the network tab, there is no POST request to the api.
The template
<script type="text/x-handlebars" data-template-name="landcode/new">
Code: {{input value=code}}<br />
Image: {{input value=image}}<br />
<button {{action 'saveLandcode'}}>opslaan</button>
The app.js (relevant code)
App.Router.map(function() {
this.resource("landcodes"),
this.resource("landcode", function() {
this.route("new");
});
});
App.LandcodeNewRoute = Ember.Route.extend({
model: function() {
this.store.createRecord('landcode');
},
actions: {
saveLandcode: function(){
this.modelFor('landcode').save(); // does not save
}
}
});
App.ApplicationAdapter = DS.RESTAdapter.extend({
namespace: 'api'
});
App.Store = DS.Store.extend({
adapter: 'App.ApplicationAdapter'
});
App.Landcode = DS.Model.extend({
code: DS.attr('string'),
image: DS.attr('string')
});
You are using this.modelFor('landcode') this will take the returned model from App.LandcodeRoute, but your model is returned from LandcodeNewRoute. Just use this.currentModel, since you want the model of the current route.
App.LandcodeNewRoute = Ember.Route.extend({
model: function() {
return this.store.createRecord('landcode');
},
actions: {
saveLandcode: function(){
this.currentModel.save();
}
}
});
Your model for should include the route name as well
App.LandcodeNewRoute = Ember.Route.extend({
model: function() {
return this.store.createRecord('landcode');
},
actions: {
saveLandcode: function(){
this.modelFor('landcode.new').save(); // the correct model
}
}
});

How to correctly access a parent controllers data (model) in nested resources?

I have a little EmberJS app to test things out hot to do nested resources. Sometimes accessing a parent routes/controllers data work, other times not.
Most likely this is due to a oversight on my part with how EmberJS does its magic.
Here is the app:
window.App = Ember.Application.create();
App.Router.map(function() {
this.resource('items', function() {
this.resource('item', {path: ':item_id'}, function() {
this.resource('subitems');
});
});
});
App.ApplicationController = Ember.Controller.extend({
model: {
items: [
{
id: 1,
name: 'One',
subitems: [
{
id: 1,
name: 'One One'
}, {
id: 2,
name: 'One Two'
}
]
}, {
id: 2,
name: 'Two',
subitems: [
{
id: 3,
name: 'Two One'
}, {
id: 4,
name: 'Two Two'
}
]
}
]
}
});
App.ItemsRoute = Ember.Route.extend({
model: function() {
return this.controllerFor('Application').get('model.items')
}
});
App.ItemRoute = Ember.Route.extend({
model: function(params) {
var items = this.controllerFor('Items').get('model')
var item = items.filterBy('id', parseInt(params.item_id))[0]
return item
}
});
App.SubitemsRoute = Ember.Route.extend({
model: function(params) {
var item = this.controllerFor('Item').get('model')
var subitems = item.get('subitems')
return subitems
}
});
http://jsfiddle.net/maxigs/cCawE/
Here are my questions:
Navigating to items/1/subitems throws an error:
Error while loading route: TypeError {} ember.js:382
Uncaught TypeError: Cannot call method 'get' of undefined test:67
Which i don't really get, since apparently the ItemController loads its data correctly (it shows up) and the same construct works for the ItemsRoute as well to get its data.
Since i don't have access to the parents routes params (item_id) i have no other way of re-fetching the data, even though directly accessing the data from ApplicationController works fine.
Why do i have define the root data in a controller not route?
Moving the model definition from ApplicationController to ApplicationRoute, does not work.
Conceptually, as far as i understand it, however this should even be the correct way to do it, since everywhere else i define the mode data for the controller int he route.
Or should the whole thing be better done via the controllers needs-api? As far as i understood the needs are more for only accessing extra data within the controller (or its view) but the routers job is to provide the model.
1. Navigating to items/1/subitems throws an error:
Your model is just a javascript object so there isn't a method get to fetch the data. You can access the subitems by just executing item.subitems.
Also the argument of controllerFor() should be lower case.
For instance:
this.controllerFor('application')
2. Why do i have define the root data in a controller not route?
You can set the model from the route in the setupController method.
App.ApplicationRoute = Ember.Route.extend({
setupController: function(controller) {
controller.set('model', { ... });
}
});
http://jsfiddle.net/Y9kZP/
After some more fiddling around here is a working version of the example in the question:
window.App = Ember.Application.create();
App.Router.map(function() {
this.resource('items', function() {
this.resource('item', {path: ':item_id'}, function() {
this.resource('subitems');
});
});
});
App.ApplicationRoute = Ember.Route.extend({
model: function() {
return Ember.Object.create({
items: [
Ember.Object.create({
id: 1,
name: 'One',
subitems: [
{
id: 1,
name: 'One One'
}, {
id: 2,
name: 'One Two'
}
]
}), Ember.Object.create({
id: 2,
name: 'Two',
subitems: [
{
id: 3,
name: 'Two One'
}, {
id: 4,
name: 'Two Two'
}
]
})
]
})
}
});
App.ItemsRoute = Ember.Route.extend({
model: function() {
return this.modelFor('application').get('items')
}
});
App.ItemRoute = Ember.Route.extend({
model: function(params) {
return this.modelFor('items').findProperty('id', parseInt(params.item_id))
}
});
App.SubitemsRoute = Ember.Route.extend({
model: function(params) {
return this.modelFor('item').get('subitems')
}
});
http://jsfiddle.net/maxigs/cCawE/6/ and deep link into subitems (that did not work previously) http://fiddle.jshell.net/maxigs/cCawE/6/show/#/items/2/subitems
What changed:
root-model data moved into ApplicationRoute
root-model moved into an ember object, and sub-objects are also their own ember objects (so calling get('subitems') and other ember magic works)
changed all the controllerFor('xxx').get('model') into modelFor('xxx') (lower case!), which probably has no effect other than consistency
I'm still not sure if this is now "the ember way" of doing what i have here but its consistent and works completely as wanted.

Ember Router transitionTo nested route with params

App.Router.map(function() {
this.resource('documents', { path: '/documents' }, function() {
this.route('edit', { path: ':document_id/edit' });
});
this.resource('documentsFiltered', { path: '/documents/:type_id' }, function() {
this.route('edit', { path: ':document_id/edit' });
this.route('new');
});
});
And this controller with a subview event that basically transitions to a filtered document
App.DocumentsController = Ember.ArrayController.extend({
subview: function(context) {
Ember.run.next(this, function() {
//window.location.hash = '#/documents/'+context.id;
return this.transitionTo('documentsFiltered', context);
});
},
});
My problem is that this code works fine when Hash of page is changed.
But when I run the above code NOT w/ the location.hash bit and w/ the Ember native transitionTo I get a cryptic
Uncaught TypeError: Object [object Object] has no method 'slice'
Any clues?
Thanks
UPDATE:
App.DocumentsFilteredRoute = Ember.Route.extend({
model: function(params) {
return App.Document.find({type_id: params.type_id});
},
});
{{#collection contentBinding="documents" tagName="ul" class="content-nav"}}
<li {{action subview this}}>{{this.nameOfType}}</li>
{{/collection}}
The problem is that your model hook is returning an array, while in your transitionTo you are using a single object. As a rule of thumb your calls to transitionTo should pass the same data structure that is returned by your model hook. Following this rule of thumb i would recommend to do the following:
App.DocumentsController = Ember.ArrayController.extend({
subview: function(document) {
var documents = App.Document.find({type_id: document.get("typeId")});
Ember.run.next(this, function() {
return this.transitionTo('documentsFiltered', documents);
});
}
});
Note: I assume that the type_id is stored in the attribute typeId. Maybe you need to adapt it according to your needs.