What Im Attempting to Do
Im pushing an object into an array, this works as expected. But as I try to update one of the objects in the array via their $parent.$index and $index all objects are updated.
Object Being Pushed Into Array (Multiple Times)
// Array for Objects
$scope.arr = []
// Object to be pushed into Array
$scope.obj = {
content:[
{
type:"text",
data:"This is Dummy Text",
style:{
"height":"500px"
}
},
// Could be more than one Object within Content
]
}
The above object will be pushed into $scope.arr multiple times, within the view the objects are looped.
// Looped Arrays
<div ng-repeat="l1 in arr track by $index">
<div ng-repeat="l2 in l1.content" ng-style="l1.style">{{l1.data}}</div>
</div>
Updating by $parent.$index and $index
So at this point I have pushed the $scope.obj multiple times into $scope.arr and this is where the issue occurs.
I need to update only one of the $scope.obj's in the $scope.arr via a line of the code like the following:
// Set $index's to target the specific array items
var parentIndex = 0
var index = 0
$scope.arr[parentIndex].content[index].style['height']
An example of a possible update would be the following:
var o = parseInt($scope.arr[parentIndex].content[index].style['height'])
var n = o + 1
$scope.arr[parentIndex].content[index].style['height'] = new + 'px'
At the moment the above will update all inserted/pushed objects in $scope.arr despite setting the correct $parent.$index and $index. Where as I need to target and update one, not all.
I must be missing something here, any help or guidance is greatly appreciated.
When pushing, try to do a copy of the object like so:
$scope.arr.push(angular.copy($scope.obj));
Since you keep the important parts of your code secret (how you insert the "objects" into the "array") I can only guess, that you're "inserting" the same object to multiple places (means: you keep the reference to the same object in multiple indexes in the array, so basically you have only 1 object) and then when you change the object in "1 place" using array[1].object.a=2, then you'll see the change in "each" index: array[4].object.a==2, because they refer to the same object actually
Related
I have a list with three empty objects like:
TimePickerList =[{},{},{}];
For example, I want to add 1 and 2 to the first argument of this list like this:
TimePickerList[0].push("1") // I know it's wrong and I can't use push like this.
TimePickerList[0].push("2")
And i want to get this:
TimePickerList =[{"1","2"},{},{}];
Is there any way to do this? I mean, can I update an argument's value?
Not really. I think you looking for an array with arrays.
const t = [[],[]];
t[0].push(1);
t[0].push(2)
console.log(t)
You can update values stored in arrays like such:
TimePickerList = [{}, {}, {}];
TimePickerList[0].a = 1;
console.log(TimePickerList)
// [{ a: 1 }, {}, {}]
The reason it wasn't working for you is because you were trying to push a value to an object. If you want to push values then push to an array, therefore using square brackets [] instead of curly braces {}.
I've spent the last couple hours going through some very similar answers to the above question but after a few implementations of loops and reduce I still have not gotten the solution I need.
I am getting an array of objects via service calls. I am pushing those controller array objects to another array because I need a single array to load data into a multi select. I.E.
StatesService.getAreaCities().then(function(response) {
controller.cities = response.data.rows;
controller.areaOptions.push(controller.cities);
});
StatesService.getAreaStates().then(function(response) {
controller.states = response.data.rows;
controller.areaOptions.push(controller.states);
});
controller.areaOptions = [];
This is an example of how I expect and need my array object to look.
With no modification this is how my array looks with those array objects pushed in.
How do I get the above data structure like the 1st image, an array of objects? I tried a solution with reduce()
var newCities = controller.cities.reduce(function(city){
return controller.city;
}, {});
controller.areaOptions.push(newCities);
but it wasnt what I was looking for because it returned a single object with all city property and all its values. I need each object to contain city and its value.
EDIT
I figured out the solution! Thanks to Lex.
I looped over each object in the array in each service and pushed the property.
Thanks to all for steering me in the right direction to figure this out, even the person that downvoted me :)
StatesService.getAreaCities().then(function(response) {
controller.cities = response.data.rows;
controller.cities.forEach(function(city){
controller.areaOptions.push(city);
});
});
Looks like response.data.rows is an array. So when you push response.data.rows into controller.areaOptions you are adding the rows array as an array element. (Basically making it a 2-dimensional array)
You should use Array.prototype.concat
I'm not sure if this is a bug or if I have a complete misunderstanding of Javascript, but this is what happens:
I take an object with two arrays inside it, one representing the current queue of IDs and another representing the total queue of IDs (hypothetical situation)
var mainObject = {
object1:[],
object2:[]
};
In a function, we set the two property arrays to the same variable which holds the array needed before we can start processing the queue.
var randomVar = [1,2,3,4];
mainObject.object1 = randomVar;
mainObject.object2 = randomVar;
Now we want to make use of the splice method to remove the first index from object1 while keeping it on object two.
mainObject.object1.splice(0,1);
The result of the object is now as follows:
mainObject = {
object1:[2,3,4],
object2:[2,3,4]
};
meaning that both of the properties were spliced when we only asked Javascript to run it once.
See JS Fiddle for live example:
https://jsfiddle.net/ypow6y8g/
Is there something I'm missing or is this just another night spent with loose JS?
You have one array, and two variables whose value is a reference to that array. When you modify the value of one of those variables, you modify the other one as it's the same.
If you want your arrays to be independent, clone one:
var randomVar = [1,2,3,4];
mainObject.object1 = randomVar;
mainObject.object2 = randomVar.slice(); // slice returns a new array
My javascript/angular code is performing contrary to what i expect and i can't figure out why. I have an angular service defining two methods for getting and setting items
app.factory('orderItems',['Restangular','$mdDialog',function(Restangular,$mdDialog){
var orderItems = [];
return{
getOrderItems: function(){
return orderItems
},
setOrderItems: function(item,fillings){
...
orderItems.push(item)
...
}, ...
Items are set using ng-click and passing an item and checked addons;
product_template.html
<div >
<md-button class="md-raised" ng-click="showAddons($event,product)">Add to Cart</md-button>
</div>
controller
app.controller('productCtrl',['$scope','getProducts','orderItems','Restangular','$mdDialog',function($scope,getProducts,orderItems,Restangular,$mdDialog){
//$scope.products;
$scope.products = getProducts(Restangular);
// Dialog
$scope.showAddons=function(ev,product){
$mdDialog.show({
locals:{current_Product: product,},
//inline controller
controller:['$scope','current_Product','orderItems',function($scope,current_Product,orderItems){
$scope.product = current_Product;
$scope.addons = {
checked:[],}
...
}],
templateUrl: 'dialog.html',
targetEvent: ev,
})
}
}])
dialog.html
<md-list-item ng-repeat="addon in product.productAddons">
...
<md-checkbox class="md-secondary" checklist-model="addons.checked" checklist-value="addon"></md-checkbox>
</md-list-item>
<md-button class="md-raised" style="background-color:#f44336; color:#fff" ng-click="setOrderItems(product,addons.checked)">Done</md-button>
The problem arises when setOrderItems is passed a similar object more than once. The first time around, orderItems.push works as expected then when a similar product is passed to 'setOrderItems', it is pushed to 'orderItems' but all items in 'orderItems' are updated to this currently set item.
That is, if orderItems was[{name:"chicken burrito",fillings:[{name:"cabbage"},{name:"cheese"}],...}] before, after setting a similar item but with diff fillings, orderItems is updated to [{name:"chicken burrito",filling:[{name:"guac"}],...},{name:"chicken burrito",filling:[{name:"guac"}],...}] . If setOrderItems is passed a different product say [{name:"goat burrito",...}] it is added as expected.
Can't happen to find a similar issue around. What am i doing wrong. I want to be able to add similar items but with different fillings to orderItems.
It's difficult to see exactly with the code you've given. But if I'm following what you are doing correctly, then the problem is probably here:
$scope.products = getProducts(Restangular);
you are getting a set of products, I assume that there is an object for chicken burrito and an object for goat burrito. The problem, I think, is that you are using the same object for every chicken burrito. So when you push it onto the array you are pushing a reference to the object in products, you then edit that object and push it again. But again you are pushing a reference to the same object. If you actually look at your array before the second push, I suspect you will see that the object already on the array is already altered to match the one you are about to push because it's the same object.
To solve this, you need to make a copy of the object. To do that, take a look at this question:
Deep copying objects in angular?
angular.copy should let you copy your product so that you aren't always pushing the same object.
For example, you could do this:
setOrderItems: function(item,fillings){
...
var itemCopy = angular.copy(item);
orderItems.push(itemCopy);
...
}
Now you are always pushing a copy into your array and your array will fill with independent objects.
I'm using a specific game making framework but I think the question applies to javascript
I was trying to make a narration script so the player can see "The orc hits you." at the bottom of his screen. I wanted to show the last 4 messages at one time and possibly allow the player to look back to see 30-50 messages in a log if they want. To do this I set up and object and an array to push the objects into.
So I set up some variables like this initially...
servermessage: {"color1":"yellow", "color2":"white", "message1":"", "message2":""},
servermessagelist: new Array(),
and when I use this command (below) multiple times with different data called by an event by manipulating servermessage.color1 ... .message1 etc...
servermessagelist.push(servermessage)
it overwrites the entire array with copies of that data... any idea why or what I can do about it.
So if I push color1 "RED" and message1 "Rover".. the data is correct then if I push
color1"yellow" and message1 "Bus" the data is two copies of .color1:"yellow" .message1:"Bus"
When you push servermessage into servermessagelist you're really (more or less) pushing a reference to that object. So any changes made to servermessage are reflected everywhere you have a reference to it. It sounds like what you want to do is push a clone of the object into the list.
Declare a function as follows:
function cloneMessage(servermessage) {
var clone ={};
for( var key in servermessage ){
if(servermessage.hasOwnProperty(key)) //ensure not adding inherited props
clone[key]=servermessage[key];
}
return clone;
}
Then everytime you want to push a message into the list do:
servermessagelist.push( cloneMessage(servermessage) );
When you add the object to the array, it's only a reference to the object that is added. The object is not copied by adding it to the array. So, when you later change the object and add it to the array again, you just have an array with several references to the same object.
Create a new object for each addition to the array:
servermessage = {"color1":"yellow", "color2":"white", "message1":"", "message2":""};
servermessagelist.push(servermessage);
servermessage = {"color1":"green", "color2":"red", "message1":"", "message2":"nice work"};
servermessagelist.push(servermessage);
There are two ways to use deep copy the object before pushing it into the array.
1. create new object by object method and then push it.
servermessagelist = [];
servermessagelist.push(Object.assign({}, servermessage));
Create an new reference of object by JSON stringigy method and push it with parse method.
servermessagelist = [];
servermessagelist.push(JSON.parse(JSON.stringify(servermessage));
This method is useful for nested objects.
servermessagelist: new Array() empties the array every time it's executed. Only execute that code once when you originally initialize the array.
I also had same issue. I had bit complex object that I was pushing in to the array. What I did; I Convert JSON object as String using JSON.stringify() and push in to the Array.
When it is returning from the array I just convert that String to JSON object using JSON.parse().
This is working fine for me though it is bit far more round solution.
Post here If you guys having alternative options
I do not know why a JSON way of doing this has not been suggested yet.
You can first stringify the object and then parse it again to get a copy of the object.
let uniqueArr = [];
let referencesArr = [];
let obj = {a: 1, b:2};
uniqueArr.push(JSON.parse(JSON.stringify(obj)));
referencesArr.push(obj);
obj.a = 3;
obj.c = 5;
uniqueArr.push(JSON.parse(JSON.stringify(obj)));
referencesArr.push(obj);
//You can see the differences in the console logs
console.log(uniqueArr);
console.log(referencesArr);
This solution also work on the object containing nested keys.
Before pushing, stringify the obj by
JSON.stringify(obj)
And when you are using, parse by
JSON.parse(obj);
As mentioned multiple times above, the easiest way of doing this would be making it a string and converting it back to JSON Object.
this.<JSONObjectArray>.push(JSON.parse(JSON.stringify(<JSONObject>)));
Works like a charm.