1

I have a React form that uses i18 next translations from JSON file in a dropdown. The objects are very simple: one key, one translation, like this (but the file is very long, there are dozens of keys).

JSON:

{
"country": "Country",
"big": "Big",
"dog": "Dog",
"integration": "Integration"
}

Code that uses data from JSON:

  const createField = (parentName: string, item: any) => {
  const field = {
  type: `${item.type}`, 
  name: `${parentName ?? ''}${parentName?.length ? '.' : ''}${item.name}`,
  label: t(`${item.label ?? item.name}`), 
  properties: {
  placeholder: `${item.placeholder ?? ''}`
  } as any,
  };
        
  if (item.type === 'select' ) {
     field.properties = {
       ...field.properties,
       options: [].concat(item.options?).sort((a,b) => 
        t(`${a.value}`) > t(`${b.value}`) ? 1 : -1).map((option: any) => {
           return {
              label: t(`${option.label}`),
              value: option.value
                  };
                }),
            };
        };
 };

I want the dropdown to be sorted according to the value alphabetically because in each language the order would be different. Everything I tried sorts the array from this JSON according to the key.

I tried concat(item.options?) for sorting but getting errors "Expression expected" and "property doesn't exist". Also tried this solution, but the dropdowns turned from text into random numbers.

if (item.type === 'select' ) {
   field.properties = {
    ...field.properties,
  options: Object.entries(item.options)
  .sort(([key1], [key2]) => t(key1).localeCompare(t(key2)))
  .map(([label, value]) => ({
    label: t(label),
    value
  }))
  };
 };
4
  • 1
    if you want just values need to sort, then you can use Object.values(obj).sort() Commented Jul 22, 2021 at 6:18
  • And how to add sorting parameters? Is it sorting alphabetically ascending by default? Commented Jul 22, 2021 at 6:23
  • Official documentation is an amazing resource most of the time. Other than this, what have you tried already on your own? See stackoverflow.com/help/minimal-reproducible-example Commented Jul 22, 2021 at 7:07
  • Sorry, my bad. Updated with the piece of code and what I tried. Commented Jul 22, 2021 at 12:41

2 Answers 2

1

Issue

Assuming that item.options is the JSON data you are trying to sort and convert to a list of options, then the issue is that you've appended the entire options object instead of each individual option. The result is an array of length 1. Another issue is that your data is a dictionary of key-value pairs, not an array of objects with label and value properties.

Solution

You can use both Object.entries and Object.fromEntries to convert the object to an array of key-value pairs and back. For the sorting function you want to sort by the key, and since the keys are strings, use localeCompare for the string comparison.

const data = {
  country: "Country",
  big: "Big",
  dog: "Dog",
  integration: "Integration"
};

const sortedData = Object.fromEntries(
  Object.entries(data).sort(([key1], [key2]) => key1.localeCompare(key2))
);

console.log(sortedData);

Since you really want an array of shape [{ label: '...', value: '...' }, ...] you can use an array.map to map the array of key-value pairs to an array of objects with the shape you need for mapping in the option values.

const data = {
  country: "Country",
  big: "Big",
  dog: "Dog",
  integration: "Integration"
};

const sortedData = Object.entries(data)
  .sort(([key1], [key2]) => key1.localeCompare(key2))
  .map(([label, value]) => ({
    label,
    value
  }));

console.log(sortedData);

For the actual rendering of your options:

options: Object.entries(item.options)
  .sort(([key1], [key2]) => t(key1).localeCompare(t(key2)))
  .map(([label, value]) => ({
    label: t(label),
    value
  }))

Since it's not very clear which of the key or value of the JSON data is your option label/value you may needs to tweak the above to fit. I can help here if needed.

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

8 Comments

You got it right: I am trying to sort the value of item.options and the value for the options I'm getting from the dictionary file, which has key-value pairs. Now the values in dropdown are shown like "Integration/Big/Dog/Country", and my goal is to sort them alphabetically in the UI, I don't care about the order of the JSON itself. And as translations in different languages are different, I want "Big/Country/Dog/Integration" in English and e.g. "Gross/Hund/Integration/Land" in German. That's why I tried to include sorting in the mapping.
@Stacey I see, so I think I did get it mostly correct then. Like I said though, if you sort by the value, or translate the value, I can help if converting proves difficult. Is your question/issue resolved then?
I'm still stuck. I understood the principle but not the implementation i.e. cannot fit it in my code.
@Stacey Oh dang, I thought it would pretty "drag-n-drop" replacement. What isn't fitting?
I added it as below and all my dropdowns are showing some numbers now. if (item.type === 'select' ) { const sortedData = Object.entries(data).sort(([key1], [key2]) => key1.localeCompare(key2)).map(([label, value]) => ({label, value})); field.properties = { ...field.properties, options: Object.entries(item.options).sort(([key1], [key2]) => t(key1).localeCompare(t(key2))) .map(([label, value]) => ({ label: t(label), value })) }; };
|
0

Hope it helps:

sort object by key and result is an array of sorted keys

const obj={
            "country": "Country",
            "big": "Big",
            "dog": "Dog",
            "integration": "Integration"
            }
            
            const sortedKeys=Object.keys(obj).sort();
            console.log(sortedKeys);

sort object by value and result is an array of sorted values

 const obj={
            "country": "Country",
            "big": "Big",
            "dog": "Dog",
            "integration": "Integration"
            }
            
            const sortedValues=Object.values(obj).sort();
                console.log(sortedValues)

sort object by value and result is an object

const obj={
            "country": "Country",
            "big": "Big",
            "dog": "aDog",
            "integration": "Integration"
            }
           
        //for case insensitive use this function
        const sortedByValue=Object.values(obj).sort(function(a, b) {
            return (a.toUpperCase() < b.toUpperCase()) ? -1 : (a.toUpperCase() > b.toUpperCase()) ? 1 : 0;
        })
        
        function getKeyByValue(value) {
          return Object.keys(obj).find(key => obj[key] === value);
        }
        
        const sortedObj={};
        sortedByValue.map(value=>{
        const key=getKeyByValue(value)
        sortedObj[key]=value;
        })
        console.log(sortedObj)

Comments

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.