Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
126 views
in Technique[技术] by (71.8m points)

javascript - How to create dynamic elements inside global tabs

I am working with react hooks, And encounter a problem where I have been stuck now.

I have one json data which I am getting whenever user logs in so by that I am creating one top bar which shows user names and when user click on those names I am showing some data which they have created or present for them in db, That data I am already getting in data

MY data I am getting from server

 let data=   [
  {
    "id": 1,
    "name": "Maxi",
    "myData": [
      {
        "data_name": "div1",
        "data_title": "div1 tittle"
      },
      {
        "data_name": "div1",
        "data_title": "div tittle"
      }
    ]
  },
  {
    "id": 2,
    "name": "Phill",
    "myData": [
      {
        "data_name": "div21",
        "data_title": "div21 tittle"
      }
    ]
  }
]

I have one button on side on which I want to create new div, inside the name I have selected from top.

SO suppose I have listed the topbar and there are total of 3 data i.e 3 names, so if data length is smaller than 4 what I am doing, showing a plus button to create one more tab, so user can create one more tab and then they can create one div inside there each tab,

What I have done

I am populating the top bar as well as when I click on side button I am creating one div inside that selected tab.

Issues I am facing

  • if length of data is less then four I am providing a plus button to create on more tab (give it default name), but I am not getting any idea how can I create the new one.
  • when I click on side button to create one dive inside tab, and I go to other tab and come back again I want that created div should not gets deleted.
  • Suppose I have 3 tabs (data) so when page loads the first tab data I want to show, but it is not showing up I need to click there only it is showing up.
  • if the data is null then I can create up to 4 tabs this also I a=want some Idea to do it.

I am linking my code sand box here so it will be easy to understand what I have done and what I am trying to do

Code sandbox

Here in code sand box I have written all my code please check it out.

I have explained every thing what I a m trying to do, I know how to code but not getting any idea or approach.

if there is no data for user then I will start creating tabs and nested elements from 1 for that user.

in each there will be a save button for each new element created, so I will do that, my only consern is to not to loss data on ui when I go one tab to other once I created them

export default function App() {
  const [active_menu, setactive_menu] = useState(0);
  const [nestedData, setnestedData] = useState(null);

  let data1 = [
    {
      id: 1,
      name: "Maxi",
      myData: [
        {
          data_name: "div1",
          data_title: "div1 tittle"
        },
        {
          data_name: "div1",
          data_title: "div tittle"
        }
      ]
    },
    {
      id: 2,
      name: "Phill",
      myData: [
        {
          data_name: "div21",
          data_title: "div21 tittle"
        }
      ]
    }
  ];
  const Tab_click = (index, li) => {
    setactive_menu(index);
    setnestedData(li);
  };

  const Create_element = () => {
    //here I don't know how to create new elements
  };
  const addnewTab=()=>{
    
  }
  return (
    <div className="App row">
      {data1.map((li, index) => (
        <div className="col-4 col-sm-4 col-md-3 col-lg-3 col-xl-3" key={index}>
          <div
            className={
              index === active_menu
                ? "row dashboard_single_cont_active"
                : "row dashboard_single_cont"
            }
            onClick={() => Tab_click(index, li)}
          >
            <div className="dashboard_name col-10 col-sm-10 col-md-9 col-lg-10 col-xl-10">
              {li.name}
            </div>
            <div
              className={
                active_menu === index
                  ? "dashboard_option_active col-2 col-sm-2 col-md-3 col-lg-2 col-xl-2"
                  : "dashboard_option col-2 col-sm-2 col-md-3 col-lg-2 col-xl-2"
              }
              align="center"
            ></div>
          </div>
        </div>
      ))}
      {data1.length < 4 && (
       <span
       onClick={addnewTab}
       >ADD</span>
      )}
      <div className="col-11 col-sm-11 col-md-11 col-lg-11 col-xl-11">
        <div className="row">
          {nestedData !== null &&
            nestedData.myData.map((li, index) => (
              <div className="col-11 col-sm-11 col-md-8 col-lg-6 col-xl-6">
                <NEsted data={li} />
                <br></br>
              </div>
            ))}
        </div>
      </div>
      <RightBar Create_element={Create_element} />
    </div>
  );
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Issues You are Facing

  1. If length of data is less than four I am providing a plus button to create on more tab (give it default name), but I am not getting any idea how can I create the new one.

Here you want to get a new name, i.e. a form on the page with a text input, random generate name, use a prompt as I did below. Call setData and use a functional state update to spread existing data into a new array and append a new data object.

const addNewTab = () => {
  /**
   * window.prompt is just a quick way to request input from user. 
   */
  const name = window.prompt('Enter Name');

  /**
   * logic to generate next id, but could be anything really
   */
  const id = generateId();

  if (name) {
    setData((data) => [...data, new Data(id, name)]);
  }
};
  1. When I click on side button to create one dive inside tab, and I go to other tab and come back again I want that created div should not gets deleted.

A couple things going on here. First, you defined data1 in the function body so it is reset every render cycle. Keep the data in state, data can be provided as initial state. Second, you need to add the created elements. Do this by updating state.

Move data1 out of the component and define local component state initialized with data (update all references in render from data to data).

const [data, setData] = useState(data1);

Similar approach as adding a new tab, get the new data name and title. Here we call setData and again use a functional state update, but this time we'll map the existing state to a new array. When the array index matches the active tab index this is the data object we need to updated. Spread its myData into a new array and append the new data object. If index isn't a match then just return the element.

const Create_element = () => {
  /**
   * window.prompt is just a quick way to request input from user. 
   */
  const data_name = window.prompt('Enter Data Name');
  const data_title = window.prompt('Enter Data Title');

  if (data_name && data_title) {
    setData(data => data.map((el, i) => i === active_menu ? {
      ...el,
      myData: [...el.myData, { data_name, data_title }],
    } : el))
  }
};
  1. Suppose I have 3 tabs (data) so when page loads the first tab data I want to show, but it is not showing up I need to click there only it is showing up.

Issue here is caused by keeping a separate nestedData state object that is only ever updated when a tab is clicked. When a new element is added to the active tab's myData array nestedData isn't updated. Solution here is to simply render the nested data directly in the UI.

Update the tab's onClick handler to simply set the active menu (index).

onClick={() => setactive_menu(index)}

Render the myData directly from the new data state.

data[active_menu].myData.map((li, index) => (...
  1. If the data is null then I can create up to 4 tabs this also I a=want some Idea to do it.

Conditionally rendering the ADD button will control this.

{data.length < 4 && <button onClick={addNewTab}>ADD</button>}

Edit how-to-create-dynamic-elements-inside-global-tabs

Full Code

import React, { useState } from "react";
import "./styles.css";

import RightBar from "./Right_option";
import NEsted from "./Nested";

import "bootstrap/dist/css/bootstrap.min.css";

/**
 * https://stackoverflow.com/questions/63814645/how-to-create-dynamic-elements-inside-global-tabs
 */

const data1 = [
  {
    id: 1,
    name: "Maxi",
    myData: [
      {
        data_name: "div1",
        data_title: "div1 tittle"
      },
      {
        data_name: "div1",
        data_title: "div tittle"
      }
    ]
  },
  {
    id: 2,
    name: "Phill",
    myData: [
      {
        data_name: "div21",
        data_title: "div21 tittle"
      }
    ]
  }
];

/**
 * Data object constructor
 * @param {number} id new data object id
 * @param {string} name new data object name
 * @example
 * new Data(1, 'Bill')
 */
const Data = (id, name) => ({ id, name, myData: [] });

/**
 * Id generator hook
 * @param {number} [seed=0] initial id generator value
 * @returns {function}
 */
const useIdGenerator = (seed = 0) => {
  function* genId(seed = 0) {
    let i = seed;
    while (true) yield i++;
  }

  const generator = genId(seed);

  return () => generator.next().value;
};

export default function App() {
  const generateId = useIdGenerator(5);

  const [data, setData] = useState(data1);
  const [active_menu, setactive_menu] = useState(0);

  const Create_element = () => {
    /**
     * window.prompt is just a quick way to request input from user.
     */
    const data_name = window.prompt("Enter Data Name");
    const data_title = window.prompt("Enter Data Title");

    if (data_name && data_title) {
      setData((data) =>
        data.map((el, i) =>
          i === active_menu
            ? {
                ...el,
                myData: [...el.myData, { data_name, data_title }]
              }
            : el
        )
      );
    }
  };

  const addNewTab = () => {
    /**
     * window.prompt is just a quick way to request input from user.
     */
    const name = window.prompt("Enter Name");

    if (name) {
      setData((data) => [...data, new Data(generateId(), name)]);
    }
  };

  return (
    <div className="App row">
      {data.map((li, index) => (
        <div className="col-4 col-sm-4 col-md-3 col-lg-3 col-xl-3" key={index}>
          <div
            className={
              index === active_menu
                ? "row dashboard_single_cont_active"
                : "row dashboard_single_cont"
            }
            onClick={() => setactive_menu(index)}
          >
            <div className="dashboard_name col-10 col-sm-10 col-md-9 col-lg-10 col-xl-10">
              {li.name}
            </div>
            <div
              className={
                active_menu === index
                  ? "dashboard_option_active col-2 col-sm-2 col-md-3 col-lg-2 col-xl-2"
                  : "dashboard_option col-2 col-sm-2 col-md-3 col-lg-2 col-xl-2"
              }
              align="center"
            ></div>
          </div>
        </div>
      ))}

      {data.length < 4 && <button onClick={addNewTab}>ADD</button>}

      <div className="col-11 col-sm-11 col-md-11 col-lg-11 col-xl-11">
        <div className="row">
          {data[active_menu].myData.map((li, index) => (
            <div
              key={index}
              className="col-11 col-sm-11 col-md-8 col-lg-6 col-xl-6"
            >
              <NEsted data={li} />
              <br></br>
            </div>
          ))}
        </div>
      </div>
      <RightBar Create_element={Create_element} />
    </div>
  );
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...