How do I handle needing the same model twice with a different dataset?


#1

I have a section of my application that allows users to compare a model with mutable date parameters. At the moment my implementation of this is really poor and I’d like to see if anyone else has tackled the same problem.

At the moment I have a route calling two separate but identical models (dataGroup1, dataGroup2) and they display data based on their own queryParams (group1DateFrom, group2DateFrom etc). This means that I also have two separate but identical queries on the back end supporting these models.

It’s very clunky and involves a lot of repetition but I’m not sure how I can have two instances off the same model displaying different data (due to the queryParams). As far as I know the model can only be called once in the route.

I thought about potentially using named outlets to display the data for each group but they would still be generated by the single route. I also thought about calling the model twice in nested routes but as the models are brought from the store I don’t think this would work either.

Does anyone have any ideas on what the best Ember way would be to deal with this requirement?


#2

Hey @sorvah, make sure to post code examples if you can. I’m doing a lot of reading between the lines here, but here is a pretty standard pattern for tackling what you’re doing:

import Route from '@ember/routing/route';
import { hash } from 'rsvp';

export default Route.extend({
  // Setup your model hook to rerun if the params change. 
  // You may not need this
  queryParams: { 
    group1DateFrom: {
      refreshModel: true
    },
    group2DateFrom: {
      refreshModel: true
    }
  },

  model(params) {
    // Use RSVP.hash to query the store. If you need to do some manipulation 
    // of the object, you could create a simple helper function inside the route
    // to eliminate some of the duplication
    return hash({
      dataGroup1: this.store.find(..., params.group1DateFrom),
      dataGroup2: this.store.find(..., params.group2DateFrom)
    })
  },

  setupController(controller, model) {
    this._super(controller, model);

    // Doing model.dataGroup1 in controller/template is annoying. But now you can just access 
    // the models directly. If there is repetition in the display, consider creating a component
    this.set('dataGroup1', model.dataGroup1);
    this.set('dataGroup2', model.dataGroup2);
  },
});

It’s possible I completely misunderstood what you’re asking, but this is what came to mind reading your post.


#4

Hi

The code you’ve placed closely matches my implementation with key difference being I have to use store.query rather than store.find:

    import Route from '@ember/routing/route';
    import RSVP from 'rsvp';
    export default Route.extend({
      queryParams: {
        group1From: {
          refreshModel: true
        },
        group1To: {
          refreshModel: true
        },
        group2From: {
          refreshModel: true
        },
        group2To: {
          refreshModel: true
        }
      },

      model(params) {
        return RSVP.hash({
          wdgroup1: this.get('store').query('wdgroup1', params),
          wdgroup2: this.get('store').query('wdgroup1', params),

        });
      },

      setupController(controller, models) {
        this._super(controller, models);
        controller.set('wdgroup1', models.wdgroup1);
        controller.set('wdgroup2', models.wdgroup2);

      },
    });

The problem is that this has me creating two unique models with identical structures (and corresponding API returns).

Ideally what I would like to be able to do is call a model and be able to manipulate a copy of it with group1 params and another copy with group2 params.

      model(params) {
            return 
              aModel: this.get('store').query('aModel', params),

           
          }

With my limited understanding of models and the data store I don’t think this is possible and it is interesting that we have such similar code! If I was to use the single model return then the group 2 params refresh the model that the group1 params have created


#5

You could make the query once in the model hook and then in your afterModel hook you could make a copy of the Ember Data record and make your necessary changes to the model at that point … https://emberobserver.com/addons/ember-data-copyable should help handle the copying aspects (as it isn’t easy to copy an Ember Data model).

Alternately, if you don’t need a full Ember Data model in your route but just need simple values you could pull the values out, clone them into two simple hashes and pass those down to your template. If you can avoid the hackery of copying the models you might have a simpler time upgrading in the future …