No More Posting New Topics!

If you have a question or an issue, please start a thread in our Github Discussions Forum.
This forum is closed for new threads/ topics.

Navigation

    Quasar Framework

    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search

    Qtable, fail to make Masonry layout if I put iframe.....

    Help
    2
    12
    437
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • M
      murvinlai last edited by

      I have followed the Masonry example in Flexbox pattern (https://quasar.dev/layout/grid/flexbox-patterns) . However, when I notice is, if I put iframe in the qCard, it will screw up the masonry layout.

      Original code:

      <template v-slot:item="props">
              <div class="q-pa-xs col-xs-12 col-sm-6 col-md-4">
                <q-card>
                  <q-card-section class="text-center">
                    Address for 
                    <br>
                    <strong>{{ props.row.address }}</strong>
                  </q-card-section>
                  <q-separator />
                  <q-card-section class="flex flex-center" >
                    <div>{{ props.row.description }} g</div>
                  </q-card-section>
                </q-card>
              </div>
            </template>
      

      Screen Shot 2020-09-18 at 12.14.26 PM.png

      Now,… i add iframe or qvideo (which is also iframe) to the qcard:

      <template v-slot:item="props">
              <div class="q-pa-xs col-xs-12 col-sm-6 col-md-4">
                <q-card>
                  <q-card-section class="text-center">
                    Address for
                    <br>
                    <strong>{{ props.row.address }}</strong>
                  </q-card-section>
                  <q-separator />
                  <q-card-section class="flex flex-center" >
                    <div>{{ props.row.description }} g</div>
                    <q-video
                      src="https://www.youtube.com/embed/k3_tw44QsZQ?rel=0"
                    />
                  </q-card-section>
                </q-card>
              </div>
            </template>
      

      Screen Shot 2020-09-18 at 12.17.26 PM.png

      now, it will just run on in the first row. I tried different things, like iframe with style, etc but nothing works.

      I am not sure why iFrame doesn’t work…

      beets 1 Reply Last reply Reply Quote 0
      • beets
        beets @murvinlai last edited by

        @murvinlai I am not sure it has anything to do with the iframes themselves. The biggest downside about the masonry layout is that you need to know the height of the container. It looks like you may not have updated the height to account for the taller cards. Can you try to increase the height first and see if it still breaks?

        1 Reply Last reply Reply Quote 0
        • M
          murvinlai last edited by

          I have added:

          <template v-slot:item=“props”>
          <div class=“q-pa-xs col-xs-12 col-sm-6 col-md-4” style=“height:200px” >
          <q-card>

          and it works. wrapping around.
          However, if I use min-height it won’t work, I can set a fix height by px or % but it will cut off the long card. so, is there a way to dynamically determine & set the height?

          beets 1 Reply Last reply Reply Quote 0
          • beets
            beets @murvinlai last edited by

            @murvinlai Perhaps I wasn’t clear enough in my answer: the height must be set on the q-table itself, not the individual items. So, you’ll need to know beforehand the approximate heights of each card and calculate from there. It isn’t ideal, but that’s the only css-only approach. It’s possible to use JS to actually calculate and resize the q-table though, but it’s not a great UX.

            1 Reply Last reply Reply Quote 0
            • M
              murvinlai last edited by

              Thanks… if I don’t use Qtable to do Masonry layout, is there a better way to do it without QTable? any insight? 🙂

              beets 1 Reply Last reply Reply Quote 0
              • beets
                beets @murvinlai last edited by

                @murvinlai What exactly do you want to accomplish? How many cards will you have? Will they change often? Will there always be the same amount of cards shown?

                1 Reply Last reply Reply Quote 0
                • M
                  murvinlai last edited by

                  What I trying to get is to display a bunch of cards. I think I will start with a fix number of cards, e.g. 12 or 15 cards per page, with pagination. So, last page will most likely won’t be full. The cards are fixed after loading.

                  However, if it is easy to just keep loading cards while scrolling down, it may work too.

                  beets 1 Reply Last reply Reply Quote 0
                  • beets
                    beets @murvinlai last edited by beets

                    @murvinlai If the average card size is the same, you can also just place them in a row of columns. Basic HTML structure is like this (not tested)

                    <div class="row q-col-gutter-md">
                    
                      <div class="col-4">
                        <div class="column q-gutter-y-md">
                    
                          <!-- Items in first column go here -->
                          <div class="col-auto">
                            <q-card>...</q-card>
                          </div>
                          <div class="col-auto">
                            <q-card>...</q-card>
                          </div>
                          <!-- End of items in first column -->
                    
                        </div>
                      </div>
                    
                    
                      <div class="col-4">
                        <div class="column q-gutter-y-md">
                    
                          <!-- Items in second column go here -->
                          <div class="col-auto">
                            <q-card>...</q-card>
                          </div>
                          <div class="col-auto">
                            <q-card>...</q-card>
                          </div>
                          <!-- End of items in second column -->
                    
                        </div>
                      </div>
                    
                    
                    
                      <div class="col-4">
                        <div class="column q-gutter-y-md">
                    
                          <!-- Items in third column go here -->
                          <div class="col-auto">
                            <q-card>...</q-card>
                          </div>
                          <div class="col-auto">
                            <q-card>...</q-card>
                          </div>
                          <!-- End of items in third column -->
                    
                        </div>
                      </div>
                    
                    </div>
                    

                    To use dynamic data, you can use computed properties to separate the cards into columns:

                    computed: {
                      col1() {
                        // slice the first four items, where this.items is your full list
                        return this.items.slice(0, 4)
                      },
                      col2() {
                        return this.items.slice(4, 8)
                      },
                      col3() {
                        return this.items.slice(8, 12)
                      },
                    }
                    

                    And then:

                    <div class="row q-col-gutter-md">
                    
                      <div class="col-4">
                        <div class="column q-gutter-y-md">
                          <div 
                            v-for="items in col1"
                            :key="item.uniq_id"
                            class="col-auto"
                            >
                            <q-card>...</q-card>
                          </div>
                        </div>
                      </div>
                    
                      <div class="col-4">
                        <div class="column q-gutter-y-md">
                          <div 
                            v-for="items in col2"
                            :key="item.uniq_id"
                            class="col-auto"
                            >
                            <q-card>...</q-card>
                          </div>
                        </div>
                      </div>
                    
                      <div class="col-4">
                        <div class="column q-gutter-y-md">
                          <div 
                            v-for="items in col3"
                            :key="item.uniq_id"
                            class="col-auto"
                            >
                            <q-card>...</q-card>
                          </div>
                        </div>
                      </div>
                    
                    </div>
                    

                    This should work okay if you don’t use infinite scrolling. If you do, you’ll need a bit more logic in the computed properties where you slice the main items array, i.e. for col1 items, it would be something like:

                      col1() {
                        // slice the first four items
                        return [
                          ...this.items.slice(0, 4),
                          ...this.items.slice(12, 16),
                        ]
                      },
                    

                    (of course you can abstract that a bit and not have to hardcode it.) However, since this method won’t auto-balance different height cards, the infinite scroll will get pretty uneven columns at some point where one column is much taller than another one.

                    You can apply more logic on top of this if you do know the height of each card, but that can get pretty tricky to implement. That being said, also take a look at https://infinite-scroll.com/#masonry-isotope-packery . I haven’t ever integrated that into Vue, so not sure how nicely it will play together.

                    Edit: a better computed function is actually like this (it just dawned on me 😁 )

                    computed: {
                      cols() {
                        const cols = [ [], [], [] ]
                        for(let i = 0; i < this.items.length; i++) {
                          cols[i%3].push(this.items[i])
                        }
                        return cols
                      },
                    }
                    

                    and then using v-for="items in cols[0], v-for="items in cols[1], and v-for="items in cols[2]. That should play nicely with the last page where you won’t have all 12 or whatever amount of items I assumed in the original post.

                    1 Reply Last reply Reply Quote 0
                    • M
                      murvinlai last edited by

                      Thank you so much @beets I will try it out and also look into the infinite-scroll website. 🙂

                      1 Reply Last reply Reply Quote 0
                      • M
                        murvinlai last edited by

                        i played around with the code… if I set the qtable height larger, e.g. 300vh, then I don’t have to define the height of qcard. so each qcard can have different height. i believe the qtable height ( or the container height) has to be tall enough to hold all qcard if stack vertically in one column.

                        see here: https://codepen.io/pen/?template=NWNEgVW

                        1 Reply Last reply Reply Quote 0
                        • beets
                          beets last edited by

                          @murvinlai Yes, the height must be set on the qtable if you’re going that route. The height doesn’t need to be equal to all of them stacked in one column, but the height of the tallest of all the columns. With dynamic content this gets tricky though. Also keep in mind when you resize the viewport, text will reflow and possibly change the height of each card.

                          1 Reply Last reply Reply Quote 0
                          • M
                            murvinlai last edited by murvinlai

                            This is very true. 🙂 thanks for the advice.

                            1 Reply Last reply Reply Quote 0
                            • First post
                              Last post