2

I am working on a web project that involves a cross-domain call, and I decided to use Knockout.js and ASP.NET Web Api. I used the Single Page Application template in VS 2012, and implemented the Knockout class as it is. The page works great when I make JSON call from the same domain, but when I try using JSONP from the remote server the knockout does not seem to bind the data. I can see the JSON data received from the remote while making JSONP call, but knockout cannot bind the data.

Here is my JavaScript ViewModel classes:

window.storyApp.storyListViewModel = (function (ko, datacontext) {
    //Data
    var self = this;
    self.storyLists = ko.observableArray();
    self.selectedStory = ko.observable();   
    self.error = ko.observable();

    //Operations
    //Load initial state from the server, convert it to Story instances, then populate self

    datacontext.getStoryLists(storyLists, error); // load update stories      

    self.selectStory = function (s) {
        selectedStory(s); $("#showStoryItem").click(); window.scrollTo(0, 0);
        storyItem = s;        
    }
    //append id to the hash for navigating to anchor tag
    self.backToStory = function () {        
        window.location.hash = storyItem.id;       
    }

    self.loadStories = function () {
        datacontext.getStoryLists(storyLists, error); // load update stories
    }

    return {
        storyLists: self.storyLists,
        error: self.error,        
        selectStory: self.selectStory
    };
})(ko, storyApp.datacontext);

// Initiate the Knockout bindings
ko.applyBindings(window.storyApp.storyListViewModel);

And my DataContext class as below:

window.storyApp = window.storyApp || {};

window.storyApp.datacontext = (function (ko) {

    var datacontext = {
        getStoryLists: getStoryLists
    };

    return datacontext;

    function getStoryLists(storyListsObservable, errorObservable) {
        return ajaxRequest("get", storyListUrl())
            .done(getSucceeded)
            .fail(getFailed);

        function getSucceeded(data) {
            var mappedStoryLists = $.map(data, function (list) { return new createStoryList(list); });
            storyListsObservable(mappedStoryLists);
        }

        function getFailed() {
            errorObservable("Error retrieving stories lists.");
        }

        function createStoryList(data) {
            return new datacontext.StoryList(data); // TodoList is injected by model.js
        }
    }

    // Private
    function clearErrorMessage(entity) {
        entity.ErrorMessage(null);
    }

    function ajaxRequest(type, url, data) { // Ajax helper
        var options = {
            dataType: "JSONP",
            contentType: "application/json",
            cache: false,
            type: type,
            data: ko.toJSON(data)
        };
        return $.ajax(url, options);
    }

    // routes
    function storyListUrl(id) {
        return "http://secure.regis.edu/insite_webapi/api/story/" + (id || "");
    }
})(ko);

This page: http://insite.regis.edu/insite/index.html makes the cross-domain call to secure.regis.edu, and it is not working. However the same page on secure.regis.eduinsite/index.html making JSON call works just fine.

What am I doing wrong? Any help will be greatly appreciated.

3
  • I put breakpoints in the getSucceeded and getFailed functions in my Firebug, and found it was entering the getFailed function. Your ajax call is failing for some reason, and this is why Knockout isn't binding anything. Commented Jan 31, 2013 at 0:58
  • Monitoring traffic in Fiddler, I can see the JSON returned from the server which leads me to believe ajax call is fired successfully. I am still not able to figure out what the issue is. Commented Jan 31, 2013 at 4:07
  • I'm mystified, too. Deep in jQuery code it is generating an "Error: jQuery18209904291128522722_1359607729260 was not called" message. I don't understand how that works, but it clearly has something to do with JSONP and cross-domain issues. Commented Jan 31, 2013 at 4:52

2 Answers 2

2

Thanks for those provided help.

I manage to solve the issue by adding WebApiContrib.Formatting.Jsonp class to my WebApi project as explained in https://github.com/WebApiContrib/WebApiContrib.Formatting.Jsonp, and making a slight modification to my jQuery Ajax helper class as below:

function ajaxRequest(type, url, data, callbackWrapper) { // Ajax helper
    var options = {
        dataType: "jsonp",
        crossDomain : true,
        type: type,
        jsonp: "callback",
        jsonpCallback: callbackWrapper,
        data: ko.toJSON(data)
    };   

    return $.ajax(url, options);
}

Everything worked as a charm.

Sign up to request clarification or add additional context in comments.

Comments

1

I suggest the following:

Create a simplified example (without Knockout) that just makes the AJAX call with simple, alert-style success and error callbacks. Affirm that it is throwing an error in the cross-domain case.

Check the following link: parsererror after jQuery.ajax request with jsonp content type. If that doesn't tell you enough, search the Web (and StackOverflow) for information on jQuery JSONP parserrors and callbacks.

If you're still stuck, and you've done #1 and seen what I expect you will see, re-write this post with your simplified example, and remove any references to Knockout (in title, tags). I know Knockout, but I don't know JSONP, and the folks who know JSONP don't seem to be touching this, so I think this question is reaching the wrong audience. Changing the title and tags to emphasize the JSONP/cross-domain aspect may get you the help you need.

Comments

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.