3

I have following kind of code:

<div>
  <compA />
  <compB />
</div>

How do I make sure that first compA is rendered only after it compB is rendered.

Why I want is I have some dependency on few elements of compA, and style of compB depends on presence of those elements.

Why in details:

I have some complex UI design, where one box will become fixed when you scroll. SO It will not go above the screen when you scroll, it will be fixed once you start scrolling and it start touching the header. So I am using jquery-visible to find if a div with a particular id is visible on the screen, if it is not visible, I change the style and make that box fixed. Following code should give the idea what I am doing:

methods: {
  onScroll () {
    if ($('#divId').visible(false, false, 'vertical')) { // This is div from the compA, so I want to make sure it is rendered first and it is visible
      this.isFixed = false
    } else {
      this.isFixed = true
    }
  }
},
mounted () {
  window.addEventListener('scroll', this.onScroll() }
},
destroyed () {
  window.removeEventListener('scroll', this.onScroll)
}

I dont want to make those in same component as one reason is it dont make sense as the nature of these components, and other I use compA at many places, while compB is specific to only one page. Also layout of these does not allow me to make compB child of compA as suggested in comments.

Any suggestions are welcome.

Saurabh
  • 71,488
  • 40
  • 181
  • 244

2 Answers2

3

An option with events:

<!-- Parent -->
<div>
  <comp-a @rendered="rendered = true"></comp-a>
  <component :is="compB"></component>
</div>
<script>
  // import ...
  export default {
    components: { CompA, CompB },
    watch: {
      rendered: function (val) {
        if (val) this.compB = 'comp-b';
      }
    },
    data() {
      return {
        rendered: false,
        compB: null
      }
    }
  }
</script>

<!-- Component B -->
<script>
  export default {
    mounted() {
      this.$emit('rendered');
    }
  }
</script>
Jonatas Walker
  • 13,583
  • 5
  • 53
  • 82
2

After going through the edit I realised that the dependency is not data driven but event driven (onscroll). I have tried something and looks like it works (the setTimeout in the code is for demonstration).

My implementation is slightly different from that of Jonatas.

<div id="app">
  RenderSwitch: {{ renderSwitch }} // for demonstration 
  <template v-if='renderSwitch'>
    <comp-a></comp-a>  
  </template>
  <comp-b @rendered='renderSwitchSet'></comp-b>
</div>
  1. When the component-B is rendered it emits an event, which just sets a data property in the parent of both component-A and component-B.

  2. The surrounding <template> tags are there to reduce additional markup for a v-if.

  3. The moment renderSwitch is set to true. component-a gets created.

Amresh Venugopal
  • 9,299
  • 5
  • 38
  • 52
  • Thanks, This works, interesting thing is I have to give `setTimeout`, even timeout can be of 0 sec, But without timeout it does not works. any reason why this might be? – Saurabh Mar 29 '17 at 06:00
  • Maybe there is a lot going on in the component where the `$emit` is happening? if yes, then setTimeouts queue the function giving it time to execute, [read here](http://stackoverflow.com/questions/779379/why-is-settimeoutfn-0-sometimes-useful). In the fiddle that I have, it was working even without the timeout. – Amresh Venugopal Mar 29 '17 at 06:05