0

I am in almost desperate need of help. I am a mechanical engineer and I'm doing a type of calculator for my line of work. I have had an issue I've spent weeks on. I can't seem to solve it.

To not bore you with long code I will try to generalise it as much as possible.

  • I will first present an example code.
  • Then I will explain the expected behaviour and what is actually happening for me.
  • Finally I will explain what I have tried so far to solve this issue.
  • I will add more content at the bottom based on comments to help clarify my question.

CODE EXAMPLE

THE PARENT OBJECT

import {childObject} from "./childObject"

// in my code "childObject" are actually different from each other
const object1 = Object.assign({}, childObject);
const object2 = Object.assign({}, childObject);
const object3 = Object.assign({}, childObject);
const object4 = Object.assign({}, childObject);
const object5 = Object.assign({}, childObject);
const object6 = Object.assign({}, childObject);

const exampleObject = {
 name: "foo",
 otherInfo: "bar",
 nestedObject:{
  standardType: [object1, object2, object3],
  specialType: [object4, object5, object6]
 },
 sumfunc(){}
}

THE CHILD OBJECT

export const childObject = {
 name: "I'm losing my mind",
 value: "" //<-- this will change
 otherInfo: "please help me",
 sumfunc(){}
}

EXPLAINING

What I am doing is the following:

  1. Searchbar with all types of parentObjects.
  2. Allowing user to select one or multiple of same or different parentObjects.
  3. Storing the copied selection in a redux store.
  4. Displaying the selection, each parentObject as a form. [see picture]
  5. When typing in form the value of the nested object will change

example of forms

Now... The issue is when I open the searchbar and select the same parentObject, thus copying it, all its values are mutated. As seen in picture above.

WHAT I HAVE TRIED

  • I have tried to use lodash clone and deepClone on the selected parentObject.
  • I have tried to use loads clone and deepClone on the selected childObjects.
  • I have tried, since the object have the same structure, to go through all key value pairs and shallow copy them.
  • I have tried to not send the parentObject via the searchbar component to the reducer, instead I just send a string and the reducer itself will add the parentObject to the store.

All methods that I've tried have not stopped the mutation. The deepClone method stopped the mutations, but in return the functions in the objects stopped working (maybe I need to bind it somehow?)

MORE CONTENT

The code that updates the value of the nestedObject

const inputsHandler = (e: React.ChangeEvent<HTMLInputElement>) => {
    const formCopy = Object.assign({}, formEQ);
    const inputFieldName = e.target.name;

    // if anything other than a empty, number or decimal inputted, then return
    const isNum = e.target.value.match(/^(?:\d{1,8}(?:\.\d{0,8})?)?$/);
    if (!isNum) return;
    // Update priority list to calculate the last updated input
    formCopy.priorityList = formCopy.priorityList.sort((a, b) => {
      if (a === inputFieldName) return 1;
      if (b === inputFieldName) return -1;
      else return 0;
    });
    // Update selected input field
    formCopy.inputs[calcmode] = formCopy.inputs[calcmode].map((input) => {
      if (input.name === inputFieldName) {
        input.value = e.target.value;
      }
      return input;
    });

    // If more than two inputs empty do not calculate
    const emptyInputs = formCopy.inputs[calcmode].reduce(
      (acc, nV) => (nV.value === "" ? (acc += 1) : acc),
      0
    );

    // Calculate the last edited input field
    formCopy.inputs[calcmode] = formCopy.inputs[calcmode].map((input) => {
      if (input.name === formCopy.priorityList[0] && emptyInputs <= 1) {
        const calculatedValue = formCopy.calculate(
          formCopy.priorityList[0],
          calcmode
        );
        input.value = Number(calculatedValue).toFixed(2);
      }
      return input;
    });

    // Final set hook, now with calculated value
    setformEQ({ ...formCopy });
  };

Please good people of StackOverFlow... Help me!

6
  • 1
    Can you share how you're updating the object ? Commented Jan 3, 2022 at 19:03
  • In nestedObject, i see nestedObject:{ standardType: [object1, object2, object3], specialType: [object1, object4, object5] }. do you realize that object1 is listed in both standardType and specialType ? Also, are you looping over these properties and printing out the indexes? Are you applying a key to each element as you print it out? what does that part of you code look like. And like programoholic asked, how are you updating the object? Commented Jan 3, 2022 at 19:08
  • @programoholic I have added it at the bottom. Commented Jan 3, 2022 at 19:21
  • @JonathonHibbard Thank you for pointing out the mistake! I have not applied any key to the nestedObject, should I do that? I have only applied keys to what react has told me to in the console. Commented Jan 3, 2022 at 19:21
  • Well your code is very complex.. can you produce a codesandbox or stackblitz . I will fix this Commented Jan 3, 2022 at 19:33

1 Answer 1

1

Your code has few problems :

  1. you are filtering based on name property of child object and all of them has the same name. Always provide unique id to the objects so that they can be differentiated in easy manner.

  2. Your filter logic is so wrong :

     formCopy.inputs[calcmode] = formCopy.inputs[calcmode].map((input) => {
          if (input.name === inputFieldName) {
            input.value = e.target.value; // < -- Culprit
          }
          return input;
        });
    
    

Never mutate inline, always create a new copy.

This is how your code change function should be (I have removed dynamic key selection for clarity) :

  const change = (e, id) => {
    const inputFieldName = e.target.name;

    // local copy of array
    const nestedArr = [...qform.nestedObject.standardType];

    // finding item to be updated
    const index = nestedArr.findIndex((i) => i.id === id);

    console.log({ index, inputFieldName, e, id });

    if (index !== -1) {
      const item = nestedArr[index];
      item.value = e.target.value;
      nestedArr[index] = item;

      // deep copy till k depth where k is the key to be updated
      const newObject = {
        ...qform,
        nestedObject: {
          ...qform.nestedObject,
          standardType: [...nestedArr],
        },
      };

      setQform(newObject);
    }}

Check this Example : Demo

Sign up to request clarification or add additional context in comments.

1 Comment

I had some time to change my code today @programoholic. It is not duplicating, I have yet to implement your suggested solution. I will keep my question open, until I have implemented your solution. But I think that you have helped me in solving my issue :)!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.