djangodev
djangodev

Reputation: 353

How to render child component for each object and based on conditions?

I feel like I need to combine v-for and v-if but I know that's not possible.

Basically, I want to render a child component for every object in a prop. But I need to parse those objects to extract data that I can pass to the child component as props and use to perform conditional rendering checks.

I can do this pretty simply in react, but not sure how to implement in Vue, I'd appreciate your insight.

React component:

 import { Svg } from './styles'
    import DirectedEdge from './directed-edge'
    import Vertice from './vertice'
    
    type Props = {
      time: number
      vertices: object
      edges: object
      bottomRight: array
    }
    
    // render the graph at a given time (time)
    const Graph = ({ time, edges, vertices, bottomRight }: Props) => {
      return (
        <Svg viewBox={`0 0 ${bottomRight[0]} ${bottomRight[1]}`}>
          {Object.entries(edges).map(([key, data]) => {
            const [u, v] = JSON.parse(key)
    
            return (
              time >= data.timeRange[0] &&
              time <= data.timeRange[1] &&
              vertices[u]?.coord &&
              vertices[v]?.coord && (
                <DirectedEdge
                  key={key}
                  start={vertices[u].coord}
                  end={vertices[v].coord}
                  label={data.label}
                />
              )
            )
          })}
          {Object.entries(vertices).map(([key, data]) => {
            return (
              time >= data.times[0] && (
                <Vertice
                  key={key}
                  center={data.coord}
                  label={data.label}
                />
              )
            )
          })}
        </Svg>
      )
    }
    
    export default Graph

my edges prop data:

edges: {
"[0,10]": { label: 1, timeRange: [ 37, 54 ] },
​​
"[0,1]": { label: 2,  timeRange: [ 1, 34 ] }
}

vertices prop data:

vertices: {
    ​ coord: [ 368.75, 50 ] ​​,
     label: "5" ​​​,
     memoized: false ​​,
     times:[ 0, 36, 56 ]
    }

Upvotes: 0

Views: 789

Answers (1)

Zachary Haber
Zachary Haber

Reputation: 11037

You can use both v-for and v-if, you just have to use the v-for on a template element. The template element is somewhat similar to React Fragments.

I've converted your React code to Vue, though it might be closer to pseudo code as I haven't checked if it works.

<script>
export default {
  props: {
    time: Number,
    edges: Object,
    vertices: Object,
    bottomRight: Array,
  },
  computed: {
    edgeValues() {
      return Object.entries(this.edges).map(([key, data]) => {
        const [u, v] = JSON.parse(key);
        return { u, v, data };
      });
    },
  },
};
</script>
<template>
  <svg :viewBox="`0 0 ${bottomRight[0]} ${bottomRight[1]}`">
    <template v-for="{ u, v, data } in edgeData">
      <directed-edge
        v-if="
          time >= data.timeRange[0] &&
          time <= data.timeRange[1] &&
          vertices[u] &&
          vertices[u].coord &&
          vertices[v] &&
          vertices[v].coord
        "
        :key="u + v"
        :start="vertices[u].coord"
        :end="vertices[v].coord"
        :label="data.label"
      />
    </template>
    <template v-for="(data, key) in edges">
      <Vertice
        v-if="time >= data.times[0]"
        :key="key"
        :center="data.coord"
        :label="data.label"
      />
    </template>
  </svg>
</template>

Upvotes: 1

Related Questions