why are key value pairs being added twice to state? - reactjs

I have the following function:
handleAddItem(s) {
var key = Object.keys(s)[0];
var value = s[key];
var allItems = {...this.state.items};
allItems[key] = allItems[key];
allItems[key].push({name: value});
var ourItems = {};
ourItems = allItems[key];
ourItems.push({name: value });
this.setState({items: allItems});
}
I realize that ourItems isn't really suppose to be doing anything but why when those three lines are added are the key value pairs being added twice to state?

Only primitives in JavaScript are passed by value. Everything else is passed by reference.
By setting ourItems = allItems[key] you make the ourItems variable point to the allItems[key] array. It does not copy the array. Because of that you actually push the object twice into the same array.

Related

Clone element of array with typescript

I am having the car object in this screenshot(I couldn't find a way to pretty print it here)
I would like to do a function that clones one of the two elements in the factory.
I tried it like this:
public cloneFactory(modelIndex: number, factoryIndex: number): void {
const newFactory = this.car.model[modelIndex].factory.slice(factoryIndex, factoryIndex + 1);
this.car.model[modelIndex].factory.push(newFactory[0]);
}
I also tried it the classic way:
public cloneFactory(modelIndex: number, factoryIndex: number): void {
const newFactory = this.car.model[modelIndex].factory[factoryIndex];
this.car.model[modelIndex].factory.push(newFactory);
}
The issue I am having is that if I, afterwards, change one of the values in the cloned object it also changes it in the original object. I cannot understand why and how / why are the original and the clone related after one of the methods above are executed.
What is the proper way of cloning an element of the array so that it can be, later, edited without the original object to be affected as well?
You are not actually cloning the object. You are pushing the reference to the same object again. To clone it you can use Object.assign:
const newFactory = Object.assign({}, this.car.model[modelIndex].factory[factoryIndex]);
Here's an example of how Object.assign works compared to just assigning a reference:
var obj = { a: 1 };
var objref2 = obj; // Just assigning reference; not a clone
var clone = Object.assign({}, obj); // Actual cloned copy of `obj`
obj.a = 100;
console.log(obj.a)
-> 100 // Value changed
console.log(objref2.a)
-> 100 // Value changed
console.log(clone.a)
-> 1 // Value unchanged

Angular - Objects seem bound to eachother but arent

I have an edit page where the user can edit a file in the system, and then save it. When loading the file, I make two objects out of the result, one is bound to the view and the other I wish to keep (in its original state) until "save" is clicked, and then use it to compare vs the view-bound object, to see if any changes have been made.
So, when the page loads, this is being run
$http.get('/api/files/' + $stateParams.id)
.then(function (result) {
vm.fileTemp = result.data;
vm.fileTempCopy = result.data;
The fileTempCopy is not being touched or referenced by anything in the view or elsewhere in the controller, except in the save-method, where i check if they are alike or not. But somehow, both of them are updated when i make changes to the input fields (as if they were both used as ng-model for the inputs).
if(vm.fileTemp === vm.fileTempCopy)//in save-function
is always true, and their fields are exactly the same.
Why does this happen and how can I solve it?
Using the assignment operator, you are actually just referencing the original array. Arrays are reference types. That means, that they don't actually store values, they only store references to those values. What you where doing is copying a reference to a memory location, meaning that any changes to the memory at that location (including removing elements) will be reflected in both arrays.
So you will want to do this instead:
vm.fileTemp = angular.copy(result.data);
vm.fileTempCopy = angular.copy(result.data);
here is a very basic approach to checking an object's "value equality".
function isEquivalent(a, b) {
// Create arrays of property names
var aProps = Object.getOwnPropertyNames(a);
var bProps = Object.getOwnPropertyNames(b);
// If number of properties is different,
// objects are not equivalent
if (aProps.length != bProps.length) {
return false;
}
for (var i = 0; i < aProps.length; i++) {
var propName = aProps[i];
// If values of same property are not equal,
// objects are not equivalent
if (a[propName] !== b[propName]) {
return false;
}
}
// If we made it this far, objects
// are considered equivalent
return true;
}
//After your update Outputs: false
console.log(isEquivalent(vm.fileTemp, vm.fileTempCopy));

substring from an array as3 **Error #1009: Cannot access a property or method of a null object reference

I am trying to create a matching game where one object in the array hitBoxes is matched to one object in the array hitBoxes2. I have tried to convert the instance name into a string and then used the substring method to match the LAST number in the instance name, if its a match they win. Right now I'm getting the error
TypeError: Error #1009: Cannot access a property or method of a null
object reference. at MethodInfo-499()
I'm wondering if anyone can help me. Thanks!
var left:String;
var correct:MovieClip = new Correct;
var isClicked:Boolean = false;
var leftClicked:int = 0;
p3.nextPage.buttonMode = true;
p3.nextPage.addEventListener(MouseEvent.CLICK, nextPage);
function nextPage(MouseEvent):void{
removeChild(p3);
}
var hitBoxes:Array = [p3.a1, p3.a2, p3.a3, p3.a4, p3.a5, p3.a6, p3.a7, p3.a8];
var hitBoxes2:Array = [p3.b1, p3.b2, p3.b3, p3.b4, p3.b5, p3.b6, p3.b7, p3.b8];
for (var h:int = 0; h < hitBoxes.length; h++){
hitBoxes[h].buttonMode = true;
hitBoxes[h].addEventListener(MouseEvent.CLICK, matchingLeft);
}
for (var h2:int = 0; h2 < hitBoxes2.length; h2++){
hitBoxes2[h2].buttonMode = true;
hitBoxes2[h2].addEventListener(MouseEvent.CLICK, matchingRight);
}
function matchingLeft(e:MouseEvent):void{
var left = String(e.currentTarget.name);
isClicked = true;
trace(left);
}
function matchingRight(e:MouseEvent):void{
var right:String = String(e.currentTarget.name);
trace(right);
if(isClicked == true && left.substring(3,3) == right.substring(3,3)){
trace("matched");
}
}
According to your code variable "left" is null at matchingRight method, because matchingLeft uses its local variable with name "left", and top-level "left" still has its default value.
also String.substring method is used incorrectly:
var name:String="p3.a1";
trace(name.substring(3, 3)); // this will always output empty string ""
trace(name.substring(4, 5)); // this will output "1" string
in conclusion I'd advise to use array indices (integers) instead of strings when calculating "matched" condition, substring operation and string comparison are CPU intensive.

flash as3 how to prevent an item from being added to an array if it already exists in the array

I know how to remove duplicates from an array, but what I'm trying to do is prevent an item from ever being added to an array in the first place if it already exists. I'm pulling in data from an xml feed in a loop, and I thought that searching for that values index would work, but no matter what, the index is always -1. Here's my code:
var yearArr:Array = new Array();
for (var i=0;i<numCovers;i++){
var coverRef = xmlObj.cover[i];
var coverClip:MovieClip = new MovieClip();
coverClip.year = coverRef.#year;
if (yearArr.indexOf(coverClip.year === -1)){
yearArr.push (coverClip.year);
}
}
Maybe I'm misunderstanding the indexOf function, but I thought it was supposed to return -1 if a value did not exist in an array. What am I doing wrong?
Here's the solution I came up with:
var yearArr:Array = new Array();
for (var i=0;i<numCovers;i++){
var coverRef = xmlObj.cover[i];
var coverClip:MovieClip = new MovieClip();
coverYear = coverRef.#year;
addCoverYear(coverYear);
}
function addCoverYear(coverYear:int):void {
if (yearArr.indexOf(coverYear) == -1){
yearArr.push(coverYear);
}
}
you can reduce an array by passing everything to a dictionary, which will automatically remove redundancies. then pass the dictionary back as a new array.
//Reduce Array
private function reduceArray(array:Array):Array
{
var dictionary:Dictionary = new Dictionary();
for each (var element:String in array)
dictionary[element] = true;
var result:Array = new Array();
for (var key:String in dictionary)
result.push(key);
dictionary = null;
return result;
}
Your code is almost fine. The problem is that an E4X property .#year is not a literal string (I'm not sure right now, but I believe it's an XMLList object). That's why the indexOf call will keep returning -1, because it is looking for a duplicate of that object, not a string. E4X will convert it to a string as soon as you put it somewhere where only strings can go, but until that time it is something else.
If you rewrite your code like this, it should work right away:
var yearArr:Array = new Array();
for each (var coverRef : XML in xmlObj.cover){
var year : String = coverRef.#year; // force the property to be a string
if (yearArr.indexOf(year) < 0){
yearArr.push (year);
}
}
There were also a few other optimizations you could do to your code. The new MovieClip() part wasn't used, not all variables were strongly typed and by using a for each loop, you can state much clearer what objects you're looping through.
Here is what you could do, if for example, you have an array of strings.
var ItemList:Array = new Array();
for each(var Item:String in UseYourXMLFeed)
{
if(ItemList.indexOf(Item) == -1)
{
ItemList.push(Item);
}
}
Edit:
Anyways, your real answer is in the comment by Sam.

Sorting a Flex Array

I have created an array as shown below
protected function getMyArray(dataArray:Array):Array
{
var labelList:Array=new Array;
for each (var property:Object in dataArray)
{
if (labelList[property.bucketTime] != property.bucketTime)
labelList[property.bucketTime]=property.bucketTime;
}
return labelList;
}
Is it possible to sort the array labelList based on property.bucketTime?
Edit: Sample input dataArray will be like this :
var tempObj:Object = new Object;
tempObj.bucketTime = DateField.stringToDate("30-01-2010", "DD-MM-YYYY").time;
tempObj.score = 76;
dataArray.addItem(tempObj);
tempObj = new Object;
tempObj.bucketTime = DateField.stringToDate("13-02-2010", "DD-MM-YYYY").time;
tempObj.score = 21;
dataArray.addItem(tempObj);
tempObj = new Object;
tempObj.bucketTime = DateField.stringToDate("30-03-2010", "DD-MM-YYYY").time;
tempObj.score = 10;
tempArry.addItem(tempObj);
Unless bucketTime is a number; then you aren't actually populating the array. You're just adding properties to the Array Object, almost like it were a Dictionary. I've seen a Dictionary called Associative Array's and Structures in other languages.
If that is the case, an you're using the Array class as a dictionary, then there is no way to sort it. The very nature of such a structure is that they are not sortable.
However, if property.bucketTime is a number, and you are trying adding items to the array as if they were an array, you can sort using the Array.sort or Array.sortOn methods.
Atlast I sorted the labelList Array.Please find my solution below. Let me know if there is any better way to achieve this.
var termObject:Object = ObjectUtil.getClassInfo(labelList);
var termsArray:Array = termObject.properties;
var sortedColumnArray:Array = new Array;
for each(var term:Object in termsArray){
if(labelList.hasOwnProperty(term)){
sortedColumnArray.push(labelList[term]);
}
}

Resources