Skip to content Skip to sidebar Skip to footer

How To Update Particular Object In Array Of Multiple Objects Dynamically

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, D

Solution 1:

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 updateconst 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

Solution 2:

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 followingconst 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.

Solution 3:

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";

classAppextendsReact.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 :)

Post a Comment for "How To Update Particular Object In Array Of Multiple Objects Dynamically"