0

I have a list of items fetched through API which is sorted in alphabetical order, but I want to add header above the list items. For example like below HTML Structure

<h4> A</h4 >
<ul>
    <li>Apple</li>
    <li>Ant</li>
</ul>
<h4>B</h4>
<ul>
    <li>Babel</li>
    <li>Ball</li>
</ul>

So far I have mapped the list of items like below in function:

filterItems = (itemList) => {
    result = result.map((item, index) => (
        <li className="brand-item" key={index}><a href="#">
            <img onError={this.nobrandimage} src={item.thumbnail} className="img-responsive" /></a>
        </li>
    ))
    return result;
}

Below is my render function:

render(){
    //code to get the letterkey, I am not sure how to put this in map function to render**
    var letters = '', groups = {};
    for (var i = 0, len; i < len; i++) {
        var letterKey = brands[i].name.charAt(0).toLowerCase(); // get the first letter
        if (letters.indexOf(letterKey) === -1) {
            letters += letterKey;
            groups[letterKey] = [brands[i]];
        } else {
            groups[letterKey].push([brands[i]]);
        }
    };

    console.log(letters);

    let brands = this.props.brands.all_brands
    if (brands) brands.sort(this.dynamicSort("name"));
    if (brands) len = brands.length
    const filteredList = this.filterItems(brands, letters);
    return (
        <ul>
            {filteredList}
        </ul>
    );
}

Note: I need help to map the first letter to my list in heading tag.

Sample App Url to have a better view: https://stackblitz.com/edit/react-pfzlvo

2
  • Can you create demo to reproduce an issue? Commented Jan 7, 2019 at 8:58
  • @Justcode Please check this url for sample app stackblitz.com/edit/react-pfzlvo Commented Jan 7, 2019 at 11:47

3 Answers 3

3

Preprocess your brands into a map {letterKey: [brands]} to use in render function.

const groups = brands.reduce((groups, brand) => {
  const letterKey = brand.name.charAt(0).toLowerCase();
  (groups[letterKey] || (groups[letterKey] = [])).push(brand);
  return groups;
}, {});

Map the entries of [key, brands] to your unordered list

Object.entries(groups).sort().map(([letterKey, brands]) => (
  <div key={letterKey}>
    <h4>{letterKey}</h4>
    <ul>
      { brands.map(brand => <li key={brand}>{brand}</li>) }
    </ul>
</div>
));

const brands = ['cca', 'ccb', 'ccc', 'bba', 'bbb', 'bbc', 'aaa', 'aab', 'aac'];

const groups = brands.reduce((groups, brand) => {
  const letterKey = brand.charAt(0).toLowerCase();
  (groups[letterKey] || (groups[letterKey] = [])).push(brand);
  return groups;
}, {});


Object.entries(groups).sort().map(([letterKey, brands]) => {
  console.log('KEY', letterKey);
  brands.map(brand => console.log('\tbrand', brand));
});

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

9 Comments

Thanks for the reply, I already have a json structure which is not having key so I am generating the alphabet first letter with this if (brands) len = brands.length var letters = '', groups = {}; for (var i = 0, len; i < len; i++) { var letterKey = brands[i].name.charAt(0).toLowerCase(); // get the first letter if (letters.indexOf(letterKey) === -1) { letters += letterKey; groups[letterKey] = [brands[i]]; } else { groups[letterKey].push([brands[i]]); } }; console.log(letters);
I just need to map letters in this function which I wrote outside render filterItems = (itemList) => { result = result.map((item, index) => ( <li className="brand-item" key={index}><a href="#"> <img onError={this.nobrandimage} src={item.thumbnail} className="img-responsive" /></a> </li> )) return result; }
Added function to process your brands into map for use in render function.
Thanks for the quick reply, I have create one sample for my code here. Can you please have a look and suggest how can I put this because I am unable to get the data of letters outside the render function. [link] (stackblitz.com/edit/react-pfzlvo)
Doesn't seem like that sandbox renders anything, nor do I see anything in console. Looks like brands or all_brands is static data, just compute it in the constructor or in componentDidMount. Remember, in the constructor you can set state directly, but in componentDidMount you have to call setState. There is no point in having that in the render function as it'll get recomputed on every render call. In fact, that is recommended against.
|
0

After you grouped brands groups = {a: [apple, Ant], b: [Babel, Ball], ...} you can iterate groups like

Object.keys(groups).sort().map(letter, key => (   

    <div key={key}>
        <h4>{letter}</h4>
        <ul>
            {
                groups[letter].map((word, index) => (
                    <li key={index}>{word}</li>
                ))
            }
        </ul>
    </div>


))

Comments

0
Object.keys(groups).map(letter, key => (   

    <div key={key}>
        <h4>{letter}</h4>
        <ul>
            {
                groups[letter].map((word, index) => (
                    <li key={index}>{word}</li>
                ))
            }
        </ul>
    </div>


))

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.