Ember Data override find method - ember.js

I need to override the find() method in ember-data to make it compatible with my app. Its not a huge modification that I have to do, but I don't know where to start.
So far when I try to do this : this.store.find('enquiry'); Ember-Data is trying to fetch information from http://localhost/enquiries instead of http://localhost/enquiry. My problem is that I don't need to get the plural of my url..
I thought also using the jquery method but, I would rather using Ember-Data for this. How can I do that ?
Another question : After this is working, is Ember-Data generate dynamically the model in the app ? Because I have a lot field in my JSON and I can't write them down manually...
Can I do something like this :
App.Store = DS.Store.extend({
adapter: '-active-model'
});
App.Enquiry = DS.Model.extend();
Thanks for your help !

This page will show you exactly how to use a custom adapter in your application. And this page will show you how to override a method in your subclass.
I didn't see your response on the Ember forum yesterday, but in my opinion, you'd still be better off writing your own adapter. It seems like you're going to do more work trying to modify the REST adapter than if you just created your own.
But if you still want to extend the rest adapter, here is how:
App.ApplicationAdapter = DS.RESTAdapter.extend({
find: () {
//...
}
}):
As for your second question, no, Ember-Data will not pick up the fields automatically. I'm pretty sure it'll throw an error if you include fields in your JSON that are not declared in the corresponding model. This is by design. If you don't know your fields at development-time, how can you use them in templates or controllers?

Related

Not possible to use shorthand route handlers if RestSerializer is used? (ember-cli-mirage)

I set up a simple Ember Twiddle to show you my error that is occurring when trying to update a model.
It's considerable that I'm using ember-cli-mirage for mocking the data.
According to the docs, I created a shorthand route that should handle the PUT request.
It does, but with the error: Your handler for the url /api/shops/1 threw an error: Cannot convert undefined or null to object
When using the JSONAPISerializer, everything is working with shorthands (mirage/config.js) and I'm able to update models, but in my case I have to use the RESTSerializer with serialized IDs in the responses.
The request payload when I'm sending the model's attrs are without Id at the end of the property name, f.e.:
// attrs object in PUT request
{
name: "Shop 1",
city: "1" // belongsTo relationship,
}
Now Mirage is trying to find those properties on the respective database model that has to be updated, but cannot find it, because in the database it's cityId and not just city...
I also found this issue report and it’s working, but I was hoping I could avoid something like this. As far as I can remember, in previous versions of ember-cli-mirage (v0.1.x) it was also not needed to override the normalize method in the serializer to be able to make use of the RestSerializer with serializedIds…
My question is:
Is there a way to stick to shorthand route handlers only, or do I really have to write a helper or other custom solution only because I have to use the RestSerializer?
That would be really sad, but at least I would know then.
Thanks for your support!
Short answer: it looks like you need the custom serializer for now until the bug fix for it is merged.
Long answer: that issue looks to be an issue that occurred in the 0.2 -> 0.3 upgrade for Mirage, likely because of underlying DB changes made in Mirage. It'll probably get fixed, but for now you'll need to work around it.

Fetch new data from API in jQuery plugin's callback

I am new to ember, so please treat me like a fool. What I'm trying to do first is to understand the concept.
In my application I heavily rely on few jQuery plugins they fetch new portion of data in their callbacks, that's how these plugins are designed, but I am not sure how can I trigger them to fetch a new portion of data from API passing to API updated query parameters after plugin has been rendered.
I have wrapped the plugin in a component, in component's template I send data to it as (I use emblem.js syntax here)
= plotly-chart chartData=model
In model I have
//app/models/data-points.js
import DS from 'ember-data';
export default DS.Model.extend({
// time: DS.attr(),
ch1: DS.attr(),
ch2: DS.attr(),
ch3: DS.attr(),
temperature: DS.attr(),
});
And then in component itself I fetch data
//app/components/plotly-chart.js
dataPoints: Ember.computed.map('chartData', function(item){
return item.getProperties('ch1', 'ch2', 'ch3', 'temperature');
}),
and make some manipulations with data, which isn't so important for the question itself.
Ah, and I have a route graph/ which later calls that component
//app/routes/graph.js
import Ember from 'ember';
export default Ember.Route.extend({
queryParams: {
start_timestamp: {
refreshModel: true
},
end_timestamp: {
refreshModel: true
}
},
model(params) {
return this.get('store').query('data-point', params);
}
});
So as you see I have tried to fetch new properties via query params, finally it works great if I just update the url in browser, but now can I trigger new call to API and fetch new data and get this new data in a component itself?
Also I'm struggling to understand what role controllers play in all of these. It is mentioned that controllers will be deprecated soon, but still used here https://guides.emberjs.com/v2.10.0/routing/query-params/
My code seems to work without controllers, so this is really confusing.
Also I suspect maybe I should use services for what I'm trying to achieve, but not sure how.
Ember experts, could you please point me into a right direction? The most important thing is how to fetch new portion of data from API with updated query parameters (query parameters to API itself, not nessesarely the ember application, but I suspect in ember-data it is the same thing? or not %) %) %)).
UPDATE 1
Really I should use services for that, shouldn't I? Pass arguments into a service and query a store there. Would that be a correct pattern?
Then query parameters in url are not the same as querying the store and is an independent thing. Am I right?
but how can I trigger new call to API and fetch new data and get this new data in a component itself?
If you change your queryParam values in a controller using an action (combined with your current route setup) it will adjust your route and re-call your API, as the values are bound together to make this particular use case simple :-) You're about 98% of the way there ... :-)
Re controllers going away, they won't for a long time as the replacement hasn't been worked out yet. You could do some of this in a service if you want to, but there is no need as you are almost done.
Thanks, that make sense though. I just worried I'm doing it wrong.
By they way finally I found a way to access store from the controller Access store from component but:
1. I was unable to take out the data from that variable, probably it's me being stupid.
2. I double it's the right way to access store directly in a component and better to use services for that or rely on “Data Down Actions Up” (DDAU) paradigm?
Finally I was able to fetch new portion of a data calling a controller's action from within the controller, but then the next problem raised - the data was updated, but the JS code did not know about that because I feed the jQuery plugin with this data and it did not pick up changes automatically. I think I might be doing it a wrong way there %)
But finally I get it working by adding an Ember's observer to that variable and in observer calling a redraw function (for chart in this particular place).
#acorncom Thanks!

How to get Ember Data's "store" from anywhere in the application so that I can do store.find()?

With the recent update, I know that in routers and controllers, I can easily just do this.store.find('model'). However I have some functions that need to call find that are not in routers and controllers. So how can I get an instance store from anywhere in an Ember App?
I know worst comes to worst I can do App.__container__.lookup('store:main'), but I'll try to stay away from that.
The TRANSITION doc says that you can do this to inject the store into components :
App.inject('component', 'store', 'store:main');
You might be able to change 'component' to 'view' or to 'model', but I'm not sure about that.
You can do
App.Model.store.find('model')
If you have a particular attribute to filter with, you can do:
App.Model.store.find('model', {'attribute_name' : 'matching_to_this_value'})
See more on this post.
You can try to do
this.get('controller').get('store').find('model')
That would wok in a View for example.
With Ember Data 1.0.0-beta.X:
App.YourModelType.store.find("yourModelType", someId).then(
function(modelInstance) {
...
});

ember-data adapter to read from cloudant RESTful API

The cloudant RESTful API is fairly simple but doesn't match the way ember-data expects things to be. How can I customize or create an Adapter that deals with these issues...
In my specific case I only want to load records from one of several secondary indexes (ie. MapReduce fnctions).
The URL for this is below, where [name] and [view] would change depending on user selection or the route I am in.
https://[username].cloudant.com/[db_name]/_design/[name]/_view/[view]
Looking at the ember-data source there doesn't seem to be an easy way of defining URLs like this. I took a look at findQuery and it expects to send any variables through as url params not as part of the actual URL itself.
Am I missing something? Is there an obvious way of dealing with this?
Then the data comes back in a completely different format, is there a way to tell ember what this format is?
Thanks!
I had similar problem where URL's are dynamic. I ended up creating my own adapater by extending DS.RESTAdapter and overriding the default buildURL method. For example:
App.MyAdapter = DS.RESTAdapter.extend({
buildURL: function(record, suffix) {
var username, db_name, name, view;
// Do your magic and fill the variables
return 'https://'+username+'.cloudant.com/'+db_name+'/_design/'+name+'/_view/'+view;
}
});
I ended up also defining my own find, findAll, findQuery, createRecord, updateRecord, deleteRecord etc. methods as I had to pass more variables to buildURL method.
If returning data is in different format then you can also write your own serializer by extending DS.JSONSerializer and define your own extraction methods extract, extractMany etc.
You should evaluate how well your API follows the data format required by ember/data RESTAdapter. If it is very different then it's maybe better to use some other component for communication like ember-model, ember-restless, emu etc, as ember-data is not very flexible (see this blog post). You can also write your own ajax queries directly from routes model hooks without using ember-data or other components at all. It is not very hard to do that.

Can I specify a Store on a Ember js model?

I am trying to use multiple stores in Ember because I have namespaced models on the api side.
Aka
App.Gl.Account = DS.Model.extend //Needs to route to /gl/accounts
App.Company = DS.Model.extend //Routes to /companies
My first thought was to define a namespace
App.Gl = Ember.Namespace.create({});
//and a store
App.Gl.Store = DS.Store.extend({adapter:DS.RESTAdapter({namespace:'gl'})});
App.Store = DS.Store.extend({adapter:DS.RESTAdapter})
problem is the model is automatically binded to the App.Store.
Any other suggestions on how to accomplish namespaced models would be helpful. I dont even need them namespaced on the client js side, as long as there is an easy way to specify the namespace for each individual model
You should never have more than one store in an Ember application.
Instead, you can register adapters for specific types:
App.Store.registerAdapter('App.Post', DS.RESTAdapter.extend({
// implement adapter; in this case
url: "/gl"
}));
You will probably want to use the RESTAdapter as a starting point, unless you have specific needs and are willing to get down and dirty with the (still evolving) adapter API.
In newer versions of ember (I'm running 1.5.0-beta.1+canary.13995621, and 1.4 also seems to lack the registerAdapter method) the api has changed a bit, the registerAdapter method is gone.
Now if you would like a non default adpter for a model you can define a App.<ModelName>Adapter and that will automatically be used for that model.
So if you have a Post model and you would like to define the namespace for that model, I think that would be:
App.PostAdapter = DS.RESTAdapter.extend({
namespace: 'gl'
})
There's no longer a registerAdapter method.
For Ember 2:
Model-specific adapters can be created by putting your adapter class in an app/adapters/ + model-name + .js file of the application.
Source: DS.Adapter Class