Is there a conventional way to look up a singleton in Ember Data? I've set up my adapter for my GameState model from these instructions (under "Singular"): https://stackoverflow.com/a/23974804/173630
Now, when I fetch the GameState I'd like to be able to do this:
store.find('gameState');
But that initiates a findAll request type in Ember Data, which expects an array, not an object.
Another option I have is to do something like this:
store.find('gameState', 'mine');
The mine param is ignored, but this will successfully fetch and load my GameState. The downside here is that Ember Data creates an extra GameState instance in my store with an id of mine. Is there any way to prevent this?
I'm using Ember Data 1.0.0-beta.11.
Here's what my model looks like:
var GameState = DS.Model.extend({
currentPuzzle: DS.belongsTo('puzzle'),
currentRound: DS.belongsTo('puzzleRound'),
currentInventory: DS.attr('number'),
moves: DS.hasMany('move', {async: true}),
createdAt: DS.attr('date'),
updatedAt: DS.attr('date')
});
No, unfortunately that's a side affect of doing it like this. You can do a few different things here:
Hack it out using private methods/members
Switch to a findAll/findQuery approach changing your api and then only returning the first item from the results (which would be the only result).
Make a boring ajax call, and sideload the record.
findAll/findQuery - pain cause you have to change your api
return this.store.find('foo').then(function(records){
return records.get('firstObject');
});
jquery ajax sideload
var store = this.store;
return $.ajax('foo').then(function(data){
return store.push('foo', data); // push returns the record
});
http://emberjs.com/api/data/classes/DS.Store.html#method_push
Related
Is there a way to load a subclass data model into a superclass's route?
As an example, I have a superclass named Vehicle and a subclass named Car.
I have route like this:
/vehicle/21/edit
And in this instance, Vehicle #21 is a Car. Accrodingly, my API returns the following payload data:
{"car": {/* lots of data */}}
When the route vehicle.edit tries to load this data, I get the following error:
Error while processing route: vehicle.edit payload.data is null
I can work around this by changing my API so that it uses vehicle as the root node in the JSON response, but I was wondering if Ember has a way to automatically cast a subclass into a superclass (e.g., load the car JSON response into a Vehicle instance).
Thanks in advance!
Today emberjs/data only supports polymorphism for relationships.
I.e. you can define following model:
//models/blog-post.js
import DS from 'ember-data';
export default DS.Model.extend({
title: DS.attr('string'),
post: DS.attr('string'),
comments: DS.hasMany('comment', { polymorphic: true }) //i.e. pic-comment, text-comment
});
What you want is to call polymorphic data from store:
this.get('store').findRecord('vehicle', 21);
But this is not possible at the moment. There's an open RFC out there. So maybe this is possible in future.
Depending on what your payload looks like, you can approach this in a couple of different ways.
If you have access to how the payload is being sent, the most elegant way to deal with it would be to use hasMany relationship.
Else, in the route, you can make the call in your model hook and return that data to be used by vehicle.edit route.
I have this model:
App.Game = DS.Model.extend({
name: attr(),
uri: attr()
});
and this route:
App.GamesRoute = Ember.Route.extend({
model: function() {
return this.store.find('game');
}
});
This works fine, calls the backend server, and stores elements in the store (I've checked with Ember inspector). This is the json I return:
{"games":[{"id":"TicTacToe","name":"TicTacToe","uri":"http://localhost:10000/games/TicTacToe"}]}
Now I have this template for 'games' (snipped):
{{#each game in model}}
{{#link-to 'games.matchlist' game.id}}{{game.uri}}{{/link-to}}
This shows the URI for each game. Now in the games.matchlist route what I would like to do is to search in the store by the game_id received param and get the game URI. The reason is that the server doesn't follow RESTAdapter conventions, and I would like to make a custom AJAX query to that URI myself.
This doesn't work:
App.GamesMatchlistRoute = Ember.Route.extend({model: function(params) {
var store = this.store;
var game = store.find('game', params.game_id)
console.log(game);
console.log("URI: " + game.uri);
at this point, game is an object but it's not an instance of my model. It doesn't have a uri attribute. What am I doing wrong? I'm feeling that I'm missing something obvious.
If you want to get records without hitting the server and you know you already have it in the store, use this.store.getById('game', ID).
I'm on my mobile, but you need to create a GameAdapter and customize I believe the fetch function. Checkout the docs for adapters on the ember site and you should have your answer.
Your other option is to fetch the data from your server and use this.store.pushPayload(data).
Docs here: http://emberjs.com/api/data/classes/DS.Store.html#method_pushPayload
And the adapter docs here: http://emberjs.com/guides/models/customizing-adapters/
I'm new to Ember and Ember-data and am deciding whether to use Ember-Data or one of the other persistence libraries. In order to evaluate, I'm experimenting with writing a small Rails-backed app.
One of my routes can be considered similar to the Todo MVC app that is frequently used in examples.
In my template, I have a number of input fields that represent attributes within the model. Furthermore, I also have one element in the model that represents a hasMany relationship.
Models:
App.CompanyModel = DS.Model.extend
company: DS.attr()
desc: DS.attr()
contacts: DS.hasMany('company_contact')
App.CompanyContactModel = DS.Model.extend
firstname: DS.attr()
lastname: DS.attr()
...
Within my controller, I want to be able to create a new CompanyModel record (and by virtue, add one or more contacts models to it), but not have it appear within the controller's instance of the CompanyModel until I'm ready to do so.
Currently, when a user wants to add a new record, I have a component that calls an action in my controller as follows:
#set('new_company',
#store.createRecord('company')
)
This actually works fine, except for one thing. My view has to populate the individual attributes within "new_company", which it does, however, the record is immediately added to the controller's model instance and appears in the list of records; I only want the newly created record to be visible in the table once a particular action has taken place.
Instead of instantiating new_company with createRecord, I could do something like this:
#set('new_company',
Ember.Object.create
companyname: ''
desc: ''
contacts: [
firstname: ''
lastname: ''
]
)
And then do a #store.createRecord('company', #get('new_company')), however, given I've already defined my attributes in the model, it doesn't feel very DRY to me.
I'm using Ember 1.5.0 and Ember-Data 1.0.0-beta.7.
It appears I'm not the first person to have this issue (create temporarty non persistent object in Ember-Data), but it appears that Ember-Data has sufficiently changed to make all of these solutions inoperable.
Thanks for your help!
You're real issue is you're using what's considered a live collection. I'm going to assume in your route you've done something like this:
App.FooRoute = Em.Route.extend({
model: function(){
return this.store.find('company');
}
});
find with no parameters says, hey Ember Data, find me all the records that are company. Well Ember Data shoots off a request to your back-end, then returns store.all('company'). all is a live collection that will always have all the records of that type currently in the store. In your case, you are saying I want to avoid any record that is new. There are a couple of ways to handle this.
Create a static list. (You'll need to manually add/remove objects to/from this list).
App.FooRoute = Em.Route.extend({
model: function(){
return this.store.find('company').then(function(companies){
return companies.toArray();
});
}
});
Example: http://emberjs.jsbin.com/OxIDiVU/641/edit
Create a computed property that only shows records that aren't new
App.FooRoute = Em.Route.extend({
model: function(){
return this.store.find('company');
}
});
App.FooController = Em.ArrayController.extend({
savedRecords: function(){
return this.get('model').filterBy('isNew', false);
}.property('model.#each.isNew')
// shorthand this could be written like this
// savedRecords: Ember.computed.filterBy('model', 'isNew', false)
});
Then in your template you would iterate over the computed property
{{#each item in savedRecords}}
{{/each}}
Example: http://emberjs.jsbin.com/OxIDiVU/640/edit
I am new(to ember) and trying to build a search centric Ember App w/ Ember-data also. I wanted to change the url on the fly(based on search string) and the data should change automatically(on the fly). How to do it?
This is my not working code:
Emapp.Data = DS.Model.extend({
first_name: DS.attr('string')
}).reopenClass({
url: Emapp.MyURL.get('url')
});
Emapp.MyURL = Em.Object.create({
urlParam: 'John',
url: function()
{
return 'emb/data.php?id=%#'.fmt(this.get('urlParam'));
}.property('urlParam')
});
When I execute. emapp.MyURL.set('urlParam', 'Adams'). I can inspect and see the url changed to 'Adams'. But data is not fetched again.
Edit: emapp -> Emapp (pointed out by rudi-angela)
As you have made the 'url' property a computed property, Ember takes care of updating this value when the urlParam changes. That is all you have instructed Ember to do here (and apparently it is doing it properly).
But I reckon what you want here is any change in the 'urlParam' property to trigger a fetch action. In that case a solution would be to create a separate object that observes the urlParam and will take action when the 'urlParam' value changes. Something along these lines:
emapp.watcher = Ember.Object.create({
valueBinding: "emapp.MyURL.urlParam",
observer: function() {
console.log("urlParam has changed:");
// perform your fetch here
}.observes("value"),
});
Note: I thought there was a requirement for the namespace to be capitalised (rather Emapp instead of emapp).
I have a very common situation, if there is a term for it, well I am not aware of it then.
A record is having fields: id, enabled, text, etc...
and having POST /record/enable to enable or disable record, as it invoke is bigger process on server.
So, once callback from normal POST is received, I want to update record.enabled to true locally, which should not be part of any transaction. and should be updated directly.
How to achieve this?? Or what is better alternative for such requirement?
I think something along these lines should do:
App.PObject = DS.Model.extend({
id: DS.attr('number'),
name: DS.attr('string'),
nestedObject: function() {
if (!this.nestedObj) {
this.nestedObj = Ember.Object.create({
active: false
});
}
return this.nestedObj
}.property()
});
As i have seen so far, Model is dirty only when its attributes, that are defined as DS.attr, change.
EDIT: Realized later that, This solution doesn't work.
Proper term of my problem is: transient field
Transient field of an Object is ignored for serialization/deserialization (like Java ORMs ignores transient fields) http://en.wikipedia.org/wiki/Transient_(computer_programming
I have figured out a solution. Its really simple.
App.PObject = DS.Model.extend({
id: DS.attr('number'),
name: DS.attr('string'),
//will not be part of Ember-data persistence, but will be populated on GET
enabled: null
});
Object (Record) properties which are not attributes are ignored.