Where to include client-side js that uses data from Ember-Data?


#1

I have an existing Express/AngularJS application that I am working to port to Ember. This application pulls data from a server, then displays it in the form of a Plotly plot. In the original implementation I started with a page template (like this) which contained a javascript section like

Plotly.plot( TESTER, [{
  x: {{xdata}},
  y: {{ydata}}
}]);

When the user requested the page I would fetch the data and feed it to the template server-side so that the user was served something like

Plotly.plot( TESTER, [{
  x: [1,2,3],
  y: [1,4,9]
}]);

With Ember and Ember-Data, I can pull the same data into an Ember model, and if I want render those same arrays as text in the page using handelbars. However, I haven’t been able to determine the proper Ember way to:

  • Include the plotting script in the page that is served to the client (or get the same effect somehow).
  • Hand the data off to that script

I think I’m sticking too closely to how I did this previously. What should this look like in Ember, or is this out of scope?


#2

Do not try to inject that into a script tag on the page! Get the data via ember data, then initialize the plotly object in Ember. Something like this:

let xArray = [];

store.findAll('some-thing').then((things) => {
    things.forEach((thing) => {
        xArray.push(thing.get('valueForChart');
    });

    Plotly.plot(TESTER, [{
        x: xArray, // created from ember data
        ...
    }]);
});

What’s happening? You’re asking the store for the data, THEN working with Plotly, after you get the data you need.

Ideally you’d do that in a component. You can access the DOM of your component via this.$(), if you need to initialize the plotly DOM, or whatever.

Read this: https://guides.emberjs.com/v2.5.0/components/the-component-lifecycle/

But seriously… don’t try to generate the script tag.


#3

This seemed cryptic at first, but started making sense after I began to play around with it – thanks! I now have it working either as a component with something like

import Ember from 'ember';
/* global Plotly */

export default Ember.Component.extend({
  store: Ember.inject.service(),
  didInsertElement() {
    this._super(...arguments);
    //var store = this.get('store');
    //console.log(store);
    Plotly.plot( 'tester', [{
    x: [1, 2, 3, 4, 5],
    y: [1, 2, 4, 8, 16] }], {
    margin: { t: 0 } } );
  }
});

or in a page route with something like

import Ember from 'ember';
/* global Plotly */

export default Ember.Route.extend({
  activate () {
    Ember.run.scheduleOnce('afterRender', this, function() {
      Plotly.plot( 'tester', [{
     x: [1, 2, 3, 4, 5],
     y: [1, 2, 4, 8, 16] }], {
     margin: { t: 0 } } );
    });
  }
});

One more question – is there any real reason to use a component rather than the route if I’m not using the component on more than one page? It seems that in my case, the route seems like a more natural home for this so I don’t have to generate a component for each of the pages that has the plot, and it has easier access to the store.

Edit: Specifically, if I use a component, how should I pass the entire model that the route receives to the component? (In my case, both the route and the component that contains the plot need access to the model).