TypeError: Attempted to assign to readonly property. in Angularjs application on iOS8 Safari

All we need is an easy explanation of the problem, so here it is.

Our Mobile App is getting “TypeError: Attempted to assign to readonly property.” only on IOS 8 and the stack traces are not helpful and seem to be in Angular code.

This might be happening because of the “use strict” on top level of Angularjs code.
My questions are (1) why did it start happening only on IOS8? is this an IOS8 bug?
(2) or is this an angular bug surfaced on IOS8? (3) Or maybe we are violating strict mode rules but only IOS8 started to catch them! I am skeptical about the third option because strict mode is supported by other major browsers.

I have found one similar reported issue here.

How to solve :

I know you bored from this bug, So we are here to help you! Take a deep breath and look at the explanation of your problem. We have many solutions to this problem, But we recommend you to use the first method because it is tested & true method that will 100% work for you.

Method 1

Looks like this is an IOS8 bug

At least the guys at ember.js will temporarily strip the ‘use strict’ from their code until it’s fixed.
Ember.js issue

Method 2

SOLUTION
Note:

  1. angular.copy didn’t work for me
  2. lodash cloneDeep didn’t work either.
  3. removing “use strict”; didn’t help – It just removed the error being logged in a try/catch arround the “erroneous” assignment to a readonly value

For us, the value that was being passed back from the SQL promise value was an array of objects.

The values that we were getting “read only” error on were strings, bools, and numbers.

console.log('this will log');
sqlReturnArray[0].name = "Bob"; // read only error here
console.log('wouldnt get to here to log');

I figured, well, if I can’t assign values to properties on THOSE objects within the array, why can’t I just copy over all the objects’ values? Assignment of objects is by reference so just doing a loop over the array won’t help. You need to loop over the keys and values.

This solved our problem

// where sqlReturnArray is the object given from the SQL promise
var newArrayOfObjects = [];
angular.forEach(sqlReturnArray, function (obj) {
  var newObj = {};
  angular.forEach(obj, function (val, key) {
    newObj[key] = val;
  });
  newArrayOfObjects.push(newObj);
});

Method 3

I just had this error and the fix was pretty simple.

My Code was-

    $http.get('/api/v1/somedata').then(function(result){
        $scope.data.somedata = result.data.list;
    });

I get the TypeError in the assign. Because I haven’t defined $scope.data.somedata anywhere and it got $scope.data undefined and trying to assign some property to it initiated the error.

I simply put $scope.data = {somedata : [] } in the top of the controller. I can also get rid of this error by changing $scope.data.somedata to $scope.somedata because any property of the $scope object that is undefined will end up to the $rootscope and won’t give any error. I found this is pretty hard to debug my view-model. And also for this TypeError I can find out what exactly is wrong.

Method 4

I had it with a form.
my issue was because of binding an SQL Return Object to an input.
after coping with angular.copy() problem resolved.

try to copy your return values and retry.

$scope.yourFunc= function(result) {
        var item = angular.copy(result.rows.item(0));
        ...
    };

Note: Use and implement method 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply