Skip to main content

Serialize Javascript Object with getter Property

JavaScript Logo

In one of my current Aurelia projects I’m using a data object that contains a calculated field. The calculated field is a simple sum of two other fields on the object. Here is an example class definition that illustrates it:

export class SomeItem {
x;
y;

constructor(x, y) {
this.x = x;
this.y = y;
}

get z() {
return this.x + this.y;
}
}

I use this class in two-way binding on an Aurelia custom component. The x and y fields are two-way bound to contenteditable DIV elements in the component. The calculated z field is one-way (display-only) bound to another DIV in the component. The class itself works just fine, the calculated field displays, etc. However, when serializing the object to JSON and sending the data to an API the calculated field is missing from the serialized JSON data.

I’m using the Aurelia fetch client to call my API and the included json helper for serialization. The json helper just stringifies the object and then packs it into a blob:


return new Blob([JSON.stringify(body)], { type: 'application/json' });

The problem with my getter approach is that functions in Javascript are not enumerable by default, which means any kind of serialization automation is not going to see the property on the object by default when it is iterating through the object’s property list. JSON serialization picked up the x and y properties on my class just fine, but not the z property.

To fix this I had to manually define the property on the object and set it to be enumerable. So now the class looks like this:

export class SomeItem {
x;
y;

constructor(x, y) {
this.x = x;
this.y = y;
}

Object.defineProperty(this, 'z', {
enumerable: true, //this adds the function property to the list of property keys
get: function() {
return this.x + this.y;
}
}
}

After setting the property function to be enumerable the JSON serializer picked it right up and it’s now flowing through to my API as desired.

AngularJS – “Error: 10 $digest() iterations reached. Aborting!” with Array Extension Method

Angular Logo

Using AngularJS 1.4.1. I had this markup with multiple calls to a custom directive:

<div ng-controller="SomeController">
<myDirective data="myData.Where('IsOpen',true)"></myDirective>
<myDirective data="myData.Where('IsOpen',false)"></myDirective>
</div>

myData is an array and Where() is an extension method that iterates over the array returning a new array containing any items from the original where the IsOpen property matches the bool value in the second parameter.

In the controller I set $scope.data like this:

DataService.getData().then(function(results){
$scope.data = results;
});

Calling the Where() extension method from the directive like in the above markup was the problem. To fix this issue I moved the call to the extension method into the controller instead of the markup:

<div ng-controller="SomeController">
<myDirective data="openData"></myDirective>
<myDirective data="closedData"></myDirective>
</div>

and the new controller code:

DataService.getData().then(function(results){
$scope.openData = results.Where('IsOpen',true);
$scope.closedData = results.Where('IsOpen',false);
});

ASP.NET MVC and WebAPI – “The parameters dictionary contains a null entry for parameter”

WWW Logo

When working in ASP.NET MVC and WebAPI you may run across this exception.  Consider the following controller action:

[HttpPost]
[Route("api/SomeController/SomeAction")]
public void SomeAction(int id)
{
.....
}

And a simple AngularJS ajax call to the method:

var someAction= function (id) {
var d = $q.defer();
$http.post('api/SomeController/SomeAction', id)
.success(function (data) {
d.resolve(data);
})
.error(function (data) {
d.reject(data);
});
return d.promise;
};

The ajax call can be from any client-side framework, AngularJS, jQuery, etc.  What’s important is the routing to the MVC controller action and, more specifically, how WebAPI performs the parameter binding.

By default, for value types (int, bool, string, etc) WebAPI will try and get a parameter value for a simple type from the URL.  This obviously creates an issue in this case since we are using a POST request; the parameter value will be in the body of the HTTP request and not in the URL.

In order to resolve this issue the parameter in the controller action must be decorated with the [FromBody] attribute indicating that WebAPI should look in the HTTP request body when performing the parameter binding.
The controller action would then look like this:

[HttpPost]
[Route("api/SomeController/SomeAction")]
public void SomeAction([FromBody] int id)
{
.....
}

Now the parameter binding works and the parameter value is sent to the action method just fine.

Mike Wasson has an excellent article with a lot more details here:

http://www.asp.net/web-api/overview/formats-and-model-binding/parameter-binding-in-aspnet-web-api