mardi 23 juin 2015

Ember Data - REST JSON API - server responding with nested URLs - what is the recommended configuration?

I'm trying to find a recommended way to configure Ember Data to consume data from server that is using nested URLs. So far I tried following approaches:

Overriding buildURL

http://ift.tt/1N6tjaK

App.SubcolorAdapter = DS.RESTAdapter.extend({
  buildURL: function(type, id, snapshot, requestType, query) {
    var urlParts = location.hash.split("/"); // don't like the way how I'm accessing it
    var parentId = urlParts[2];
    var url = "/colors/" + parentId + "/subcolors";
    return url;
  }
});


Overriding findAll

http://ift.tt/1N6tjaO

App.SubcolorAdapter = DS.RESTAdapter.extend({
  findAll: function(store, type, sinceToken) {
    var urlParts = location.hash.split("/"); // don't like the way how I'm accessing it
    var parentId = urlParts[2];
    var url = "/colors/" + parentId + "/subcolors";
    return new Ember.RSVP.Promise(function(resolve, reject) {
      jQuery.getJSON(url).then(function(data) {
        Ember.run(null, resolve, data);
      }, function(jqXHR) {
        jqXHR.then = null;
        Ember.run(null, reject, jqXHR);
      });
    });
  }
});

It sort of works, but I don't like the way how I'm accessing the ID. I tried accessing arguments or this.get( ... ) in buildURL or findAll but no success.


Specifying model relationship

Ember Data nested resource URL - so I tried:

App.Color = DS.Model.extend({
  name: DS.attr('string'),
  subcolors: DS.hasMany('App.Subcolor'),
});   

App.Subcolor = DS.Model.extend({
  name: DS.attr('string'),
  color: DS.belongsTo('App.Color'),
});  

App.Router.map(function() {
  this.resource('color', function(){
    this.route('show', { path: ':color_id' }, function() {
      this.route('subcolor');
    });
  });
});

But the request is made to /subcolors that fails.




Ember.ENV.ENABLE_DS_FILTER = true;

    App = Ember.Application.create();

    App.ApplicationAdapter = DS.RESTAdapter;
    
    App.Router.map(function() {
      this.resource('color', function(){
        this.route('show', { path: ':color_id' }, function() {
          this.route('subcolor');
        });
      });
    });

    App.Color = DS.Model.extend({
      name: DS.attr('string'),
      subcolors: DS.hasMany('App.Subcolor'),
    });   

    App.Subcolor = DS.Model.extend({
      name: DS.attr('string'),
      color: DS.belongsTo('App.Color'),
    });  

    App.IndexRoute = Ember.Route.extend({    
      model: function() {
        return this.store.find('color');
      }
    });         

    App.ColorShowSubcolorRoute = Ember.Route.extend({    
      model: function() {
        return this.store.find('subcolor');
      }
    });

    // APPROACH 1
    //  
    //
    //
    // http://ift.tt/1tHjp6y
    // As suggested here: http://ift.tt/1N6tjaK

    // App.SubcolorAdapter = DS.RESTAdapter.extend({
    //   buildURL: function(type, id, snapshot, requestType, query) {
    //     var urlParts = location.hash.split("/");
    //     var parentId = urlParts[2];
    //     var url = "/colors/" + parentId + "/subcolors";
    //     return url;
    //   }
    // });


    // APPROACH 2
    //  
    //
    //
    // http://ift.tt/1fxHtak
    // As suggested here: http://ift.tt/1N6tjaO

    // App.SubcolorAdapter = DS.RESTAdapter.extend({
    //   findAll: function(store, type, sinceToken) {
    //     var urlParts = location.hash.split("/");
    //     var parentId = urlParts[2];
    //     var url = "/colors/" + parentId + "/subcolors";
    //     return new Ember.RSVP.Promise(function(resolve, reject) {
    //       jQuery.getJSON(url).then(function(data) {
    //         Ember.run(null, resolve, data);
    //       }, function(jqXHR) {
    //         jqXHR.then = null;
    //         Ember.run(null, reject, jqXHR);
    //       });
    //     });
    //   }
    // });


    { // mocking AJAX requests (dummy braces so I can collapse in the editor)
      $.mockjax({
        type: 'GET',
        url: '/colors',
        dataType: 'json',
        responseText: {
          "colors" : [
            { id: 1, name: "Red" },
            { id: 2, name: "Blue" },
          ]
        }
      });      

      $.mockjax({
        type: 'GET',
        url: '/colors/1',
        dataType: 'json',
        responseText: {
          "colors" : [
            { id: 1, name: "Red" }
          ]
        }
      }); 

      $.mockjax({
        type: 'GET',
        url: '/colors/2',
        dataType: 'json',
        responseText: {
          "colors" : [
            { id: 2, name: "Blue" }
          ]
        }
      });       

      $.mockjax({
        type: 'GET',
        url: '/colors/1/subcolors',
        dataType: 'json',
        responseText: {
          "subcolors": [
            { id: 1, name: "Light Red" },
            { id: 2, name: "Dark Red"  }
          ]}
      });    

      $.mockjax({
        type: 'GET',
        url: '/colors/2/subcolors',
        dataType: 'json',
        responseText: {
          "subcolors": [
            { id: 3, name: "Light Blue"},
            { id: 4, name: "Dark Blue" }
          ]}
      });
    }
  <script type="text/x-handlebars" id="index">
    <h3>index</h3>
    <ul>
      {{#each color in model}}
        <li>{{#link-to "color.show" color}} {{color.name}} {{/link-to}}</li>
      {{/each}}
    </ul>
   </script>

  <script type="text/x-handlebars" id="color/show">
    <h3>color/show</h3>
    {{#link-to "application"}}Go back to the list{{/link-to}}
    <br>
    {{ model.name }}
    <br>
    {{#link-to "color.show.subcolor" model}} go to subcolors {{/link-to}}

    {{outlet}}
  </script>  

  <script type="text/x-handlebars" id="color/show/subcolor">
    <h3>color/show/subcolor</h3>
    <ul>
      {{#each subcolor in model}}
        <li>{{subcolor.name}}</li>
      {{/each}}
    </ul>
  </script>
 
  <script src="http://ift.tt/183v7Lz"></script>
  <script src="http://ift.tt/1fxHqvb"></script>
  <script src="http://ift.tt/1Iq6rj2"></script>
  <script src="http://ift.tt/1exfLuj"></script>
  <script src="http://ift.tt/1fxHqvd"></script> 



For demo purposes (so it is runnable and self-contained) I mock the following GET requests:

/colors
/colors/1
/colors/1/subcolors
/colors/2
/colors/2/subcolors




Aucun commentaire:

Enregistrer un commentaire