Reputation: 15089
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
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
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
Reputation: 411
You could use
this
instead of
$scope
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
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:
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
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
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