0

This is a two stage problem when working with backbone.js and a web api controller.

I have a simple web api controller that returns a JSON string, in fiddler the result looks like this:

{
    "$type": "MvcApplication.Models.Article, MvcApplication",
    "Id": "1",
    "Heading":"The heading"
}

I use the following code to fetch a user from my web api

var user = new Usermodel({ id: "1" });

user.fetch({
    success: function (u) {
        console.log(u.toJSON());
    }
});

now my backbone user object looks like this

{
    id: "1",
    {
        "$type": "MvcApplication.Models.Article, MvcApplication",
        "Id": "1",
        "Heading": "The heading"
    }
}

When I try to bind this backbone model object to my view template that looks like this

<form>
    <input type="text" value="<%=Heading%>" />
    <input type="submit" value="Save" />
</form>

i get, Heading is undefined but when I use id it binds just fine? It seems like underscore does not like the backbone model object and just want a plain JSON object just like the one I get from my web api?

The second problem with this is that when I save my model with user.save({ Heading: "my new heading }); the payload to my web api is the backbone model which is completely wrong because my api expects a user object like this to be sent to the server:

{
    "$type": "MvcApplication.Models.Article, MvcApplication",
    "Id": "1",
    "Heading":"The heading"
}

and not the backbone model with the real object wrapped inside. Is it possible to solve so that underscore can handle backbone models and tell backbone to only send the payload that my end point expects?

4
  • 1
    The second one is not a valid JSON - you need to have a key before the object surrounded by {}. Is it possible that you have omitted part of it? Commented Mar 17, 2013 at 17:07
  • @svetoslavnedkov No, the first JSON in my question is what I get from my service but backbone seem to alter the object by adding the id property around the object I receive from the server? Commented Mar 17, 2013 at 17:35
  • Can you show us your Backbone.sync code in the case of 'read'? Commented Mar 17, 2013 at 18:16
  • @svetoslavnedkov this is the exact code I'm using but the end point is of course not available. jsfiddle.net/J83aU/12 Commented Mar 17, 2013 at 18:28

3 Answers 3

1
+50

You may be able to solve the problem by following these steps:

In addition to using fiddler to inspect your response, look at the response on the network tab of Chrome Developer Tools. If the response does not look like this, then your web api is not returning a valid json response, the problem is most likely within your web api. You need to get/provide more information about your web api to solve the problem. Verify that the response looks like this:

enter image description here

After verifying that the response from the web api is correct, check out the following jsfiddle I modified:

http://jsfiddle.net/J83aU/23/

Fix your client side code referencing the example I have provided.

Properly instantiate the Backbone objects.

Call the view.render function at the correct step, after the response is received from the server.

Make sure that the main content div is actually rendered before creating a view which depends on it for the 'view.el' property.

Declare the 'view.el' property properly, with a string rather than jQuery object.

Use development Backbone and underscore to enable debugging, an important concept when learning to use open source frameworks such as Backbone.

Use jsfiddle's echo/json api to mock a valid ajax json response, exactly as described in step 1.

The following json example you submitted is not even valid json, if you update your question with valid json example, it would be easier to solve the problem. It is unlikely that Backbone created this non-json structure and more likely that you have submitted it here incorrectly.

{
    id: "1",
    {
        "$type": "MvcApplication.Models.Article, MvcApplication",
        "Id": "1",
        "Heading": "The heading"
    }
}

Finally, try to provide a screenshot of the http headers or something for the problem that is occurring when you call model.save().

Read over the Backbone documentation for model.save() and make sure you are doing everything just as the example provided.

You may be able to workaround Backbone's funky save function by forcing your attributes into POST parameters using ajax options:

$.fn.serializeObject = function(){
    var o = {};
    var a = this.serializeArray();
    $.each(a, function() {
        if (o[this.name] !== undefined) {
            if (!o[this.name].push) {
                o[this.name] = [o[this.name]];
            }
            o[this.name].push(this.value || '');
        } else {
            o[this.name] = this.value || '';
        }
    });
    return o;
};

var saveView = Backbone.View.extend({
    events:{
        'click #saveSubmitButton':'submit'
    },
    submit:function (event) {

        event.preventDefault();
        var view = this, 
            attributes = $('#saveForm').serializeObject();

        this.model.save(attributes, {
            data:attributes,
            processData:true,
            success:function (model) {
                //....
            }
        });
    },
    render:function () {
        //.......
    }
});
Sign up to request clarification or add additional context in comments.

Comments

0

The attributes property of your model should be unaltered. Send those to your template call:

var MyModel = Backbone.Model.extend();
var newModel = new MyModel({
    "$type": "MvcApplication.Models.Article, MvcApplication",
    "Heading":"The heading"
});
var html = _.template(templateVar, newModel.attributes);

In your templateVar, which is your templated markup, you should be able to reference $type and Heading directly.

2 Comments

This example works but the problem is when I create a new model with an id and fetches it then backbone will alter the JSON and make in invalid. I have updated my question with the code I'm using to create a user
Not sure I'm following - when you instantiate the model with the json, it puts it in the attributes property. The model has other properties on it as well, but it shouldn't be necessary to worry about that as you can still access the attributes. If you're concerned about what toJSON is returning, then don't use it, just use the attributes property.
0

If you have a look at the jsFiddle through a debugger like Firebug you can see that the way you construct the model's URL is not working out, because the forward slash gets encoded. Can you try to modify your model declaration to this:

var Usermodel = Backbone.Model.extend({
    url: function () {
        return '/api/page/articles/' + this.get('id');
    }    
});

var user = new Usermodel({
    id: '85'
});

And see if you still get the same JSON. Basically if you don't have a Backbone.sync override you are using built-in retrieval that for one shouldn't produce invalid JSON.

3 Comments

the error on fiddler seems to be because the end point are not available because I don't get the same error on my ws. Tried your suggestion but this is how the object passed to the browser looks like cl.ly/NdpD , I also get the same error when I save my model because the payload also looks like the image.
Well the JSON you get is valid, the responseText which is the second parameter to the success callback is the key and the options which are the third are the value. Unfortunately I can't tell why this happens, I hope someone can shed some light on this. What you can try is to use the second parameter to success which is server response verbatim.
as you say, the second parameter is the correct server response.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.