SuperMarco
SuperMarco

Reputation: 721

emberjs display an object return from an ajax call

I have a small problem with my ember app, but I still don't know how to solve it..

I have this error :

Error while loading route: TypeError: Object #<Object> has no method 'addArrayObserver'

With this code :

<script type="text/x-handlebars" data-template-name="enquiry">

{{#link-to 'enquiries' class="create-btn"}}Back to the enquiries{{/link-to}}
<div class="enquiry-info">
    <button {{action "update"}}>Update</button>

    <table>
        <tr>
            <td>{{enquiry.customerName}}</td>
        </tr>
        <tr>
            <td>{{customerEmail}}</td>
        </tr>
        <tr>
            <td>{{customerPhone}}</td>
        </tr>
    </table>

</div>
{{outlet}}
</script>

My controller :

App.EnquiriesController = Ember.ArrayController.extend({
    actions: {
        clickBtn: function( id ) {
            console.log('DEBUG: ClickBtn OK id = ' + id);
            this.transitionToRoute('enquiry', id);
        }
    }
});

Router :

App.EnquiryRoute = Ember.Route.extend({
    model: function( param ) {
        console.log('Enquiry id = ' + param.enquiry_id);
        return App.Enquiries.findOne(param.enquiry_id);
    }
});

To explain this better, I have a button, and when the user click on it, it trigger the clickBtn function. That return in my router the content of an ajax call from my server.

The thing is that is return me an object and it seems that ember prefer to have an array no ?

Is it possible to display an object in the template instead ?

Here is the ajax call :

findOne: function(id) {
        var result = {};
        $.ajax({
            url: host + 'mdf/enquiry/' + id,
            type: 'GET',
            accepts: 'application/json',
            success: function (data) {
                result = data;
            },
            error: function() {
                console.log('DEBUG: GET Enquiry ' + id + ' Failed');
            }
        });
        return result;
    }

Thanks for the help !! :)

[edit]

My router map :

App.Router.map(function() {
    this.resource('login', { path: '/' });
    this.resource('home');
    this.resource('enquiries', function (){
        this.route('create');
    });
    this.resource('enquiry', { path: '/:enquiry_id' }, function(){
            this.route('update');
        });
});

This is the object I've back from the server :

Object {ok: true, enquiry: Object}
enquiry: Object
-createdAt: "2014-02-03T15:32:16.000Z"
-customerEmail: "[email protected]"
-customerName: "Name Test"
-customerPhone: "01523456789"
-id: 1
-__proto__: Object
ok: true
__proto__: Object

Upvotes: 0

Views: 1451

Answers (1)

Jake Haller-Roby
Jake Haller-Roby

Reputation: 6427

Ember has both ArrayControllers and ObjectControllers. It looks like you need to declare

App.EnquiriesController = Ember.ObjectController.extend({

insted of

App.EnquiriesController = Ember.ArrayController.extend({

EDIT: In response to your edit with more info, I see a couple of issues.

First, and most importantly: Your enquiry route is a serialized route. As a result, ember will handle the model for this route in a different way than it does other routes.

If you transition to this route by typing in the corresponding URL, the route will behave in a way that rightfully corresponds to your Ember.Route object/model hook. However. If you transition to this route via transitionToRoute('enquiry') or {{#linkTo 'enquiry'}}, it will not behave correctly. Your transitions and linkTos should be in format transitionToRoute('enquiry', modelObject) and {{#linkTo 'enquiry' modelObject}}, however, it seems you are passing an id rather than the returned of your ajax call.

So replace:

App.EnquiriesController = Ember.ArrayController.extend({
    actions: {
        clickBtn: function( id ) {
            console.log('DEBUG: ClickBtn OK id = ' + id);
            this.transitionToRoute('enquiry', id);
        }
    }
});

with

App.EnquiriesController = Ember.ArrayController.extend({
    actions: {
        clickBtn: function( id ) {
            console.log('DEBUG: ClickBtn OK id = ' + id);
            this.transitionToRoute('enquiry', App.Enquiries.findOne(id));
        }
    }
});

In addition, on your template, all of your handlebar helpers should be in the format {{enquiry.[propertyName]}} if you wish to access properties held within the enquiry object. You did this correctly for customerName but not for the other 2 properties.

EDIT #2, edit harder:

Additional issues are found.

There's a problem with your Ajax call. The object you return will always be an empty object. That's because ajax calls are asynchronous. You can not rely on an ajax call to run in the order you type it in.

Here's the order that your program is currently running in:

  1. var result = {};
  2. Ajax call is sent out.
  3. return result;
  4. Some time passes as we wait for a response....
  5. Ajax call is returned.
  6. result = data;... But we already returned an empty result in step 3!

Because your ajax call is fairly simple and you don't do any transformations on the returned data, I would suggest replacing your findOne function with:

findOne: function(id) {
    return $.ajax({
        url: host + 'mdf/enquiry/' + id,
        type: 'GET',
        accepts: 'application/json',
        success: function (data) {
            console.log('DEBUG: GET Enquiry ' + id + ' Succeeded');
            return data;
        },
        error: function() {
            console.log('DEBUG: GET Enquiry ' + id + ' Failed');
        }
    });
}

Additionally, in response to your comment about whether you should keep the model hook in your EnquiryRoute: Yes. If a person were to type in the URL associated with that route, then the model hook will trigger (because there will be no modelObject given). If you remove the model hook, the app will only work when clicking links within the app, and will cause errors if you enter the app from a url.

Upvotes: 1

Related Questions