alexandernst
alexandernst

Reputation: 15089

Make a copy of data held by $scope

Let's say I have a few variables in a $scope and I want to create a new object that contains those variables, without all the internal stuff that Angular holds in $scope. I don't necessarily know the names of the $scope variables that I want to copy.

Something like:

$scope.a = "Test";
$scope.b = {x: 1, y: 2};
$scope.c = 99;
//possibly other unknown variables

var obj = angular.copy_without_angular_stuff($scope);

How can I get just the relevant data?

Upvotes: 1

Views: 138

Answers (6)

Sudhansu Choudhary
Sudhansu Choudhary

Reputation: 3360

I am omitting any functions on scope or any angular variables(which tend to start with $), also injecting $rootScope such that no inherited properties from $rootScope to $scope would get copied to the new object, obj and have come up with this,

<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope, $rootScope) {
   $scope.a = "Test";
$scope.b = {x: 1, y: 2};
$scope.c = 99;
var obj = {};
angular.extend(obj, $scope);
console.log("obj is "+obj);
for(var k in $scope) {
    if(!(Object.hasOwnProperty.call($rootScope, k))) {
if(typeof $scope[k] != "function")
if(k.indexOf("$") != 0){
        obj[k] = $scope[k]; 
console.log("key is "+k);
console.log("value is "+obj[k]);  
    }
}
}
});
</script>

Upvotes: 0

Grundy
Grundy

Reputation: 13381

$scope object have a few interval properties, that starts from $, so as workaround you can simply copy just properties that not start from $, or even create map for internal $scope properties and if property not in map - copied it.
Note: list of internal properties can be different in different angular versions

angular.module('app', [])
  .controller('ctrl1', function($scope) {
    function clearCopy(scope) {
      var dest = {};
      for (var i in scope) {
        if (scope.hasOwnProperty(i) && i[0] !== '$' && i !== 'this') {
          dest[i] = scope[i];
        }
      }
      return dest;
    }
    $scope.a = "Test";
    $scope.b = {
      x: 1,
      y: 2
    };
    $scope.c = 99;

    $scope.copy1 = clearCopy($scope);
  })
  .controller('ctrl2', function($scope) {
    function clearCopy(scope) {
      var internalProperiesMap = {
          $$ChildScope: true,
          $$childHead: true,
          $$childTail: true,
          $$listenerCount: true,
          $$listeners: true,
          $$nextSibling: true,
          $$prevSibling: true,
          $$watchers: true,
          $$watchersCount: true,
          $id: true,
          $parent: true
        },
        dest = {};
      for (var i in scope) {
        if (scope.hasOwnProperty(i) && !internalProperiesMap[i]) {
          dest[i] = scope[i];
        }
      }
      return dest;
    }
    $scope.a = "Test";
    $scope.b = {
      x: 1,
      y: 2
    };
    $scope.c = 99;
    $scope.copy2 = clearCopy($scope);
  }).controller('ctrl3', function($scope) {
    function clearCopy(scope) {
      var internalProperiesMap = {
        $$ChildScope: true,
        $$childHead: true,
        $$childTail: true,
        $$listenerCount: true,
        $$listeners: true,
        $$nextSibling: true,
        $$prevSibling: true,
        $$watchers: true,
        $$watchersCount: true,
        $id: true,
        $parent: true
      };
      return Object.keys(scope).reduce(function(acc, el) {
        if (el[0] !== '$' && typeof scope[el] !== "function") {
          acc[el] = scope[el];
        }
        return acc;
      }, {});
    }
    $scope.a = "Test";
    $scope.b = {
      x: 1,
      y: 2
    };
    $scope.c = 99;
    $scope.fun = function(d){return d;};

    $scope.copy3 = clearCopy($scope);
  console.log($scope.copy3);
  });
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.0/angular.js"></script>
<div ng-app='app'>
  <div ng-controller='ctrl1'>copy 1: {{copy1}}</div>
  <div ng-controller='ctrl2'>copy 2: {{copy2}}</div>
  <div ng-controller='ctrl3'>copy 3: {{copy3}}</div>
</div>

But anyway it seems like XY problem

Upvotes: 1

jsuser
jsuser

Reputation: 411

You could use

this

instead of

$scope

Plnkr

Controller:

angular.module('myApp').controller('MyCtrl', function(){
  var vm = this;

  vm.a = 'test';

  vm.b = {a: 'a', b: 'b'};

  vm.c = 123;

  var obj = vm;

});

In my view, I displayed each of the values attached to VM. As well as VM, where it shows just a, b, and c as the objects attached to VM.

vm.a: {{vm.a}}
<br/>
vm.b: {{vm.b}}
<br/>
vm.c: {{vm.c}}
<br/>

vm: {{vm}}

UPDATE

If you don't get to choose whether it's on $scope or not, then here is a new plnkr that uses $scope.

Controller:

angular.module('myApp').controller('My2ndCtrl', function($scope) {
  $scope.a = 'test';

  $scope.b = {a: 'a', b: 'b'};

  $scope.c = 123;

  var obj = {};


  for(var k in $scope) {
    if($scope.hasOwnProperty(k) && k.indexOf('$') < 0) {
      obj[k] = $scope[k]
    }
  }
 console.log(obj);
});

The obj is then:

{a: "test", b: Object, c: 123}

Upvotes: 2

Mathew Berg
Mathew Berg

Reputation: 28750

I can't believe I'm actually suggesting this. You should really refactor your code so you don't have to do it. Regardless if you actually need to do this...

$scope.test = 4;
var copiedObject = {};
for(var key in $scope){
    if(key[0] != '$' && key != 'this'){
        copiedObject[key] = $scope[key];
    }
}
console.log(copiedObject);

This will loop through all the keys and rip out the angular specific stuff. Here's a jsFiddle of it:

http://jsfiddle.net/n8bz4L7e/

Note: If you have references in the object, or other $scope variables saved for some reason this will copy those over as well. As someone mentioned elsewhere, this is most likely an XY Problem.

Upvotes: 1

Andrei Nemes
Andrei Nemes

Reputation: 3122

If you're happy with using underscore you can do

var obj = _.extendOwn({}, $scope);

Otherwise just manually copy the properties in a loop

var obj = {};

for(var k in $scope) {
    if(Object.prototype.hasOwnProperty.call($scope, k)) {
        obj[k] = $scope[k];   
    }
}

Upvotes: 0

lfergon
lfergon

Reputation: 973

A possible solution could be copy the properties of one object, in this case $scope, into another object:

for(var k in $scope) {
  secondObject[k] = $scope[k];
}

Upvotes: 0

Related Questions