I have an Angular controller that defines a scoped variable that consist of an array of objects. Each object is a tagName and its value is a list of services associated to those tags:
$scope.recordedServices = [{"myTag" : [{ url : "http://service0"}, { url : "http://service1" }] }];
After the page is loaded {{recordedServices}} prints correctly:
[{"myTag":[{"url":"http://service0"},{"url":"http://service1"}]}]
In that controller I have a replaceList function that replaces the whole $scoped.recordedServices list:
$scope.replaceList = function(){
$scope.recordedServices = [ {"myTag" : [{url:"http://replacedList"}] }];
}
When calling it, everything works as expected, {{recordedServices}} is now:
[{"myTag":[{"url":"http://replacedList"}]}]
Now the problem. What I really want to do is add a new service to "myTag":
$scope.addToList = function(){
$scope.recordedServices["myTag"].push({url:"http://addedService"});
}
But it fails because $scope.recordedServices["myTag"] doesn't exist, the actual structure of the $scoped.recordedServices list is:
$scope.recordedServices: Array[1]
0 : Object
$$hashKey : "object:33"
myTag : Array[1]
0 : Object
$$hashKey : "object:36"
url : "http://replacedList"
What is the correct (Angular) way to add an element to that array?
UPDATE:
One possible solution would be doing:
$scope.addToList2 = function(){
if($scope.recordedServices[0] == null){
$scope.recordedServices[0] = [];
}
if($scope.recordedServices[0]["myTag"] == null){
$scope.recordedServices[0]["myTag"] = [];
}
$scope.recordedServices[0]["myTag"].push({url:"http://addedService"});
}
But this works only if $scope.recordedServices was initialized in the controller (for instance: $scope.recordedServices = [{"myTag" : [{ url : "http://service0"}, { url : "http://service1" }] }];). However if initially it is $scope.recordedServices = [] it doesn't work.
{{recordedServices}} prints [[]]
Inspecting the variable the content is as follows. It looks similar with the only differenced that myTag[0] doesn't contain $$hashKey.
$scope.recordedServices: Array[1]
0 : Array[0]
$$hashKey : "object:68"
length : 0
myTag : Array[1]
0 : Object
url : "http://addedService"
$scope.recordedServices is an array. You should use an index:
Change this:
$scope.recordedServices["myTag"].push({url:"http://addedService"});
to this:
$scope.recordedServices[0]["myTag"].push({url:"http://addedService"});
UPDATE
You can check if it is empty, if so, add myTag object too:
if ($scope.recordedServices.length == 0){
$scope.recordedServices.push({"myTag": [{url:"http://addedService"}]});
}else{
$scope.recordedServices[0]["myTag"].push({url:"http://addedService"});
}
You can define your $scope.recordedServices=[] as an empty array inside your controller. So now you can play with it inside the controller and view as you wish.
Push new record like this -
$scope.addToList = function(){
$scope.recordedServices.push({url:"http://addedService"});
}
Related
I have a class definition…
class anObj {
"ID" : string;
dialog: {[id : number]:{hide: boolean;}} = {
0 : {"hide": false},
14 : {"hide": false}
}
}
class manyObjects {
myGroup: anObj [] = [];
}
...
public stuff = manyObjects;
This totally works just the way I'd like for it to...I can use the id value as a direct key...
var x:number = 1 //used for a different tier of logic
stuff.myGroup[x].dialog[14].hide!=true
Here's where I'm stuck... I'd like to add more dialogs to the group. I get all the way our to...
stuff.myGroup[x].dialog
and can't figure out how to add something like with a push...
.push(7 : {"hide": true})
for example, I can type this line and the IDE says it's ok...
stuff.myGroup[x].dialog[[id=7].push({"hide": false})];
however, when I check, the element does not get added to the array...
What I could gather from your code is that you're trying to add a new dialog to the object contained in the "dialog" property of anObj, which is not an array. It's an object with an expected structure in typescript: every property of that object should be a number, and the value of every property should be of type {hide: boolean;}.
From there, it's quite easy, you add a new property (or overwrite an existing one) as you do for any JS object:
stuff.myGroup[x].dialog[7] = {hide: false};
Again, stuff.myGroup[x].dialog is an object, not an array, the array is stuff.myGroup.
If you want to add another "group" to myGroup then you'd do something like:
stuff.myGroup.push(new anObj());
EDIT
Example that ignores the noise created by extra objects like stuff and my group, but demonstrates adding a new key-value pair:
class anObj {
"ID" : string;
dialog: {[id : number]:{hide: boolean;}} = {
0 : {"hide": false},
14 : {"hide": false}
}
}
class manyObjects {
myGroup: anObj [] = [];
}
var obj = new anObj();
obj.dialog[7] = { hide: true };
console.log(obj);
You can try that in typescript playground -> https://www.typescriptlang.org/play/?ssl=14&ssc=18&pln=1&pc=1#code/MYGwhgzhAEYHYHkBGAraBvaAoa0BEAkgCJ7QBc0EALgE4CWcA5gNw7QAmdYIA9oxegDadduWhwArgFskAUxoBdMugAWI2RSQ8eIWfGYBfA9AC8GNrgAMY9HjXtZeCgDNuEWQYA0F6AEYALDZ26k7QriDuBmzGuNhRoJAwUvAAnsgossBUMOhsUikA4jQ8EgAOFPDp0IIKptUKrFFYAG5gNNA8qHVwsgDusIioABQAlKydKAB0nNx8ggDstWaY9hrQtBKy0AaswDxwEDqyk7yMQxNjQA
Update 2
To return the enumerable keys of an object, you can use the Object.keys method. See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys
console.log(Object.Keys(obj));
I am pretty new to JavaScript. I have a nested object and I want to be able to reorder the key/value pairs. I tried looking for a solution at a lot of places online but mostly found answers to sort a 2-D array, nothing with this complexity level.
My object looks something like this:
id:{
Category1 : {
a : {count:1, volume:5}
b : {count:2, volume:10}
}
Category2: {
a : {count:4, volume:8}
b : {count:10, volume:4}
}
}
and I want to sort it on the basis of the name instead of category. Intedend result:
id:{
a : {
Category1 : {count:1, volume:5}
Category2 : {count:4, volume:8}
}
b: {
Category1 : {count:2, volume:10}
Category2 : {count:10, volume:4}
}
}
You can do it using
let id = {
Category1 : {
a : {count:1, volume:5},
b : {count:2, volume:10}
},
Category2: {
a : {count:4, volume:8},
b : {count:10, volume:4}
}
}
for(obj in id){
for(obj2 in id[obj]){
id[obj2] = id[obj2] || {};
id[obj2][obj] = id[obj][obj2];
}
delete id[obj];
}
console.log(id);
in this code
for(obj in id)
traverses all properties of id so obj would be in the set {"Category1", "Category2"} and id[obj] would refer to the sub object
for(obj2 in id[obj])
traverses the property of the sub object and so obj2 would be in the set {"a", "b"}
id[obj2] = id[obj2] || {};
initialises the new property of id if it doesn't already exist i.e id["a"] and id["b"]
id[obj2][obj] = id[obj][obj2];
assigns the sub sub object ({count:1, volume:5}) to the new property within the sub property obj
delete id[obj];
lastly delete the current property since it is not of use anymore
I am using two different array object initialPermissionArr[item.id] and newPermissionArr[roleId] in two different functions
function(item){
vm.initialPermissionArr[item.id] = item.permissions.map(function (permission) {
permission.status = true;
return permission;
});
}
staticArr[item.id] = item.permissions.map(function (permission) {
permission.status = true;
return permission;
});
newpermissionArr[item.id] = vm.initialPermissionArr[item.id];
Below function updates the array, if same object is found it updates the status and if new object is found it pushes to newPermissionArr
function onChanageOfPermission(roleId,item) {
var flag = false ;
for (var key in newpermissionArr[roleId]){
if(newPermissionArr[roleId][key].id == item.id){
flag = true;
newPermissionArr[roleId][key].status = item.status;
break;
}
}
if (!flag) {
newPermissionArr[roleId].push(item);
}
}
So when newPermissionArr[roleId][key].status = item.status; is updated it also update the status in the initialPermissionArr[item.id] also.
And initial declaration is
var newPermissionArr = [];
var staticArr = [];
where for eg item is
{
roleId : 1,
permissions : [{"name": "A", "id" : 1},{ "name" : "B", "id" : 2 }]
}
I need initial object Array to remain same and at the end i need to compare the initial array with the modified array and need to find the reference however on updating the status it updates in both array. How to avoid this ?
The arrays reference the same object. To modify just one of them, you should use slice() function for clone the array:
newpermissionArr[item.id] = vm.initialPermissionArr[item.id].slice();
This is happening because of following line of code
newpermissionArr[item.id] = vm.initialPermissionArr[item.id];
Here object is passed by reference, so whenever newpermission is updated intialpermission will also be updated.
To fix this just copy the intialPermissionArr to newPermissionArr.
Unfortunately,plain javascript does not have any function like angular.copy. So you will have to do this in following way-
newrPermissionArr[item.id] = JSON.parse(JSON.stringify(vm.intialPermissionArr[item.id]));
this should fix your problem.
When you assign something to a and b and it is a pointer in memory to object c. Then as soon as you change it to c2 both a and b will get c2 from that point as they were just pointers to same location.
I initialize here
$scope.statuses = [];
Then if I simply set the data from $http.get to the $scope variable, that "works" but I need to filter it down more.
$scope.statuses = result.data.Devices;
console.log($scope.statuses);
That returns the array of data like this in dev tools console output
0: Object
$$hashKey
:
"object:5"
Aid
:
"oAAABTUAAg=="
DKiIndex
:
"DKi00000002"
DefaultPayload
:
"C:\ProgramData\"
DeviceId
:
"00022B9A000000010001"
DeviceStatus
:
3
ManifestIdList
:
Array[3]
PendingManifestId
:
null
PendingTimeStamp
:
"0001-01-01T00:00:00"
Sha
:
"R2tiZRQgY/iohXZt5O4HaQwtVe/adWU2VOcKaelJ3Us="
StagedManifestIdList
:
Array[0]
However I only WANT some specific data
$scope.statuses = result.data.Devices.DeviceStatus;
Why does it say 'undefined' and how do I do this?
So 0: Object DeviceStatus is there.. :/
<div ng-app="app" ng-controller="DeviceController as vm">
...
<tr ng-repeat="device in vm.devices">
<td>{{device.DeviceId}}</td>
<td>{{device.DeviceStatus}}</td>
<td>{{device.Aid}}</td>
<td>{{device.Sha}}</td>
</tr>
...
Essentially I wish to manipulate the data in Javascript /angular (.js) before it makes it to the ng-repeat loop
Thus is $scope even the proper thing to even be using?
I know that I have some data to change for example
Some data in a field was surrounded by [] e.g. [01,02,03] so doing
{{ device.aid.join(',') }} would "fix" the [] issue but i need to have some function like this? where can i use this?
// usage {{displayArchived(item.archives)}}
$scope.displayArchived = function(archives){
return (archives.length > 0) ? archives.join(',') : 'none';
};
Then will a "let" help for numbers of DeviceStatus?
let statuses = ['Old Device', 'New Device', 'Activated', 'Unactivated'];
In this instance, result.data.Devices is an array of objects that looks something like this:
[
{DeviceId : "00022B9A000000010001" DeviceStatus : 3 .... },
{DeviceId : "00022B9A000030011111" DeviceStatus : 9 ...},
....
]
So when you try to get result.data.Devices.DeviceStatus, there is no array element called DeviceStatus, which is why you are getting back undefined.
You will need to iterate through the array of Devices to get a specific Device's DeviceStatus:
angular.forEach(result.data.Devices, function(value, index){
$scope.statuses.push(value.DeviceStatus);
});
or you can access directly if you know which device you want:
var index = 1;
$scope.statuses = result.data.Devices[index].DeviceStatus;
EDIT:
If you want to get all of the devices and display {{ device.DeviceStatus }} with your template, here is a solution:
Code:
$scope.devices = result.data.Devices;
Template:
<div ng-repeat="device in devices">
{{ device.DeviceStatus }}
</div>
In our code, we assign the request.data.Devices array to $scope.devices. Then in the template, we use ng-repeat to go through each device in $scope.devices and display the device's DeviceStatus.
EDIT2:
In order to match the DeviceStatus to it's actual name, you can create a custom filter.
In your code create the filter:
app.filter('deviceStatus', function () {
return function (status_id) {
var statuses = ['Old Device', 'New Device', 'Activated', 'Unactivated'];
return statuses[status_id];
};
});
You can use the new filter in your template now:
<td>{{device.DeviceId | deviceStatus}}</td>
We pipe the DeviceId into our custom deviceStatus filter in order to get the correct status name in the template.
So I have an empty array defined.
admin.links = [];
I then push items to it like so.
angular.forEach(links, function(value, key) {
var title = value.title;
var url = value.url;
admin.links.counter.push({
'parent' : counter,
'name' : title,
'url' : url
})
})
When I run the code above I get an error
Cannot read property 'push' of undefined
counter is a dynamic value. How would I do this?
I want it to be something like admin.links.0
What you mean with:
counter is a dynamic value.
admin.linksis an array, so if you want to add items you must use:
admin.links.push
if, instead, you want links to be an object you should initialize it with:
admin.links = {
counter: []
}
admin.links.counter.push()