Search code examples
javascriptangularjsjsonumbraco7

Malformed JSON when loading $scope.model.value in custom Umbraco data type


I'm occasionally noticing strange behaviour in the data that Umbraco initializes my data types $scope.model.value value with.

I'm working with Umbraco 7.11.1, and my custom data type is built around a complex JSON based data model.

During "Save and Publish" (from the Umbraco back-office), Umbraco seems to accept the JSON that my controller has stored in $scope.model.value - no error dialogs are displayed, console errors logged, etc.

When the back-office reloads however, Umbraco attempts to initialize my data type with a partial, malformed JSON string, rather than the expected JSON object (ie that was previously saved).

I'm following the regular pattern for implementing a custom data type, via an angularjs controller:

angular.module('umbraco')
.controller('MyDataType', ['$scope', function ($scope) {

    var loadedData = $scope.model.value;

    // Do stuff with "loadedData"

    $scope.model.value = loadedData;
}])

The issue seems to occur when I have a large amount of data in my JSON model (ie json that would serialize to ~150 characters or more)

Is there a limit to the amount of data that I can store in an Umbraco data type? Or is there something else that I am overlooking here?


Solution

  • The solution to this problem was to sanitize the JSON data that my controller stored in $scope.model.value.

    It seems that Umbraco is sensitive to the extra metadata "stuff" that angularjs drops into scope variables ("$$hashKey", etc) and this appears to be what caused my datatype to be subsequently initialized with a malformed JSON string rather than the expected JSON object.

    In the end, I opted to:

    1. clone the model value (ie $scope.myModel as shown below) that my data type was initialized with
    2. set up a $watcher to synchronize $model.scope.value with any changes made to $scope.myModel
    3. during synchronization, store a sanitized clone of $scope.myModel (ie that excludes internal angular metadata like "$$hashKey") in $model.scope.value

    Example pseudo code demonstrating solution:

    angular.module('umbraco')
    .controller('MyDataType', ['$scope', function ($scope) {
    
        $scope.myModel = cloneValue($scope.model.value)
    
        var endWatcher = $scope.$watch('myModel', function() { 
    
            $scope.model.value = cloneAndSanitizeMyModel($scope.myModel)
        });
    
        $scope.$on('$destroy', function() {
            endWatcher();
        });
    }])