Ember with XML based data and a rest like API


#1

So far i have been having a great experience with Ember but one thing i feel i am not doing right is the data access. My application is almost a pure data reader and when it does need to submit data it is all submitted via the url as it is more a command like rest but with no data. My issue is currently 2 fold.

  1. My source data is in an XML format
  2. A lot of the time i don’t want to cache my data or i need to refresh it frequently

The XML data i can currently handling using xslToJson library which gives me the same javascript object structure if would have if the data was loaded via json but sadly it does not follow the standards ember-data expects and had quite a few layers to it (lots of children etc). Currently i have the loading and working by having my controllers call $.get method that gets the xml and converts it to javascript object but this does not feel like the correct way to do this sort of thing in Ember. The other thing i have not worked out is the correct way/time to load children data as it gets a little complex.

My datasource is a “Plex Media Server” and the majority of the api works like this

  • /Metadata/5 (displays info for item 5)
  • /Metadata/5/children (displays info for item 5 and contains a property that has an array of child instances. Each of these child instance has the same content as /Metadata/id where the id is the id on the child )
  • /Metadata/x/children (where x is the child if from above) (displays the info for the child and its children.)

There are other url’s but i have not investigated them yet. most of the data is accessed based on the 2 url formats above.

Am i better off just loading my data via my controllers like i currently am or is there some better way i should be loading this data? I am not sure if ember-data is the best fit due to the strange way the url works as well as the data been returned is quite structured and changes based on the type of item the metadata is for(i think it changes i still need to do some tests on this)


#2

Am i better off just loading my data via my controllers like i currently am or is there some better way i should be loading this data?

Controllers are not a great place to make asynchronous calls. It’s usually better to use Routes, because they have built it mechanism for asynchronous loading.

Ember Data might not be the best fit. It depends on how much work you have to do to get Ember Data working for you. Have you tried doing everything without Ember Data ( at least until you fully understand the APIs that you’re working with )?


#3

You typically want to be creating your data models at the Router layer.

If you have little control over the API, Ember Data or the many other persistence libraries, probably would be more of a headache than beneficial. Your best bet is to setup simple model objects and wrap the AJAX responses.

Anyway, you might find this link helpful which goes into more detail. It’s a little dated, but still applicable.


#4

I will do some reading on that as i am not sure how to load data this way.

ok. At the minute i am just taking the xml response, converting it to javascript variable and using that as my model and it sort of works. I will have to post some of my code when i get home so you can see and hopefully advise.

I have read that url but thought things may have changes since then hence i was asking.


#5

I have not used Ember Data at all yet. I have just been doing direct JQuery calls in my controllers so far to load the models. I will post one of my controllers when i get home in about an hour


#6

@jasonmit @tarasm Thanks for the advice so far. It seems i got things a little confused. I am using Route to load my data like follows

App.EpisodesRoute = Ember.Route.extend({
    model: function () {
        var url = server + '/library/metadata/1955/children';
        return Ember.$.get(url).then(function (xml) {
            var json = $.xml2json(xml);
            //console.log(JSON.stringify(json));
            return json.Video;
        });
    },
    setupController: function(controller, model) {
        controller.set('model', model);
        //console.log(JSON.stringify(model));
    },
    
});

and

App.EpisodeRoute = Ember.Route.extend({
    model: function (params) {
        //console.log(params.ratingKey);
        var url = server + '/library/metadata/' + params.ratingKey;
        return Ember.$.get(url).then(function (xml) {
            var json = $.xml2json(xml);
            //console.log(JSON.stringify(json));
            return json.Video;
        });
    },
    setupController: function (controller, model) {
        controller.set('model', model);
        //console.log(JSON.stringify(model));
    },
});

but this does not seem to be ideal because when the controller is initalised it does not seem to have data so the following seems to fail. @jasonmit this is me trying to implement your solution from the keyboard controlled list navigation sample.

this.objectAt(0).set('active', true);

Fails in the controller below and i think it has to do with me loading the model aysnc.

App.EpisodesController = Ember.ArrayController.extend({
    sortProperties: ['title'],
    sortAscending: true, // false for descending
    actions:
        {
            changeSelection: function (params) {
                var toBeSelected;

                if (params && params.hasOwnProperty('id')) {
                    // click event handled differently from keyDown event on view
                    var idx = this.get('content').indexOf(params);
                    toBeSelected = this.objectAt(idx);
                }
                else {
                    // this came from the keyDown event on the view
                    var current = this.get('currentSelected'),
                        currentIndex = this.indexOf(current);

                    toBeSelected = this.objectAt(currentIndex + params.direction);
                }

                if (toBeSelected) {
                    this.setEach('active', false);
                    toBeSelected.set('active', true);
                }
            }
        },
    init: function () {
        this._super();

        // by default, setting the first userController as active
        var fn = function () {
            this.objectAt(0).set('active', true);
            this.removeObserver('content', this, fn);
        };

        this.addObserver('content', this, fn);
    },

    currentSelected: function () {
        var i = this.findBy('active', true) || -1;
        return i;
    }.property('@each.active')
});

— EDIT— forgot to say the error i get is

Uncaught TypeError: Object #<Object> has no method 'set' 

— end edit – That said maybe i am just doing something else that is stupid. I am normally a back-end developer not a web developer so this has been a bit of a learning curve.


#7

ok so now that i am debugging the line that is my issue i am noticing that the data is loading and that the cause is that my object that i load from xml does not have a property called active. @jasonmit should i be adding that property to my data model some how? Shouldn’t that be on the controller not the data model or am i misunderstanding something?

Also wondering based on what i posted is the route data load way of doing things the best way for me or should i be looking at some sort of object that has methods on it to load all the objects and have the routes call that?


#8

It’s getting late here, so I’m heading to sleep. However, if you return an Ember.Deferred in your model function, setupController will not be fired until you resolve the deferred.

Try this.

model: function () {
   var df = Ember.Deferred.create(),
       url = server + '/library/metadata/1955/children';

   Ember.$.get(url).then(function (xml) {
      var json = $.xml2json(xml);
      df.resolve(json.Video);
   });

   return df;
 }

#9

@jasonmit Thanks i worked out a few of the errors. It was because i misunderstood a few things in your implementation. No errors now. Loads data etc and not console errors. Keyboard navigation does not work but i am sure that is just to me have other things wrong. Hopefully i can fix it on my own now. Thanks for all the help!

If i still can’t work it out i will post it on the other thread i guess as it relates to that now not the loading of data.