Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ember.JS - 'TypeError: internalModel.getRecord is not a function' when trying to reverse a collection of records

--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);
like image 226
Chris Lam Avatar asked Aug 21 '16 19:08

Chris Lam


2 Answers

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.

like image 185
Ember Freak Avatar answered Nov 20 '22 05:11

Ember Freak


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}}
like image 2
Sam Selikoff Avatar answered Nov 20 '22 05:11

Sam Selikoff