Nikk
Nikk

Reputation: 7889

Adding parent div's inside .map

Is there any way I can include the wrapping div's FilterListContainer, FilterListScroll and FilterList in the map itself?

So if there is something to map, it will add the parent div's. If not it wont.

 <FilterListContainer>
      <FilterListScroll>
           <FilterList>
              {Object.keys(this.props.body_search_filter)
                .map((k) => (
                  <SidebarFilter
                    key={k}
                    type={k}
                    filter={this.props.body_search_filter[k]}
                    handleChange={this.handleFilterChange}
                  />
                ))
                .filter(
                  (i) =>
                    i.props.filter.list.length > 0 &&
                    ((!i.props.filter.optional && !i.props.filter.hidden) ||
                      (i.props.filter.list.length !== 1 &&
                        !i.props.filter.list[0].disabled))
           </FilterList>
      </FilterListScroll>
 </FilterListContainer>

Upvotes: 0

Views: 146

Answers (2)

0stone0
0stone0

Reputation: 43934

Moving my comment to an answer to add a snippet


You could do the map before the return. Then you can 'check' if the map has some content, if so, use it, otherwise, don't render (or use fallback)

Please see comments in code

const { useState } = React;

const Example = () => {

    // Demo data
    const [data, setData] = useState([ 'foo', 'bar' ])

    // Filter + Mapping logic
    const mapped = data
      .filter(d => d !== 'foobar')
      .map(d => <li>{d.toUpperCase()}</li>);
    
    // Content based on map, use it, or render 'null'
    // The wrapped 'ul' is OP's FilterListContainer as an example
    const content = !mapped.length ? null :
      (
        <div>
          <ul>
            {mapped}
          </ul>
        </div>           
    );
    
    // Render
    return content;
}
ReactDOM.render(<Example />, document.getElementById("react"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="react"></div>

Upvotes: 0

tenshi
tenshi

Reputation: 26326

You'll be able to use short-circuiting of logical operators here:

{Object.keys(this.props.body_search_filter).length && (
  <FilterListContainer>
      <FilterListScroll>
           <FilterList>
              {Object.keys(this.props.body_search_filter)
                .map((k) => (
                  <SidebarFilter
                    key={k}
                    type={k}
                    filter={this.props.body_search_filter[k]}
                    handleChange={this.handleFilterChange}
                  />
                ))
                .filter(
                  (i) =>
                    i.props.filter.list.length > 0 &&
                    ((!i.props.filter.optional && !i.props.filter.hidden) ||
                      (i.props.filter.list.length !== 1 &&
                        !i.props.filter.list[0].disabled))
           </FilterList>
      </FilterListScroll>
  </FilterListContainer>
)}

But you might want to filter the list, then check if the filtered list has any elements instead:

const filtered = Object.keys(this.props.body_search_filter).filter((k) => {
    const f = this.props.body_search_filter[k];

    return f.list.length > 0 && 
        ((!f.optional && !f.hidden) ||
            (f.list.length !== 1 && !f.list[0].disabled))
});

// ...

// then use 'filtered' instead

{filtered.length && (
  <FilterListContainer>
      <FilterListScroll>
           <FilterList>
              {filtered.map((k) => (
                  <SidebarFilter
                    key={k}
                    type={k}
                    filter={this.props.body_search_filter[k]}
                    handleChange={this.handleFilterChange}
                  />
              ))}
           </FilterList>
      </FilterListScroll>
  </FilterListContainer>
)}

Upvotes: 1

Related Questions