0

I'm a beginner trying to get my app to pass props that set CSS styles down a chain to child components. I have a listener that checks for view port size, and as the window gets resized, it checks past a certain point and then swaps the css class and passes it down the chain..

I think I may be doing something incorrectly because my child components don't seem to be receiving the new styles and aren't updating in the DOM as I drag the window.

Here is my code.. I removed irrelevant code to make it easier to read:

Page_Listings.vue

    <template>
      <main>
        <section>
        <ListingRack 
          :prp_classes="rackClass" 
        />
        </section>
      </main>
    </template>
    
    <script>
    import ListingRack from './Listing__Rack.vue';
    export default {
      name: 'Front_Page__Panel',
      data() {
        return {
          viewportWidth: window.innerWidth
        }
      },
      methods: {},
      mounted() { window.onresize = () => this.viewportWidth = window.innerWidth },
      components: {ListingRack},
      },
      computed: {
        rackClass: function(){
          let theValue;
          console.log('>> viewport width is now: ',this.viewportWidth)
          if(this.viewportWidth > 1200) { 
              theValue = "grid_view"; 
              console.log('>> grid view')
            }
          else { 
              theValue = 'card_view'; 
              console.log('>> card view') 
          }
          return theValue
        }
      }
    }
    </script>

Listing__Rack.vue

    <template>
      <div class="listing_rack" :class="classes">
        <ul>
            <li v-for="item in listings" :key="item.postId"> 
                // I removed irrelevant code for hte sake of simplicity in this example. 
                // listings is a GraphQL returned array of data that generates a list of "listings".
                  <Listing 
                    :prp_classes=classes
                  />
            </li>
          </ul>
      </div>
    </template>
    
    <script>
    
    import Listing from './Listing.vue'
    
    export default {
      name: 'listing__rack',
      data() {
        return {
          posts: [], // what we get from the database.
          listings: [], // what we copy from the database.
          classes: this.prp_classes
        }
      },
      props: {
          prp_classes: String
      },
      components: {
        Listing
      },
      watch: {
       classes: function(){
         //just to check if we're receiving anything...
         console.log(">> [Listing_Rack](watch)(classes) there was a change to classes!");
       }
      }
    }
    </script>

Listing.vue

    <template>
       <div :id=id 
       :class=classes
       class="listing"
       :style="backgroundStyle"
       >
      </div>
    </template>
    
    <script>
    export default {
      name: 'Listing',
      data() {
        return {
          classes: this.prp_classes,
          backgroundStyle: String
        }
      },
      props: {
        prp_classes: String
      },
      methods: {
        checkClasses: function(){
          if(this.classes === 'grid_view') this.backgroundStyle = 'background: center / cover no-repeat url(background.jpg);';
        }
      },
      mounted: function() {
        this.checkClasses();
      },
      watch: {
        classes: function(){
          this.checkClasses();
        }
      }
    }
    </script>

My console.logs on rackClass so I know the class swapping part is working, but all my subsequent child components don't seem to be updating accordingly..

Can someone tell me what I'm doing wrong? Is there a better way to do this? How come my props aren't being passed when I drag the window, and how can I dynamically set styles in the DOM?

Cmaxster
  • 1,035
  • 2
  • 11
  • 18

1 Answers1

1

Your code does not work because of the one big mistake (don't worry, many people do it)

You are passing your classes using props to child components. But instead of using this prop (prp_classes) directly in the child's template, you create an absolutely unnecessary classes property in the data()

Problem with that is that data() is executed only once when the component is created. If the value of the prp_classes prop changes later, classes property from the data() just holds the old value.

To fix this, remove unnecessary classes from the data and use the prop directly in the template...

...bit more explanation by example what is going on:

let prp_classes = 'card_view'
let classes = prp_classes
prp_classes = 'grid_view'
// prp_classes === 'grid_view', classes  === 'card_view', prp_classes  !== classes 
// strings/numbers/Date ...all work the same

let o1 = { a: 1 }
let o2 = o1
o1.a = 2
// o1.a === 2, o2.a === 2, o1 === o2

More to study

Michal Levý
  • 33,064
  • 4
  • 68
  • 86
  • This is fantastic thank you! It works now.. but.. I thought that "data" was reactive. If I pass a new prop assigned to data shouldn't it update and refresh (reacting to new prop)? Or if I setup a watcher on the prop, could I use that to dynamically assign new props to my data to make it reactive? Trying to understand why it failed the other way. – Cmaxster Jun 10 '21 at 15:38
  • @Cmaxster Yes, `classes` in the `data` creates the reactive property in the component. But by **initialising** it's value to the same value the `prp_classes` prop has at the time `data()` is executed, do not tie the two in some magic way... – Michal Levý Jun 10 '21 at 16:00