Home > Software engineering >  Output ul tags conditionally in JSX?
Output ul tags conditionally in JSX?

Time:04-01

Setup: Headless Wordpress CMS, GatsbyJs, GraphQL

I think this is a JavaScript ES6 problem rather than a GatsbyJS problem.

I've got a query that outputs an author, title and url. The data is queried from an ACF repeater field, so there could be one, none or many items.

Here's the code:

  {citationPath &&
    citationPath.map(item => {
      return (
        <li key={item.url}>
          <a href={item.url} target="_blank" rel="noopener noreferrer">
            {item.title}
          </a>
          <p>Author: {item.author}</p>
        </li>
      )
    })}
    

THIS WORKS, no problem.

I now want to put a <ul> tag before the code, and a </ul> tag after the code ONLY if some citationPath items are returned.

OPTION #1

I could do this:

  {citationPath &&
    citationPath.map(item => {
      return (
        <ul>
            <li key={item.url}>
            <a href={item.url} target="_blank" rel="noopener noreferrer">
                {item.title}
            </a>
            <p>Author: {item.author}</p>
            </li>
        </ul>
        )
    })}

but then I get a <ul></ul> around each list item.

OPTION #2

I could do this:

<ul>
  {citationPath &&
    citationPath.map(item => {
      return (
        
            <li key={item.url}>
            <a href={item.url} target="_blank" rel="noopener noreferrer">
                {item.title}
            </a>
            <p>Author: {item.author}</p>
            </li>
        
        )
    })}
</ul>

but then I get <ul></ul> when NO citationPath items are returned.

OPTION #3

When I try this:

  {citationPath && parse("<ul>")}
  {citationPath &&
    citationPath.map(item => {
      return (
        <li key={item.url}>
          <a href={item.url} target="_blank" rel="noopener noreferrer">
            {item.title}
          </a>
          <p>Author: {item.author}</p>
        </li>
      )
    })}
  {citationPath && parse("</ul>")}

No HTML is printed out on those posts which do not return citationPath data. However, on those that do I get the following HTML output:

<ul></ul>
<li>
    <a href=[my url] target="_blank" rel="noopener noreferrer">
<li>
[more list items ...]

So it seems that {citationPath && parse("<ul>")} and {citationPath && parse("</ul>")} are being executed before:

  {citationPath &&
    citationPath.map(item => {
      return (
        <li key={item.url}>
          <a href={item.url} target="_blank" rel="noopener noreferrer">
            {item.title}
          </a>
          <p>Author: {item.author}</p>
        </li>
      )
    })}
    

Note: the reason I don't simply go for OPTION #2 is that I don't want screen readers bumping into empty <ul></ul> tags.

Does any one have any ideas on how to solve this?

CodePudding user response:

You just need to put the condition above and make sure to check the condition of length.

{citationPath && citationPath.length > 0 && (
  <ul>
    {citationPath.map(item => {
      return (
        <li key={item.url}>
          <a href={item.url} target="_blank" rel="noopener noreferrer">
            {item.title}
          </a>
          <p>Author: {item.author}</p>
        </li>
      );
    })}
  </ul>
)}

Since this checks both the length and the truethy value of citationPath, this is the solution you're looking for and as an industry professional, I use this code in production.

  • Related