3
votes

I'm trying to add objects to my Emberjs Arraycontroller. I have a "create" action that fires when a button is pushed. This works fine but I can't seem to add the element with the this.pushObject function to the ArrayController. I get this error message:

Uncaught Error: The result of a server query (on App.Software) is immutable.  

I guess this is because I'm using the RESTAdapter to load data and it does not like that I'm adding elements manually?

Here is my controller and the create action.

App.SoftwareIndexController = Ember.ArrayController.extend({
    sortProperties: ['revision'],

    create:function(){
        var revision = $('#software_revision').val();
        var doc = $('#software_document').val();

        var software  = App.Software.createRecord({
          product_id: 1,
          revision: revision,
          doc: doc
        });
        this.pushObject(software);

    }
});

Here is the route

App.SoftwareIndexRoute = Ember.Route.extend({
  setupController:function(controller){
    var product_id = 1;
    controller.set('content', App.Software.find({product_id:1}));
  }
});

Here is the model and store

App.Store = DS.Store.extend({
  revision: 12,
  adapter: 'DS.RESTAdapter'
});

DS.RESTAdapter.configure("plurals", {
  software: "software"
});

App.Software = DS.Model.extend({
  revision: DS.attr('string'),
  doc: DS.attr('string'),
  verified: DS.attr('boolean')
});

And here is the template view with the create form and list of software

<script type="text/x-handlebars" data-template-name="software/index">
  <p>
  <fieldset>
    <legend>Create a new software revision</legend>
    <label for="software_revision">Revision</label>
    <input id="software_revision" name="software_revision" type="text" placeholder="">
    <label for="software_document">Document ID</label>
    <input id="software_document"  name="software_document" type="text" placeholder="">   
    <button class="btn btn-success" {{action create}}>Create</button>
  </fieldset>
  </p>


  {{#if length}}
  <table class="table">
    <thead>
      <tr>
        <th>Revision</th>
        <th>Created</th>
      </tr>
    </thead>
    <tbody>
      {{#each controller}}
          <tr>
            <td>{{revision}}</td>
            <td>{{createdAt}}</td>
          </tr>
      {{/each}} 
    </tbody>
  </table>

  {{else}}
  <div class="alert alert-info">
    <button type="button" class="close" data-dismiss="alert">&times;</button>
    <strong>No software revisions found!</strong> start by creating a new revision above.
  </div>
  {{/if}}
</script>

Does anybody know the proper way to add new object to a ArrayController store? Thank you!

This works by the way if I change the route so it doesn't use the RESTAdapter

App.SoftwareIndexRoute = Ember.Route.extend({
  setupController:function(controller){
    var product_id = 1;
    controller.set('content', []); // not using the RESTAdapter to load data
  }
});
1
I've not tested it, but you could try to extend your App.Software model with the Ember.MutableArray mixin: DS.Model.extend(Ember.MutableArray, {...}); and see if you get the functionality - intuitivepixel
Thanks for the suggestion intuitivepixel. I tried to extend the model so it's : App.Software = DS.Model.extend(Ember.MutableArray,{ but I get the same Immutable error message - Arni Gudjonsson
This seems funky. Your controller should automatically load new records without having to push them in. Instead of setupController can you try using the model function in your route? - mehulkar

1 Answers

5
votes

I had this same problem. It looks like the content returned from App.Software.find() is an immutable array. I was able to get around this by getting the content of the immutable array which returned a mutable array.

For example:

In ember 1.0.0 + ember data 1.0.0 beta 3:

this.store.find('software').then(function (softwares) {
  controller.set('content', softwares.get('content'));
});

And this is only a guess but for the version you were working with at the time of your post:

controller.set('content', App.Software.find().get('content'));