0

I have a bit of complex data to work with. I am building an application with Nodejs and Nextjs. I am pulling data from my database that has this type of structure:

const response = {
     item1: 'someItem',
     item2: 'someitem2',
    packages: [
     {
      packagaA: 'packageA',
      quantity: 3
     },

      {
      packagaA: 'packageB',
      quantity: 1
     },

      {
      packagaA: 'packageC',
      quantity: 2
     },
     
     questions: [
       {
         question1: 'question1',
         
      },

      {
         question2: 'question2',
         
      },

      {
         question3: 'question3',
         
      }
     ]

    ]
  }

This is just a sample of the response structure. I would like to render this in frontend this way: For packages which is an array, I want to render it based on the number of package quantity. So, if packageA has 3 quantities, using map method, packageA would be rendered 3 times, packageB would be rendered 1 and packageC would be rendered 2 times. This I have achieved. The challenge is rendering question and updating accordingly. If you take a look at question field, it is an array. So, I would like question to be rendered per package item and should be rendered based on the quantity of the package. For instance, packageA appeared 3 times, this means that the question would be rendered 3 times too. These questions would take answers from users from input tag. How can I make these input tag responses unique? How do I handle such complex data structure?

To render the packages, I created a custom array that replicates the package object based on their quantity and formed a new array like this:

useEffect(()=>{
let tempObjArray:{itemName: string}[] = [];

const filterArray = response?.packages?.filter((item, index) => item?.itemType === 'package_order');

filterArray?.map((item, index)=>{
    for(let i = 0; i < Number(item?.orderedQuantity); i++){
        tempObjArray.push({itemName: item?.orderedItemName});
    }
    
  });

  setTemporaryPackageData(tempObjArray)
 }, []);



return(
    <div>
       {
        temporaryPackageData?.map((item, index)=>(
           <p>{item?.itemName}</p>
        ))
      }
    </div>
  )

This renders the packages based on their quantity. So, if the first package has 3 quantities, it would render 3 times. The challenge now is how to make each of them rendered to have their own questions and for users to uniquely respond to these questions. I have been able to get this done but I am not able to get users respond to each of these questions uniquely.

  • each package and question has a different field name? why is it not the same/constant? like `{ package: string, quantity: number }` and `{ question: string }`. – arthur simas Jul 23 '23 at 09:33
  • answers should be unique for each package or among all of them? in case `packageA` has 3 quantities, should each question appear 3 times (one for each item)? – arthur simas Jul 23 '23 at 09:36
  • Actually it is same name. I have corrected that. Yes, the answers would be different based on what the user wrote. A user needs to respond to first item in the package. Let me give you example, let say, I paid for the first package and I want 3 quantity. Now, I need to provide the names of the user who are going to use the first package. Since I chose 3 quantities, it means I need to provide the 3 user details one for each belonging to first package. And if in second package, I decided to pay for 2 quantities, I will provide 2 user details, etc – princekings Jul 23 '23 at 09:37
  • Yes, if for instance, PackageA has 3 quantities, the block array of questions will appear 3 times. I solved this by multiplying the question length by each package quantity. This gave me the accurate number of questions to be rendered dynamically. However, on updating the question fields, I couldnt get them to be updated specifically. For instance, when responding to question under packageA, it also appears in question under packageB. If I can fix this, I have solved my problem – princekings Jul 23 '23 at 09:42
  • the questions field is for the question text or the _answer_ of the question? where and how are you storing the state for answers? – arthur simas Jul 23 '23 at 09:44
  • The question field returns the question texts sent from the server, based on that question text, I need to render input tag for user to respond to each of the questions. – princekings Jul 23 '23 at 09:56
  • have a look at my updated answer, please – arthur simas Jul 23 '23 at 10:01

1 Answers1

0

May I suggest a change in your code?

I would do it like that:

interface Package {
  package: string
  items: { question: string, answer: string }[]
}

In this case, as you have a question for each item, you can just have the quantity for each package just doing package.items.length. If you need more than one question per item, you can create a question array: { question: string, answer: string }[][].

And then, to render and maintain answer state for each item becomes easy. You can handoff this to Formik FieldArray:

const QUESTION = { question: 'question text?', answer: '' }

<Form>
  <FieldArray
    name={`packages.${package_index}.items`}
    render={arrayHelpers => (
      <div>
        {values.items.map((item, index) => (
          <div key={index}>
            <span>{packages[package_index].items[index].question}</span>
            <Field name={`packages.${package_index}.items.${index}.answer`} />

            <button type="button" onClick={() => arrayHelpers.remove(index)}>
              -
            </button>
          </div>
        ))}
        <button
          type="button"
          onClick={() => arrayHelpers.push({ ...QUESTION })}
        >
          +
        </button>
      </div>
    )}
  />
</Form>

To handle unique field values, you can have a look at this thread.

Hope it helps!

arthur simas
  • 132
  • 5
  • My major challenge is rendering the questions and allowing users to respond to these questions uniquely. – princekings Jul 23 '23 at 09:47
  • Thanks for this. Even though I created a different system that renders the questions for each packages based on their quantity, the major challenge is for users to respond to these questions uniquely. U know I would be rendering an input tag for each question under each package based on their quantities, I also need to have these questions in useState to control their input. – princekings Jul 23 '23 at 10:20
  • Do you mind helping me further maybe via skype or zoom? It is really a complex data system, even the questions aren't of same type. Some are texts, some are file upload, some are dates, some are checkbox, some are multiple choices, etc. It is really complex and I don't even know how to put out all here. I would appreciate a further help. I am almost getting it right. Just little more tweak could work – princekings Jul 23 '23 at 10:23
  • i've designed such system before for a quiz. we had different types of questions. you need to signal the question type. i mean: `type QuestionType = 'text' | 'date' | 'file-upload' | 'checkbox' | 'multiple-choice'` then use that to render the question accordingly. as you're dealing with file uploads, i would direct you to some binary coding to transfer everything at once (instead of uploading the file separately), e.g. [messagepack](https://msgpack.org/). i don't provide further help to job-related questions. if you want to, pay me a consulting hour and i'll be glad to further help you – arthur simas Jul 23 '23 at 23:35
  • Thank you for your reply. I was able to solve my problem yesterday. yea, I already designed the questions based on types in the server and already rendered it accordingly. My challenge as at when I came here was capturing them uniquely on useState to update them but I have done that. I used a forloop to recreate the data appropriately as i wanted in frontend and everything is working as I wanted. – princekings Jul 24 '23 at 16:14