I am trying to implement a dynamic highcharts that changes every time a new model comes in. In ember-highcharts documentation, they explain that all needs to be done is implement the EmberHighChartComponent and implement a contentdidchange observer that observes the model and would change the graph when the model changes
details here :
https://github.com/ahmadsoe/ember-highcharts#overriding-chart-redrawing
So when I implement it, it works perfectly and graph changes when there is new content, but as soon as I try to navigate somewhere else on the page, it throws this error:
Even when I emptied the component this happens, which tells me that the problem is in EmberHighChartComponent
this is what I have after emptying the component
dynamic-chart.js
import EmberHighChartsComponent from 'ember-highcharts/components/high-charts';
export default EmberHighChartsComponent.extend( {
});
dynamic-chart.hbs
{{high-charts mode=mode chartOptions=chartOptions content=content}}
The Error that I get:
TypeError: undefined is not an object (evaluating 'chart.renderTo.removeAttribute')
Any ideas whether this is a package issue or I am misunderstanding the implementation ?
Remove dynamic-chart.hbs file. You extending a component, not wrapping it.
Related
Working with an older ember application (2.18.1). The following problem is repeated too many times to all fix in the time frame I got available right now.
The component is loading it's own data (setting this.get('model')) and all works fine.
However as the database is now a little slower the user sometimes click on one link, where the template render the component and it start loading it's data .
If the user click another link (to a route that does exactly the same) data from both the previous and the "new" component get loaded.
I can't reset the model when data get loaded, since the fetchRecord method that loads the data get called over and over with paging (as the user scroll down).
I'm sure I'm just not thinking of an obvious solution (did not work on Ember for a few years), any advise?
(ps: some of these components does not use paging, in mean time I'm going to clear out the model before setting it to what the api returns)
I'm afraid ember-data gives no support to abort a request, but you can handle that yourself directly on your component calling the endpoint through Ajax or fetch, and then pushing the payload or aborting requests using the lifecycle hooks. For example, you can trigger the abort() on the willDestroyElement hook.
import $ from 'jquery';
import Component from '#ember/component';
export default Component.extend({
init() {
this._super(...argument);
const xhr = $.get( "ajax/test.html", (data) => {
this.get('store').pushPayload(data);
});
this.set('xhr', xhr);
}
willDestroyElement() {
this._super(...argument);
this.get('xhr').abort()
}
});
I am trying to implement searching with ember-infinity. But, I do not understand the interaction between the route model and infinityModel.
I have the following code:
model() {
...
return this.infinityModel("myModel", {...}, {...})
}
My search action looks like the following:
search(searchCriteria){
const controller = this.get('controller');
...
_this.infinityModel("myModel", {search:searchCriteria, ...}, {...}).then((myMod)=>{
...
controller.set('model', myModel);
});
}
So this works, but the my query gets fired twice when search is called.
The following only fires the query once.
search(searchCriteria){
const _this = this;
...
_this.infinityModel("myModel", {search:searchCriteria, ...}, {...});
}
But my model does not update. However infinityModelUpdated() function is fired. So I assume that means the infiniteModel was updated, which I assume is my model.
I am pretty sure I am missing something simple. But any help would be greatly appreciated.
Just calling the following:
_this.infinityModel("myModel", {search:searchCriteria, ...}, {...});
does not solve your problem; that is because that method call just returns fresh set of new objects retrieved; which is irrelevant with your original model that you had already returned from model hook. In other words; that method call makes the remote call but does not push the objects retrieved to the model that is already returned from the hook method. If you instead set the model of the controller; then of course the new data is updated to the screen; but I am not sure why a second remote call is being made. That might be related with existence of an infinity-loader already existing in your screen.
What I would suggest is to use updateInfinityModel provided instead of setting the model of the controller. Please take a look at the twiddle I have provided. It uses ember-cli-mirage to mock data returned by the server. Anyway, our point is looking at the makeInfinityRemoteCall action.
this.infinityModel("dummy", { perPage: 12, startingPage: 5}).then((myModel)=>this.updateInfinityModel(myModel));
Here a remote call is made upon button click and data is appended to the model already constructed in model hook. I hope this helps you clear things. Please do not hesitate to alter the twiddle yourself or ask further questions you have.
After your comment, I have updated the twiddle to change the model directly. The duplicate remote call that you have mentioned does not seem to be appearing. Are you sure an exact duplicate remote call is being made? Can it be just the case you are using infinity-loader at your template and a remote call for the next page is being made due to appearance within the view port?
Given a route it is easy enough to get Ember to navigate to an error route if the model promise rejects. Currently I have the simple method of having an error.hbs and /routes/error.js, and if the model promise errors it loads the error page.
I have a situation where the model resolves fine, but one of its relationships does not. This relationship is used in the routes template e.g.
{{#each model.addresses as |address id|}}
{{address.line1}}
{{/each}}
So myurl.com/api/addresses/1 returns a 500 error. I see this in the console window, but Ember does not automatically transition to the error page. How can I get it to do this for all promises that reject as a result of a template requesting more data?
One solution would be to return RSVP.Promise in route model() which loads all data (also relationships instead of lazy loading them later by template) and rejects if any of asynchronous requests fail.
Ember generates the error pages by it self if im not wrong, if ember depends on an DS.error object for the transition you have to fulfill the requirements in order to get Ember to recognize an valid error, in Ember 2.x the error code MUST be 422 and has to follow jsonapi http://jsonapi.org/format/#errors-processing
I wrote up a long post on using Route error substates here -> https://pixelhandler.com/posts/emberjs-handling-failure-using-route-error-substates
So ultimately, error handling happens as the result of knowing "what broke" and "who owns the fact that it broke". Generally, if X asked for Y and Y fails, its X's job to display the error. In that example, if FooRoute triggers an ajax, and it fails, FooRoute more or less should handle the error.
But when it comes to the template causing fetches, it actually becomes the responsibility of the template.
One thing one can do is, actually bind to the various boolean properties representing the async operation on the PromiseProxy (in your case, model.addresses). The properties are as follows
isPending - ongoing work is happening
isFulfilled - it is done, and succeeded
isRejected - it is done, but failed
isSettled, - it is done (failed or succeeded)
using these flags could be as follows
{{#if model.addresses.isPending}}
loading...
{{else if mode.addresses.isRejected}}
Sorry something went wrong, {{model.addresses.reason.message}}
{{else}}
{{#each model.addresses as |address| }}
...
{{/each}}
{{/if}}
When loading data for a page, I like to ask myself, what data is critical to show? That is, if there are three sections on the page -- say backed by foo, foo.bars, and foo.baz -- are all three sections of highest priority? Or can I let one of them fail and show the other two? Let's assume that without either foo or foo.bars, we show an error page, but foo.baz is optional. In that case, I would write that as
// controller:foo
model(params) {
return this.get('store').find('foo', params.id);
},
afterModel(foo) {
return foo.get('bars'); // block on foo.bars fetch
}
Then I might have a {{foo-baz}} component that renders Loading... at first, then fetches foo.baz in the background and shows the full content later.
I am new to ember.js, I am trying to save the model from another contoller where i have am able to get all the information of the model. Whenever i try to save the model using the code below
saveModel: function(model) {
model.save();
},
I am getting this error
Uncaught TypeError: model.save is not a function
Any idea how to solve this error?
Model information is getting passed from components using this.sendAction().
this.sendaction() should be CamelCase -> this.sendAction()
Check the Ember Guides for Components -> Handling Events to make sure you are using this.sendAction() correctly
Make sure by debugging that model is being passed correctly from the component.
Had the same error.
Using _internalModel works but is an ugly solution. My mistake was binding the model to the promise
this.set('prop', this.get('store').findRecord('model', id))
and not use
this.get('store').findRecord('user', this.selectedUser.id).then(function(model) {
self.set('prop', model);
});
Hope that this helps someone having the same problem.
I'm trying to figure out Ember.js and keep hitting what seems like basic problems that are not documented in a way I understand.
I want a object to manage a list of stuff. ArrayController seems to make sense. I assume having that controller load the data from the 3rd party server (youtube) makes the most sense. So My plan is to write some custom functions in the controller to load the data.
App.videoController = Ember.ArrayController.extend({
loadSomeVideos() {
console.log("I have run");
}
});
after I run the above code App.testController.someFunction() does not exist. Why not? I feel like I am missing some basic concept.
When you call Ember.ArrayController.extend, you're actually just extending the class not creating a concrete instance, therefore you can't call loadSomeVideos.
There are a few conventions in Ember that can get you stumped if you're unaware of them. As commented by "Unspecified", you should use the following convention to extend the class.
Please note the upper case VideoController and also the way in which I'm defining the loadSomeVideos method:
App.VideoController = Ember.ArrayController.extend({
loadSomeVideos: function() {
console.log("I have run");
}
});
Now, if you want to run this, you need to create an instance of the App.VideoController class. Once again notice the capitalisation:
App.videoController = App.VideoController.create();
So, I use a lower case v for the instance, and an upper case V for the class. I've just created an instance (App.videoController) of the class (App.VideoController).
To call your method, you need to call it from the instance, like this:
App.videController.loadSomeVideos();
Check out the following two pages in the documentation.
This first page gives you some info about extending classes and then instantiating them so you can call their methods:
http://emberjs.com/guides/object-model/classes-and-instances/
The second page goes into a bit of depth about more advanced methods reopen and reopenClass.
http://emberjs.com/guides/object-model/reopening-classes-and-instances/