I have an Ember app with a login form which returns the current user in JSON format after successful login.
Using createRecord sets the returned JSON attributes directly on the model. For instance, is_private becomes user.is_private, not user.get('isPrivate')?
How do I load the user model so that the attributes are set correctly and I don't have to re-fetch it using the id?
As of a few days ago in ember data 1.0 beta you can use pushPayload to load data directly into the store. For example if you get data pushed to your app through WebSockets (we use the Heroku add-on Pusher). You can call it on the store (source) directly and it will pass it through the appropriate serializer:
var postsJSON = {
posts: [
{id: 1, post_title: "Great post"}
]
}
this.store.pushPayload('post',postsJSON)
NOTE that it will not currently load a singular object (ie post: {id: 1, post_title:"First!"}) - you need to format it as plural with an array.
DS.RESTSerializer has pushPayload as well (source), in which case you need to pass it the store instead.
I highly encourage reading the source code before using, as it looks like the implementation of it will be revisited.
Supposedly, the official way to do this is using adapter.load, as described in this thread:
Loading Data
Previously, some features of the store, such as load(), assumed a
single adapter.
If you want to load data from your backend without the application
asking for it (for example, through a WebSockets stream), use this
API:
store.adapterForType(App.Person).load(store, App.Person, payload);
This API will also handle sideloaded and embedded data. We plan to add
a more convenient version of this API in the future.
But unfortunately, it doesn't handle sideloaded data, despite what the documentation claims. I personally use something like the following, which is based on how find(ID) is implemented:
var id = json["person"]["id"];
var store = DS.get("defaultStore");
var adapter = store.adapterForType(App.Person);
adapter.didFindRecord(store, App.Person, json, id);
var person = App.Person.find(id);
Note that this code assumes JSON in the same format that find(ID) expects to receive from the server, as documented in the RESTAdapter guide:
{
person: {
id: 1,
is_private: false,
projects: [3]
},
projects: [
{ id: 3, name: "FooReader" }
]
}
This will apply any transformations you've configured using keyForAttributeName (such as mapping is_private to isPrivate), and it will handle sideloaded records. I'm not sure if this is a best practice, but it works quite well.
how about store.push('user', userJSON)?
http://emberjs.com/guides/models/pushing-records-into-the-store/#toc_pushing-records
All answers above did not work for me.
What only worked for me was:
this.store.buildRecord(this.store.modelFor('person'), data.id, data)
Related
As u already know the Local resolvers are deprecated so we can't use it as a perspective way to handling REST cache. What we should use instead of resolvers?
'field policies' are not good for that at all. Let's imagine... You have two different client queries: getBooks and getBook. Each query getting data from the rest API. Somehow we need to handle the situation when we already got the data from getBooks and runing another query getBook. getBook should not make a request because the data were already cached. We did that in resolvers before it was deprecated. We were just checking the cache and return the data if it already exists in the cache if not did a request. How we can handle this in current circumstances?
Sorry but it's a bit not what I meant. Here is a code example:
export const getBooks = gql`
query getBooks () {
getBooks ()
#rest(
type: "Book"
path: "books"
endpoint: "v1"
) {
id
title
author
}
}
`
export const getBook = gql`
query getBook ($id: Int!) {
getBook (id: $id)
#rest(
type: "Book"
path: "book/{args.id}"
endpoint: "v1"
) {
id
title
author
}
}
`
So we have two different queries. The goal is when we run both in turn the getBook should not make a REST request because we already have the same data in the cache since we get it from getBooks. Before resolvers were deprecated we handle it in resolvers. Like: if this ID is not exist in the cache just make a request if exist give me data from the cache. How we can do that now?
As u can see fetchPolicy it's completely different.
Local fields it's also not good because it's something about fields not about the whole entity.
I have a users model which fetches data from github users api (https://api.github.com/users). While displaying the list there is a add button which should add the user to a shortlist section below and which has a remove button to remove user from shortlist. I don't have api to save shortlist data. What is the best approach to make this work?
Try 1: Created a shortlist model and used store.push
this.store.push({
data: [{
id: user.id,
type: 'shortlist',
attributes: {
login: userData.login,
avatar_url: userData.avatar_url,
type: userData.type
}
}]
});
and used item.unloadRecord(); to remove from model. But did nor found a way to fetch all record and show as this.store.peakAll('shortlist') wasen't working.
Try 2: Used localstorage to add user to shortlist, display and remove but here it needs page reload to display the add/remove changes as i used setupController to get the items from localstorage.
Please suggest how to do this in best possible way.
I'm using Loopback, Angular2 and ng-bootstrap date picker in an application and having trouble saving dates.
I'm using #angular/http to send a POST request to a Loopback backend that includes a ng-bootstrap date picker input. The date picker format is:
{
day: 15,
month: 6,
year: 2017
}
which I can see in the headers of my request, however Loopback expects dates to be saved as a JavaScript Date Object.
Before I attempt to save my date data, I want to convert it from the format above to a native JavaScript Object. However, if I run the following code the console shows Invalid Date.
MyModel.observe('before save', (ctx, next) => {
console.log('date: ', ctx.instance.date);
});
The loopback documentation states that the before save observer triggers before the request validators are called, but that doesn't look like the case in this instance.
What is the correct loopback method of accessing the POST request and modifying it before the validators sink their teeth into it and throw an error?
It looks like the remote hooks are hit before the validators. You might want to try:
MyModel.beforeRemote('create', (ctx, [instance], next)=>{
// handle code here
// don't forget to validate the data on 'updateById' too
next();
});
I'm having issues accessing the current route params within an adapter. I've tried looking in the store and type objects that are passed in but have not been able to find anything.
I know I could use window.href.location to access the string of the url and do some manipulation to access the route param, however I'm not comfortable hardcoding that in because the url may change.
I would recommend you to use query argument passed to a method you use to query your data.
Look at the default implementation of rest-adapter's queryRecord():
query(store, type, query) {
var url = this.buildURL(type.modelName, null, null, 'query', query);
if (this.sortQueryParams) {
query = this.sortQueryParams(query);
}
return this.ajax(url, 'GET', { data: query });
},
It has access to the query argument and uses buildURL, you can override function buildURL() or query() and adjust it the way you need.
What you need to do afterwards is to use your route or controller to read query parameters from the url and pass to the store your query object to reflect your need.
Here is the link to Ember-Data DS.Adapter API
When I call myModel.save(), in one of my controllers, to insert a new record into the store I get back a promise with isRejected: true.
The reason object has the following attributes:
readyState: 4,
status: 201,
statusText: "created"
The object is created properly in my backend REST service. In fact, if I put the transitionToRoute in the catch(), instead of the then(), everything would appear to be just fine.
What's going on here?
You need to return the object back with your request. This is particularly important because the server should provide an id for that newly created record. Without an id there is no definitive way of updating and being sure you're updating the correct record. The format should follow the same format if you were to find the model.
IE:
{
type: {
id:12312,
property:'value',
otherProperty:'value'
}
}