0

How to update a particular object in array of objects. For example, have an object like this

tabs: [{
    name: "Step 1",
    DroppedDetails: [
      {id:1,name:Step1,
       DroppedDetails:[
       {DraggedItemRandomId: "70d19a9f-7e6e-4eb2-b974-03e3a8f03f08"
         draggedItem:
         category: "basic"
         disabled: false
         fieldClass: "Text"
         height: 30
         id: "text"
         image: "/static/media/type.327c33c2.png"
         label: "Text Field"
         placeholder: "Edit This Field"
         readOnly: false
         required: false
         width: 200
      }
      {DraggedItemRandomId: "70d19a9f-7e6e-4eb2-b974-039e3a8f03f0"
       draggedItem:
       category: "basic"
       disabled: false
       fieldClass: "Text"
       height: 30
       id: "text"
       image: "/static/media/type.327c33c2.png"
       label: "Text Field"
       placeholder: "Edit This Field"
       readOnly: false
       required: false
       width: 200
      }
    ]
  },
  {
    name: "Step 2",
    DroppedDetails: [
       {DraggedItemRandomId: "70d19a39-7e6e-4eb2-b974-03e3a82f03f0"
       draggedItem:
       category: "basic"
       disabled: false
       fieldClass: "Text"
       height: 30
       id: "text"
       image: "/static/media/type.327c33c2.png"
       label: "Text Field"
       placeholder: "Edit This Field"
       readOnly: false
       required: false
       width: 200
      }]
  }
],

and my new value should update is

{
  DraggedItemRandomId: "70d19a9f-739e-4eb2-b974-03e3a8f032d1",
  draggedItem:{
  category: "basic"
  disabled: false
  fieldClass: "Text"
  height: 30
  id: "text"
  image: "/static/media/type.327c33c2.png"
  label: "Text Field"
  placeholder: "Hey  Sagar"                      // updated value
  readOnly: true                                 //updated value
  required: true                                //updated value
  width: 200}
  }
}

How can i Update this object in state (0th or 1st object dynamically) object like

how can i do setState for inner loop of array of objects dynamically???

i have tried so many examples but no result ..please help me guyz

final output:

 tabs: [{
        name: "Step 1",
        DroppedDetails: [
          {id:1,name:Step1,
           DroppedDetails:[
           {DraggedItemRandomId: "70d19a9f-7e6e-4eb2-b974-03e3a8f03f08"
             draggedItem:
             category: "basic"
             disabled: false
             fieldClass: "Text"
             height: 30
             id: "text"
             image: "/static/media/type.327c33c2.png"
             label: "Text Field"
              placeholder: "Hey  Sagar"                      // updated value
              readOnly: true                                 //updated value
              required: true                                //updated value
             width: 200
          }
          {DraggedItemRandomId: "70d19a9f-7e6e-4eb2-b974-03e3a8f03f08"
           draggedItem:
           category: "basic"
           disabled: false
           fieldClass: "Text"
           height: 30
           id: "text"
           image: "/static/media/type.327c33c2.png"
           label: "Text Field"
           placeholder: "Edit This Field"
           readOnly: false
           required: false
           width: 200
          }
        ]
      },
      {
        name: "Step 2",
        DroppedDetails: [
           {DraggedItemRandomId: "70d19a9f-7e6e-4eb2-b974-03e3a8f03f08"
           draggedItem:
           category: "basic"
           disabled: false
           fieldClass: "Text"
           height: 30
           id: "text"
           image: "/static/media/type.327c33c2.png"
           label: "Text Field"
           placeholder: "Edit This Field"
           readOnly: false
           required: false
           width: 200
          }]
      }
    ],


0

3 Answers 3

0

You can get, first of all, the tabs of the state:

const { tabs } = this.state;

// here you code to decide what tab do you want to update
const tabSelected = tabs[0];
const { DroppedDetails } = tabSelected;
DroppedDetails[0]= {
  name: "sagar111"
};
// You can edit another one or add a new one to the array also.
DroppedDetails[1]= {
      name: "NameEdited"
    };
DroppedDetails.push({ name: "New Name" })

And set state a new state:

this.setState(
{ tabs: tabs.map(t => t === tabSelected ? { ...tabSelected, DroppedDetails }) : t });

But it could be in this way too:

this.setState(tabs);

Because the original references were updated. At the end DroppedDetails and tabs[0].DroppedDetails[0] are the same object.

how can i do setState for inner loop of array of objects???

It's not recommended the use of setState in a forloop. Check this Calling setState in a loop only updates state 1 time

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

2 Comments

I would not recommand doing it that way, as you mutate the array tabs[0].DroppedDetails, while keeping the same ref, which means a pure component which is passed DroppedDeatils as a parameter would not rerender as the props shallow compare would say that it did not change.
please check my updated question i dont know which object i need to change whether 0 or 1st ... i need to change dynamically..please refer my updated question
0

You can easily do that (this changes the name to lower case):

const { tabs } = this.state;

tabs.map(tab => {
  // Do something with your tab value like the following
  const newDroppedDetails = tab.map(({ name }) => ({ name: name.toLowerCase() }); 
  return {
    ...tab,
    DroppedDetails: newDroppedDetails
  }
});

The key point here is to not mutate objects or arrays, but to create a new reference to objects that you modify, so the shallow compare on PureComponents will always work properly.

1 Comment

please check my updated question i dont know which object i need to change whether 0 or 1st ... i need to change dynamically..please refer my updated question
0

Applying the same concepts from your original codesandbox, we can do something like this to edit each individual Dropdown Detail.

working sandbox https://codesandbox.io/s/tab-creator-v2-8hc7c

import React from "react";
import ReactDOM from "react-dom";
import uuid from "uuid";

import "./styles.css";

class App extends React.Component {
  state = {
    tabs: [
      {
        id: 1,
        name: "Tab 1",
        content: "Wow this is tab 1",
        DroppedDetails: [
          { name: "Bhanu", editing: false },
          { name: "Sagar", editing: false }
        ]
      },
      {
        id: 2,
        name: "Tab 2",
        content: "Look at me, it's Tab 2",
        DroppedDetails: [
          { name: "Christopher", editing: false },
          { name: "Ngo", editing: false }
        ]
      }
    ],
    currentTab: {
      id: 1,
      name: "Tab 1",
      content: "Wow this is tab 1",
      DroppedDetails: [
        { name: "Bhanu", editing: false },
        { name: "Sagar", editing: false }
      ]
    },
    editMode: false,
    editTabNameMode: false
  };

  handleDoubleClick = () => {
    this.setState({
      editTabNameMode: true
    });
  };

  handleEditTabName = e => {
    const { currentTab, tabs } = this.state;

    const updatedTabs = tabs.map(tab => {
      if (tab.id === currentTab.id) {
        return {
          ...tab,
          name: e.target.value
        };
      } else {
        return tab;
      }
    });

    this.setState({
      tabs: updatedTabs,
      currentTab: {
        ...currentTab,
        name: e.target.value
      }
    });
  };

  handleOnBlur = () => {
    this.setState({
      editTabNameMode: false
    });
  };

  handleDetailChange = (e, id, index) => {
    const { tabs, currentTab } = this.state;

    const updatedCurrentTab = { ...currentTab };

    updatedCurrentTab.DroppedDetails = updatedCurrentTab.DroppedDetails.map(
      (detail, detailIndex) => {
        if (index == detailIndex) {
          return {
            ...detail,
            name: e.target.value
          };
        } else {
          return detail;
        }
      }
    );

    const updatedTabs = tabs.map(tab => {
      if (tab.id == id) {
        return {
          ...tab,
          DroppedDetails: tab.DroppedDetails.map((detail, detailIndex) => {
            if (detailIndex == index) {
              return {
                ...detail,
                name: e.target.value
              };
            } else {
              return detail;
            }
          })
        };
      } else {
        return tab;
      }
    });

    this.setState({
      tabs: updatedTabs,
      currentTab: updatedCurrentTab
    });
  };

  createTabs = () => {
    const { tabs, currentTab, editTabNameMode } = this.state;

    const allTabs = tabs.map(tab => {
      return (
        <li>
          {editTabNameMode && currentTab.id === tab.id ? (
            <input
              value={tab.name}
              onBlur={this.handleOnBlur}
              onChange={this.handleEditTabName}
            />
          ) : (
            <button
              className={currentTab.id === tab.id ? "tab active" : "tab"}
              onClick={() => this.handleSelectTab(tab)}
              onDoubleClick={() => this.handleDoubleClick(tab)}
            >
              {tab.name}
            </button>
          )}
        </li>
      );
    });

    return <ul className="nav nav-tabs">{allTabs}</ul>;
  };

  handleSelectTab = tab => {
    this.setState({
      currentTab: tab,
      editMode: false,
      editTabNameMode: false
    });
  };

  handleAddTab = () => {
    const { tabs } = this.state;

    const newTabObject = {
      id: uuid(),
      name: `Tab ${tabs.length + 1}`,
      content: `This is Tab ${tabs.length + 1}`,
      DroppedDetails: []
    };

    this.setState({
      tabs: [...tabs, newTabObject],
      currentTab: newTabObject,
      editMode: false,
      editTabNameMode: false
    });
  };

  handleDeleteTab = tabToDelete => {
    const { tabs } = this.state;
    const tabToDeleteIndex = tabs.findIndex(tab => tab.id === tabToDelete.id);

    const updatedTabs = tabs.filter((tab, index) => {
      return index !== tabToDeleteIndex;
    });

    const previousTab =
      tabs[tabToDeleteIndex - 1] || tabs[tabToDeleteIndex + 1] || {};

    this.setState({
      tabs: updatedTabs,
      editMode: false,
      editTabNameMode: false,
      currentTab: previousTab
    });
  };

  setEditMode = () => {
    this.setState({
      editMode: !this.state.editMode
    });
  };

  handleContentChange = e => {
    const { tabs, currentTab } = this.state;

    const updatedTabs = tabs.map(tab => {
      if (tab.name === currentTab.name) {
        return {
          ...tab,
          content: e.target.value
        };
      } else {
        return tab;
      }
    });

    this.setState({
      tabs: updatedTabs,
      currentTab: {
        ...currentTab,
        content: e.target.value
      }
    });
  };

  handleOnDetailBlur = (id, index) => {
    const { tabs, currentTab } = this.state;

    const updatedCurrentTab = { ...currentTab };

    updatedCurrentTab.DroppedDetails = updatedCurrentTab.DroppedDetails.map(
      (detail, detailIndex) => {
        if (index == detailIndex) {
          return {
            ...detail,
            editing: false
          };
        } else {
          return detail;
        }
      }
    );

    const updatedTabs = tabs.map(tab => {
      if (tab.id == id) {
        return {
          ...tab,
          DroppedDetails: tab.DroppedDetails.map((detail, detailIndex) => {
            if (detailIndex == index) {
              return {
                ...detail,
                editing: false
              };
            } else {
              return detail;
            }
          })
        };
      } else {
        return tab;
      }
    });

    this.setState({
      tabs: updatedTabs || [],
      currentTab: updatedCurrentTab
    });
  };

  handleDoubleClickDetail = (id, index) => {
    const { tabs, currentTab } = this.state;

    const updatedCurrentTab = { ...currentTab };

    updatedCurrentTab.DroppedDetails = updatedCurrentTab.DroppedDetails.map(
      (detail, detailIndex) => {
        if (index == detailIndex) {
          return {
            ...detail,
            editing: true
          };
        } else {
          return detail;
        }
      }
    );

    const updatedTabs = tabs.map(tab => {
      if (tab.id == id) {
        return {
          ...tab,
          DroppedDetails: tab.DroppedDetails.map((detail, detailIndex) => {
            if (detailIndex == index) {
              return {
                ...detail,
                editing: true
              };
            } else {
              return detail;
            }
          })
        };
      } else {
        return tab;
      }
    });

    this.setState({
      tabs: updatedTabs || [],
      currentTab: updatedCurrentTab
    });
  };

  createContent = () => {
    const { currentTab } = this.state;

    return (
      <div>
        <div>
          <p>{currentTab.content}</p>
          <div>
            <h4>Dropped Details</h4>
            {currentTab.DroppedDetails ? (
              <div>
                {currentTab.DroppedDetails.map((detail, index) => {
                  if (detail.editing) {
                    return (
                      <div>
                        <input
                          value={detail.name}
                          onChange={e =>
                            this.handleDetailChange(e, currentTab.id, index)
                          }
                          onBlur={() =>
                            this.handleOnDetailBlur(currentTab.id, index)
                          }
                        />
                      </div>
                    );
                  } else {
                    return (
                      <p
                        onDoubleClick={() =>
                          this.handleDoubleClickDetail(currentTab.id, index)
                        }
                      >
                        {detail.name}
                      </p>
                    );
                  }
                })}
              </div>
            ) : (
              ""
            )}
          </div>
        </div>

        {currentTab.id ? (
          <div style={{ display: "flex", justifyContent: "space-between" }}>
            <button className="edit-mode-button" onClick={this.setEditMode}>
              Edit
            </button>
            <button onClick={() => this.handleDeleteTab(currentTab)}>
              Delete
            </button>
          </div>
        ) : (
          ""
        )}
      </div>
    );
  };

  render() {
    const { currentTab, editMode } = this.state;
    return (
      <div className="container">
        <div className="well">
          <button className="add-tab-button" onClick={this.handleAddTab}>
            <i className="text-primary fas fa-plus-square" /> Add Tab
          </button>
          {this.createTabs()}
          <div className="tab-content">
            {editMode ? (
              <div>
                <textarea
                  onChange={this.handleContentChange}
                  value={currentTab.content}
                />
                <button className="save-button" onClick={this.setEditMode}>
                  Done
                </button>
              </div>
            ) : (
              this.createContent()
            )}
          </div>
        </div>
      </div>
    );
  }
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

To activate "edit-mode" double-click a dropped-detail. The input should appear in its place and you can type in the new text. When complete, click out of the input and it will finalize the updated text :)

9 Comments

@ Christopher Ngo bro i have modified above question clearly ..Check my above question and give me suggestions i Need total object should modify..If u have any queries let me know bro ..Thank you
@sagarbhanu how would I user typically interact with the item? Are they changing the test?
@sagarbhanu heres's an updated sandbox: codesandbox.io/s/tab-creator-v2-8c2in. It looks like we can use name as the same thing as placeholder. Other than that, it seems you only want to set readOnly and required to be true when something is being editted. For the item that is being editted, we just toggle those properties to true. See logic in handleOnDetailBlur and handleDetailChange :)
cant we change entire updated object based on index??? how many fields i need to update that many we can write in those methods??
@sagarbhanu that is pretty much what we're doing though if you see in the sandbox. We are updating the object based on its index. We just need to clarify what parts of the object need to be changed. In your example, you only listed the 3 with updated values. See lines 89 to 94
|

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.