I want my model to reload when the queryParams has changed. queryParams change is reflecting in the URL but model reload is not happening. I followed the ember.js guides (https://guides.emberjs.com/v2.6.0/routing/query-params/) on making full-on transition. I've my queryParams declared in my controller
//controllers/service/service.js
import Ember from 'ember';
export default Ember.Controller.extend({
queryParams:['showFriends']
});
//routes/service/service.js
model(params){
return this.store.query('service', params);
},
actions:{
updatePage(params){
this.transitionTo('service',{queryParams:{showFriends:params}});
},
},
queryParams:{
showFriends:{
refreshModel:true
}
},
I'm calling updatePage from a component which passes params as true or false based on a checkbox selection. The component is called from application.hbs file as below
{{test-component model=model updatePage="updatePage"}}
If I remove refreshModel:true from my route, I see the URL is updating but my model is not reloading (as expected according to the docs).
Since, I'm doing a full-on transition I added the line refreshModel:true which gives me error
ember.debug.js:32096 TypeError: this.refresh is not a function
at Class.queryParamsDidChange (ember.debug.js:26286)
at Object.triggerEvent (ember.debug.js:28580)
at Object.trigger (ember.debug.js:53473)
at fireQueryParamDidChange (ember.debug.js:52255)
at Object.queryParamsTransition (ember.debug.js:51983)
at Object.getTransitionByIntent (ember.debug.js:51913)
at Object.transitionByIntent (ember.debug.js:52018)
at doTransition (ember.debug.js:52590)
at Object.transitionTo (ember.debug.js:52087)
at Class._doTransition (ember.debug.js:28291)
I spent more than 2 days on this issue but of no use. Anybody who has faced this similar issue or has any idea on how to solve this would be a great help to me. Thanks in advance
Put queryParams:{
showFriends:{
refreshModel:true
}
} in corresponding route.
Routes are responsible for fetching models, so it should be there
Answering my own question, thought if somebody is facing the same problem. Solution is simple but you know finding out the right spot is the difficult task.
I've a service injected into all of my routes and the name of the service is "refresh". When I call refreshModel:true in the route as we all know ember in the backend calls this.refresh() method.
But, here in my case, a service with refresh name is already been injected in the application, ember is not calling this.refresh() method of the route instead calling the injected service which is obviously not a method.
So, it is throwing me a error this.refresh is not a function. Ember would've have given the error more specifically but again its hard for anyone to expect this scenario. Anyways, thanks for all who gave the solutions which directed me in the right path.
Related
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!
--Using Ember Data 2.7.1--
I am trying to reverse the order of a collection of records without first turning them into an array using toArray(). This collection of objects comes from the promise returned by this.store.findAll('history-item').
I want to do this the ember way instead of making them plain javascript. I am getting a TypeError: internalModel.getRecord coming from record-array.js. For some reason when it is trying to do objectAtContent(), the content it is looking seems to not have a type. Through the stack trace I can see that the object I am dealing with is [Class], class being the history-item model. A few stack calls before the objectAtContent(), the object being dealt with switches from that history-item model to some other Class object that has no type attribute.
I am able to use Ember Inspector to see my data correctly, and if I just displayed the original collection of records on my template, it shows properly.
Has anyone run into this?
Some thoughts and considerations:
-Is there anything special about how findAll() works with its promise that doesn't allow for reversal since it is reloading in the background? I do want it to keep reloading live data.
-I am using ember-cli-mirage to mock my db and endpoints and I've follow the instructions to the letter I think. I am using an unconfigured JSONAPISerializer for mirage and and a unconfigured JSONAPIAdapter for ember. Could it have anything to do with metadata that is being sent from the back? Could it have something to with the models or records not being set up? Is there something special I have to do?
Route Segment that defines model and tries to reverse it:
[note: I know it may not be convention to prep the data (ordering) in the route but I just put it in here for ease of description. I usually do it outside in the controller or component]
model(){
return this.get('store').findAll('history-item').then(function(items){
return items.reverseObjects();
}).catch(failure);
History list model declaration:
export default DS.Model.extend({
question: DS.attr('string'),
answer: DS.attr('string')
});
Ember-Cli-Mirage config.js end points:
this.get('/history-items', (schema) => {
return schema.historyItems.all();
});
Ember-Cli-Mirage fixture for history-items:
export default [
{id: 1, question: "1is this working?", answer: "Of course!"}
}
Error:
TypeError: internalModel.getRecord coming from record-array.js
This issue also happens when I try to create a save a record. The save is successful but when the model gets reloaded (and tries to reverse), it fails with the same error. It doesn't matter if I the fixture or not.
Controller:
var newHistoryItem = this.store.createRecord('history-item', {
question: question,
answer: answer
});
newHistoryItem.save().then(success).catch(failure);
The result returned from store.findAll and store.query is an AdapterPopulatedRecordArray (live array), mutation methods like addObject,addObjects,removeObject,removeObjects,
unshiftObject,unshiftObjects,pushObject,pushObjects,reverseObjects,setObjects,shiftObject,clear,popObject,removeAt,removeObject,removeObjects,insertAt should not be used.
Have a look at corresponding discussion and
Proposed PR to throw error and suggestions to use toArray() to copy array instead of mutating.
I think using toArray is fine, no need to reinvent the wheel. Even Ember's enumerable/array methods are implemented using toArray under the hood.
I like keeping transforms on controllers/components, so Routes are only concerned with [URL -> data] logic. I think here I would keep the model hook returning the server data, and use a computed property on the controller:
import Ember from 'ember';
export default Ember.Controller.extend({
reversedItems: Ember.computed('model.[]', function() {
return this.get('model').toArray().reverse();
})
});
Twiddle: https://ember-twiddle.com/6527ef6d5f617449b8780148e7afe595?openFiles=controllers.application.js%2C
You could also use the reverse helper from Ember Composable Helpers and do it in the template:
{{#each (reverse model) as |item|}}
...
{{/each}}
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) {
...
});
I'm a newbie to Ember Data and I've just switched from FIXTURE data to the RESTAdapter but I don't know enough about how to connect the model and the API's call signature. Specifically I'd like to be able to call an endpoint GET /activities/[:user_id]/[:by_date]. This would load an array of "Activity" objects but only those for a given date.
Router:
this.resource('activities', { path: '/activities' }, function() {
this.route('by_date', {path: '/:user_id/:by_date'});
});
Route:
App.ActivitiesByDateRoute = Ember.Route.extend({
serialize: function(activity) {
return {
userId: 1,
dateBy: "2013-07-01"
};
}
});
First off I tried to hard code the values for userId and dateBy making the adjustments to the Route above. Sadly that did not work. I think I understand why -- although I don't have a quick way to fix this -- but more disturbing for me was that when I manually put in the parameters into the URL: http://restful.service.com/api/activities/1/2013-07-01. The results are quite surprising to me:
Initially the debugging messages suggest a success:
This however, is not correct as no network requests are actually made
If you reload the browser, it will now go out and get the Activities but to my surprise it also goes out to find the specified user. Hmmm. That's ok, the user 1 is pulled back successfully.
The Activity, however, is just a GET /activities call which fails because this endpoint needs the user and date qualifier to work. Why weren't these included in the request?
I don't think ember data supports "composite keys" (which is essentially what you are trying to do). You'd probably need to build your own Ajax for that specific model and implement it in the model hook for that specific route. You can always fetch the data and sideload it into ember-data if you'd like to have an ember data model.
I'm trying to use the new Router API (at commit 6a165ad), and I have some problems.
Given this router:
Router.map(function(match) {
match("/posts").to("posts", function(match) {
match("/new").to('new', function(match) {
match("/author").to('author');
});
});
});
I'm trying to transition to the new route.
Using new.index: this.transitionTo('new.index')
It works, but as you can see the route name is not really explicit (we don't even know that it's for a new post). It's consequently not a viable solution.
Using posts.new: this.transitionTo('posts.new')
I hoped it works, but an error is thrown:
The route posts.new was not found.
I believed the transition to the index was made automatically, but it seems not.
Using customized route name:
Since the commit specified above, Ember allows custom route naming. As my previous attempt does not work, I tried to force the new route to be posts.new, but it still does not work (idem if it was foo.new).
It looks like its not possible to go to a customized route that has nested routes.
TL;DR
I'd like to transition to the new route (and specifying posts). How should it be done ?
Before the router v2.1, I had routes that has child without to (i.e. match("/posts", function(match) { ... })), is it still working ? If so, what's the name of its children ?
This was actually a bug in Ember. Because index is implicit, you should not need to explicitly provide it.
The bug was fixed on master.
If you want to go to a route that has child routes, you should transitionTo the specified name of the route, and Ember will automatically add the index for you.