0

.NET + KnockoutJS, demo here, use knockout-mapping.js for mapping

As in pure .NET application@Html.TextBoxFor(model=>model.questionarie.Sheets.ToList()[0].Timestamp) shows the timestamp. Using knockout shows nothing.

As I view the source, the seriazlied object data looks like this

var data={"questionarie":{"Sheets":[{"Groups":[{"GroupsOfQuestions":[{"Groups":null,"Questions":[{"Answers":[{"Questions":null,"answersid":1,"questionid":1,"userid":1,"value":1,"User":null,"Timestamp":[0,0,0,0,0,0,7,221].....

also log the viewmodel, timestamp is also turned into observable, but the submmited value is null, please help! The only walk around that I can come up with is to add one more property to model class as string represatation of the byte array, let knockout submit that string value instead of the bytearray, but don't think it's good idea.

user3453552
  • 199
  • 1
  • 2
  • 11
  • 1
    Error on demo website, re Entity Framework – Robert Slaney Mar 27 '14 at 00:33
  • Hi Robert, its working now, please help, clickiing save will raise this exception "Store update, insert, or delete statement affected an unexpected number of rows (0). ...." its because Timestamp is null – user3453552 Mar 27 '14 at 08:36
  • Couldn't see where you bound your timestamp property. Also, please don't use a large site with loads of code for your question sample. Please create a [Minimal, Complete, and Verifiable example](http://stackoverflow.com/help/mcve) which shows your issue. Please create a minimal jsfiddle/plunker/jsbin which shows your issue and you'll be more likely to get more people to try to answer your question. – Robert Westerlund Mar 27 '14 at 10:03
  • Hi, sorry, I do not know how to create a byte array in javascript, can't do it in a fiddle. if you access the demo page again, you see the log object already contains the observable bytearray for timestamp, but the submit value is null. Also, I add two areas, one with background color blue to show the timestamp using .net code, another area with green color showing the value from knockout – user3453552 Mar 27 '14 at 10:48
  • My guess is that the default value binding for elements isn't handling the array. How do you display an array in a textbox? Do you toString() it? Do you treat it as an array of characters? Why are you display an array inside a textbox? Knockout can handle storing an array in an observable and pulling it back out at a later time using ko.toJSON. If you're getting null, there's something else going on. Please create a small jsFiddle that reproduces your problem. – PatrickSteele Mar 27 '14 at 11:36

2 Answers2

0

Sorry for the trouble, Roberts and Patrick, next time I will post a fiddle, but regarding this question, a fiddle is not going to help neither. The json data being submitted back to backend (ko.toJSON(self.mysurvey)) contains a string represatation for bytearray like this "Timestamp":[0,0,0,0,0,1,17,133], the problem is that .NET turns this into null. A related question can be found here: MVC3 - posting byte array to a controller - Database RowVersion. So knockout is functional, but maybe there is another way changing Timestamp":[0,0,0,0,0,1,17,133] to some format that can be recognized be .NET controller

Community
  • 1
  • 1
user3453552
  • 199
  • 1
  • 2
  • 11
  • What JSON library are you using to serialize and deserialize your JSON on the server? What data type is the Timestamp property in your server side model ? – Robert Slaney Mar 28 '14 at 00:03
  • I am using the default JSON provider used by .NET MVC controller, http://stackoverflow.com/questions/14591750/asp-net-mvc4-setting-the-default-json-serializer, the type for the timestamp is as following [Timestamp] public Byte[] Timestamp { get; set; } – user3453552 Mar 28 '14 at 20:43
0

The default MVC3 ModelBinder for the byte[] type expects the data to be transported as a Base64 string, but the JavascriptSerializer pushes them out as arrays. You have a round trip issue that cannot be solved without changing either client side or server side infrastructure.

CLIENT SIDE

You will need to encode the timestamps in the JSON as base64 strings before sending to the server. Add a replacer function to your ko.toJSON to convert whenever you have a timestamp property.

var convertTimestampToBase64String = function(data)
{
    var str = String.fromCharCode.apply(null,data);
    return btoa(str);
}

var timestampReplacer = function(key, value) {
    if ( key === 'Timestamp' && Array.isArray(value)) {
        return convertTimestampToBase64String(value);
    }
    return value;
}

self.submitSurvey = function () {
    $.ajax({
        url: "/Survey/SubmitSurvey/",
        type: 'post',
        data: ko.toJSON(self.mysurvey, timestampReplacer),
        contentType: 'application/json',
        success: function (result) {
            alert("survy is saved")
        }
    });
}

SERVER SIDE

The other alternative is to replace your JSON serializer and value provider with another vendor, like JSON.NET. See my answer here for possible implementation details.

Community
  • 1
  • 1
Robert Slaney
  • 3,712
  • 1
  • 21
  • 25