I've a route which user can pick more options for your account. But when I enter on this route, ember send a GET to my API. How I avoid this since I've the information I need.
I'm using Ember JS 2x.
import Ember from 'ember';
export default Ember.Route.extend({
searchPlaces: Ember.inject.service(),
model() {
return this.store.findAll('user');
},
afterModel(model) {
let token = model.get('token');
let places = model.get('places');
this.set('places', places);
this.set('token', token);
}
});
First, I recommend reading the DS.Store API docs. There are four methods that seem relevant:
findRecord -- returns a Promise, tries memory first, then an API call
findAll -- like findRecord, but for all records of a type
peekRecord -- returns the record if it's in memory already, or null if not; doesn't make an API call
peekAll -- returns an Array of the records of a type that are already in memory
I suspect you want to call store.peekRecord or store.peekAll in your route if you want to avoid the API lookup.
If you access some relationships of that account in "some route" template it might need to lazy-load them and that's why GET request could fire.
If you want to get rid of that request you could override model of some route and make sure you don't use store.find there.
Related
I have an API in ExpressJS and a middleware that gets executed before each endpoint controller:
app.use(segregationMiddleware);
app.get('/some-endpoint', controller1);
app.get('/some-endpoint-2', controller2);
The segregationMiddleware is used to look for some parameters in the request and then it calculates a value that then is stored in the request object as req.locals.domain so the controllers can access it.
In each Mongoose model, I define a field named domain using a Mongoose plugin (so I don't have to do it every time). That field is used to segregate my assets. This means that when the segregationMiddleware populates req.locals.domain = 'foo' for example, if I make a model.find({}) I want to get only assets that have { domain: 'foo' }. Same thing if I try to update, save, delete, and so.
Of course, I can just simply modify the query on each controller since I have accesso to req, but I need to do it every time and I need to remember it for finds, findAndUpdate, save, and soo... sooner or later I'm gonna forget it.
I can define some hooks in Mongoose that will modify the query using a plugin so it adds the domain constraint to the query so I don't have to do it in the controller BUT I don't have the current req object in the Mongoose plugin unless I pass it, and the only way that come to my mind is to abstract the DB methods in the plugin, so in the controller, I do something like this:
model.safeFind(req, query);
And in the plugin I define safeFind like:
safeFind = () => {
const theRealQuery = Object.assign({}, query, { domain: req.locals.domain });
return this.find(query);
}
BUT, in this way, I need to redefine each DB query function (find, findOne, update, save...) and I need to remember to use the safe methods. Then again, I'm going to forget it sooner or later.
Is there a way I can still use the regular Mongoose methods from the controller and have the plugin somehow modify the query for every method using the current req object?
I was asked to make API call to send data.
On Click in vue, I was firing this event
async facebookDataToSend () {
let campaignID = await this.$store.getters['CurrentInstance/id']
this.$axios.post(process.env.API_BASE_URL + 'faceeBookCampaign', { campaignID: campaignID }, { withCredentials: true })
},
But then, I was told to use API functions which already exsist in some xyz.js file.
My xyz.js file looks like this..
const rest = {
something: axios.create({
baseURL: process.env.API_BASE_URL,
withCredentials: true
}),
setClient: function (client) {
this.something = axios.create({
baseURL: process.env.API_BASE_URL,
withCredentials: true,
params: {
__somethingClient: client
}
})
this.client = client
}
}
Here, I am unable to comprehend how can I use this instance to make an api call So I viewed the code where they have already made the api call and saw something like this
const API = {
url: '/whateverHtml/',
method: 'post',
withCredentials: true,
data: {
'schemaType': 'something-event', // TODO FIXME
'field': 'description', // TODO FIXME
'html': this.model[this.field.key]
}
api.something.request(API).then(result => {
And I wasn't able to comprehend the code. For starters
What is request? I don't see my any method or property inside something in my rest variable
second why are they using withCredentials: true in their API object when they have already set up the property as true in rest object]
What are the pro's of using axios.create({ i.e what they are doing than what I initially did this.$axios.post(
request is a method defined by axios. Link to docs.
request allows you to make an HTTP call with any verb you want (POST, GET, DELETE, PUT). Most likely axios calls request from inside all the other helper methods (get, post), but this is an implementation details. One of the advantages of using request is that you don't have to hardcode the HTTP verb (POST, GET ...) and you can set it at run time depending on your input.
I see 2 reasons why they would set withCredentials:
setClient may or may not be called before something
for clarity: it's enough to look at the definition of something to realise that the client is using credentials and you don't need any extra information about how rest works.
I don't think the request for you to use something boils down to advantages of axios.$post vs axios.create. It's probably related more to how to organise your code.
Some advantages of using a separate module vs calling axios directly
when calling axios directly you are prepending base url all the time, when using a module for your REST API the base URL is tucked away and arguably makes your code easier to read
you can bake other options inside config and make sure they are used. For instance you may have an access token, the module can store that token and always added to any request. When calling axios by hand you need to remember this
you are decoupled from axios (to some degree)(1). When using a module you don't actually care if it's axios doing the requests or not.
You can add more API calls to the module that you can reuse in the future. I'm expecting xyz file to grow in time and your call to faceeBookCampaign to end up being a method on the rest variable. It makes more sense to end up using this.client and not something but this is up to the devs.
it keeps all the REST API calls in one place allowing you to build an SDK for that API, which as the project grows can have its own life cycle.
(1) I say that id decouples you to some degree because there are semantics that need to be kept so everything works. The returned object needs to have a request method that accepts a config object. The config need to conform to the same structure as the one that axios wants. But, you can always write an adapter for that, so you are actually decoupled from axios.
request here takes a config and returns a promise. I am guessing this approach is usually taken when you want to reuse a request object that is created using create (at least my sense).
I feel the request method is used to overwrite the initial configuration with new one defined in API. And, the double withCredentials should be an oversight.
OR, because API is defining a new config object, therefore when defined without withCredentials, it would overwrite the create's configuration.
Hence, it looks like its specified twice.
Ember 2.17
I am calling an helper from my template :
{{#each invoice.invoiceLines as |line| }}
{{pricings/full-pricing line.pricing}}
{{/each}}
invoice,invoiceLine, as well as pricing are ember models.
Here is how invoice is created in model () :
model(params) {
let invoice= this.store.findRecord('invoice',params.invoice_id)
return Ember.RSVP.hash({
invoice: invoice,
allShares: invoice.then((i)=>{return i.allShares()}),
detailShares: invoice.then((i)=>{return i.detailShares()})
});
}
The goal of the helper is to take pricing, extract numbers (everything is in the model, no more relations) and return a string formatting the initial price and the subscription price.
The helper is as following :
import { helper } from '#ember/component/helper';
export function pricingsFullPricing([pricing]) {
return pricing.then(
p=>{
debugger
},p=>{
}
)
}
export default helper(pricingsFullPricing);
When I run the page, debugger is called twice (the template loop run once).
First time p is null, the second time it is a pricing.
Isn't then supposed to prevent that? Why does it behave like that?
Your route is wrong, routes are promise aware (that's what hash is for), it should be:
model(params) {
return Ember.RSVP.hash({
invoice: this.store.findRecord('invoice',params.invoice_id)
//allShares: invoice.then((i)=>{return i.allShares()}),
//detailShares: invoice.then((i)=>{return i.detailShares()})
});
}
Then your handlebars is just:
{{#each model.invoice.invoiceLines as |line| }}
{{line}}
{{/each}}
You also shouldn't call methods like you are on a model. It's not really clear what allShares(), etc does but these should (probably) be computed in the controller. Something along the lines of:
import { computed } from '#ember/object';
export default Controller.extend({
allShares:computed('model.invoice', function(){
return this.get('model.invoice').allShares();
});
});
Though this doesn't seem ideal. Like I said, it's hard to be explicit as it's not clear what your trying to do here. It'd probably make more sense if your extracted these methods into a service.
You then don't need the helper at all. This appears to be just trying to work around promises.
It makes life a lot easier if you try and load all server side data in the route before load.
First rule of helpers
Each time the input to a helper changes, the compute function will be called again.
Second, there's nothing about helpers that will make this block subsequent calls because you are returning a promise.
export function pricingsFullPricing([pricing]) {
return pricing.then(
p=>{
debugger
},p=>{
}
)
}
You've created a simple helper here that will use the promise itself as the value. Look at ember-promise-helpers/await to see how a class based helper is used to manually set the value that's displayed in the template.
Now, if you're wondering why the recomputation is happening, I'm going to have to speculate based off the knowledge I have of Ember data just from being part of the Ember community (I've never actually used Ember Data). You know line.pricing is a promise? I can then assume your using some sort of relationship, which will most likely have to be loaded via an ajax call (hence the promise). But these relationships in Ember data, iirc, use this PromiseProxyMixin that allow them to behave simultaneously like a promise or like an object (depending on whether the data is in the store already or not). This is what allows you to reference the promise in your template without then
See this article for a better understanding of what I mean
I have the following code in ember 2.6; ember-data 2.6.1
import Ember from 'ember';
export default Ember.Route.extend({
activate() {
var route = this;
var sessionId = localStorage.getItem('sessionId');
if (sessionId) {
localStorage.removeItem('sessionId');
this.store.findRecord('session', sessionId).then(function found(session) {
session.destroyRecord();
route.transitionTo('index');
});
} else {
this.transitionTo('sessions.new');
}
}
});
I have a logout button that has hbs template code as:
<li>{{#link-to 'sessions.delete'}}{{fa-icon "fa-lock"}} Logout{{/link-to}}</li>
The Route.extend code is executed when /sessions/delete is called!
What I observe is the order of REST calls are:
1) ***DELETE*** http://dozee.me:3000/api/sessions/<sessionId>
2) ***GET*** http://dozee.me:3000/api/sessions/<sessionId>
The second REST request throws and error because by that time the session/cookie is already cleaned up.
What I expect is the order of the REST calls should actually be reverse but I am unable to figure out why is it not like that!
Any pointers & hints will be appreciated ;)
this might be because ember already have that session on the store and returning that object to you and trying to update the object later via making a GET call.
which can happen after delete because promise was already resolved with store object.
What u can do is look for session object in store first with peekRecord and make findRecord call only if object in not found in store.
Other way would be make a forsed server call for findRecord for session which wont get resolved untill object is returned from server.
Hope this helps you.
I'm make a search for a application in Ember 2 which my backend only accept a POST for this search, so Im trying send data through customize createRecord, but the behavior is completely different from I'm expected, two points I believe be a problem.
After several console.log(), I see my actions don't work, even action setted in route.
Inside Ember Inspector the route for this search haven't a model related
Anyone have a hint about why my route don't have a model related, follow the model declaration for this specific route.
model() {
return {
data: this.store.findAll('booking'),
booking: {}
};
}
PS: I edited the title, to be more clear about I need.
I believe you need to use Ember.RSVP.hash for that:
model() {
return Ember.RSVP.hash({
data: this.store.findAll('booking'),
booking: {}
});
}