tarponjargon
tarponjargon

Reputation: 1032

ember-data: having a hard time getting data into the store

I have an existing search app I built on the server-side that uses elasticsearch processed by python/flask. On the client side, it's using JS/jQuery and handlebars to parse and present the data.

I'd like to take it one step further and build it in ember, as the "controls" (filters, sorting, pagination, etc) make it a perfect candidate for an SPA.

I understand the ember fundamentals, but I feel like I've hit a wall with ember-data - i.e. how to get my data into the store so I can bind actions. Can somebody point me in the right direction?

My existing JSON API is accessed like this:

http://localhost:8000/search?q=shirt&paging=18&filter-price=100

and it returns JSON like this:

{
  "aggregations": {
    "breadcrumb": [], 
    "color": [], 
    "price": [], 
    "size_apparel": [],
    "size_jewelry": []
  }, 
  "meta": {
    "agg_list": [], 
    "default_sort": "", 
    "key_translations": {}, 
    "paging": 18, 
    "paging_options": [], 
    "sort_methods": [],
    "from": 0, 
    "hits": 89, 
    "pages": 5, 
    "q": "shirt"    
  }, 
  "results": [
    {
      "creation_date": "", 
      "image": "", 
      "images": {
        "altimg1": "", 
        "large": "", 
        "regular": "/", 
        "small": ""
      }, 
      "name": "This Product", 
      "price": "19.95", 
      "skuid": "ABC123", 
      "url": "shirt.html"
    }, 
    {...}, 
    {...}
  ] 
}

Is this usable or do I need to rewrite the back-end?? I've tinkered with accessing the data and have something very rough working. I can actually see the 'results' data, but I have NO IDEA how to access the 'meta' and 'aggregations' data. I think this is "multiple models in the sam payload" and RSVP.hash should work...but ember-data seems to have a requirement that each model have an id. That makes sense for the "results" model, but not for aggregations and definitely not for meta.

For now I just want to get it to show up.

For starters, my adapter is:

export default DS.RESTAdapter.extend({
    host: 'http://localhost:8000',
    pathForType() {
        return 'search';
    }
});

Test controller is:

export default Ember.Controller.extend({
  queryParams: ['q','paging'],
  q: 'shirt',
  paging: '18'
});

my 'result' model is:

const { attr } = DS;

export default Model.extend({
    'creation_date': attr('string'), 
    'has_pricerange': attr('string'), 
    'image': attr('string'), 
    'name': attr('string'), 
    'price': attr('string'), 
    'skuid': attr('string'), 
    'url': attr('string')
});

route:

export default Ember.Route.extend({
  model(params) {
    return this.store.query('result', { 
        q: params.q,
        paging: params.paging
    });   
  }
});

serializer:

export default DS.RESTSerializer.extend({
    primaryKey: 'skuid'
});

This is so easy to do with jquery - you just $.get and then access the data with object notation. I know ember is not jquery, but it seems like it should be easier to access data. Am I missing something? Taking the wrong approach? Should I start from scratch?

Upvotes: 0

Views: 306

Answers (2)

Chad
Chad

Reputation: 395

Ember Data is a great piece of the Ember puzzle, but by no means required. Whether or not you should use Ember Data really depends on the nature of your data, the control of your API, and your desired futureproofability

Nature of your Data

Ember Data really excels at your typical model/entity type data. "Things" that have attributes, and can relate to each other. If your data follows that pattern then Ember Data could be a great fit.

Control of your API

As mentioned in the other answer, you get a lot for free if you can buy into a JSON API format. This has become the standard for Ember Data, but is not exclusive to Ember. A lot of server-side options will have ways to serialize these resources easily with many existing frameworks. If you can't change the data coming from the server, or if it's easier to just handle it on the front-end, you can go down the path of customizing the adapters/serializers in Ember.

Desired Futureproofability

Ember Data allows you to swap out the adapter/serializer while keeping your models in tact. This is desirable if you want your application to handle different sources in the future, maybe swap from using your own API to using a local storage, or a 3rd-party service like firebase. If don't plan on much changing, you can do your basic ajax calls and return a promise within your model hook and Ember will work more or less the same. I would recommend using ember-network which is spec'ed against the fetch API and will likely become more and more supported as a FastBoot compatible request.

Other things to consider is that Ember Data and using the Ember Object can be heavy depending on the amount of instances of each model you'll be passing in.

Others are tackling this problem, too. Toran Billups has pulled the redux pattern with ember-redux, which is another great way of thinking about how you approach your data.

Your use case

So you could:

Use Ember Data with find

Taking a look at the shape of your data, it looks like you're providing more of a search service than querying for specific models/entities. Ember Data does have a find method, but the amount of metadata you're providing it might be overloaded for the model use case.

Forget Ember Data and use search end point

model: function(params), Use the params from the model hook to construct the url to the search end point, and return a promise (add then as needed to shape the data)

Query the search end point (API refactor)

Similar idea as above, but you would use get the product id's and use those to query the ember data store for the products.

Something similar to:

fetch("service-end-point?with=queryparams")
  .then(result => {
    return {
      products: this.store.findMany(Product, result.ids);
    };
  });

I think it'd be easiest to get started just handling and shaping the data directly in the controller, and skipping Ember Data. If you want specific computed property bindings there's no reason why you can extend Ember.Object with the shape you want and then use something like .map to take the result from the network request and apply it like payload => Object.create(payload).

Let me know if you have any questions surrounding any of these ideas.

Upvotes: 3

AlexMA
AlexMA

Reputation: 10192

I recommend you read this section of the guide, specifically the bit about $.getJSON. Ember is designed to use a powerful store. It's much easier to use if you're using a standard api (e.g. JSON API); you can just use Ember data code directly. But if not, you will have to write some serializer code so Ember knows how to use your api. Once that's done though, your component code won't be coupled to your data fetching code.

You can use $.getJSON if you are still prototyping, though.

Upvotes: 1

Related Questions