Showing events on a multi room scheduler I write a web app that shows events on a multi room scheduler. I use VueJS for the first time on a real project.

Here, I loop through the events array every room column (two nested v-for). In jQuery I need to loop once through this array to fill all columns at once.

My question: is there any other more efficient way to write this code that fills rooms divs with events in Vue?



var vm = new Vue({
        el: '#app',
        data: {
            rooms: [
               {id: 1, title: 'Room 1' },
               {id: 2, title: 'Room 2' }
            ],
            events: [
              { id: 1, start: 230, duration: 30, title: 'Event 1', room_id: 2},
              { id: 2, start: 400, duration: 45, title: 'Event 2', room_id: 1}
            ]
        }
    })
.agenda-wrapper { max-width: 100%; overflow-x: scroll; }

  .agenda { padding-top: 50px; overflow: hidden; }
  
.room {
    width:300px;
    height:1170px;
    padding: 0 10px;
    margin-left: 5px;
    background:#ECECEC;
    position:relative;
    float: left;
}

.room span {
    position: absolute;
    top: -20px;
    height: 10px;
    text-align: center;
    width: 300px;
    font-weight: bold;
}

.event {
    display: block;
    background:#fff;
    color:#4B6EA8;
    border:1px solid #ccc;
    border-left:4px solid #c4183c;
    position:absolute;
    padding:0 10px;
    font-weight:bold;
    font-size:13px;
    border-radius: 5px;
    width: 280px;
}
&lt;div class="agenda-wrapper" id="app"&gt;
  &lt;div class="agenda" :style="{ width: (rooms.length * 350) + 'px' }"&gt;
    &lt;div class="room" v-for="room in rooms" :key="room.id"&gt;
      &lt;span&gt;{{ room.title }}&lt;/span&gt;
      &lt;div class="event" 
        :style="{ top: event.start + 'px', height: event.duration + 'px'}" 
        v-for="event in events" 
        v-if="event.room_id === room.id"&gt;
      &lt;h5&gt;{{ event.title }}&lt;/h5&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"&gt;&lt;/script&gt;
I asked you how you would do it in jQuery and you said that you would do something like:


$.each(events, function(event){
    var el = $("&lt;div&gt;&lt;/div&gt;")
        .addClass("event")
        .css({ "height": event.duration + "px", "top": event.start + "px" })
        .text(event.title);
    $('.room').data('place', event.place_id).append(el);
});



And sure, this would only loop through the events array once. But what happens in every iteration? It does a jQuery search for $('.room').data('place', event.place_id), which is not a constant-time lookup operation, so this approach might be slower than what you think it is.



Now, for your Vue approach. You said:


  maybe I need to do it on backend to make a rooms array look like that: { id: 1, title: 'Room 1', events: [{ id: 1, title: 'Event 1', start: 90, duration: 30 }] } 


And yes, I agree with this. Putting the events inside your rooms makes much more sense.

As for your Vue template, overall the code looks fine. I'm not a CSS expert so I don't know if there's something you can improve there, but there probably is. Maybe consider using CSS Grids, where each room could be one column, and time-slots could be rows? The current approach of having 1px = 1 minute seems a bit unnatural to me.

As for this part:

&lt;div class="room" v-for="room in rooms" :key="room.id"&gt;
  &lt;span&gt;{{ room.title }}&lt;/span&gt;
  &lt;div class="event" 
    :style="{ top: event.start + 'px', height: event.duration + 'px'}" 
    v-for="event in events" 
    v-if="event.room_id === room.id"&gt;
  &lt;h5&gt;{{ event.title }}&lt;/h5&gt;
&lt;/div&gt;


The only thing I would change is to put v-for and v-if before your :style-binding, as they are more important to be aware about, this is mostly my personal opinion though.

&lt;div class="room" v-for="room in rooms" :key="room.id"&gt;
  &lt;span&gt;{{ room.title }}&lt;/span&gt;
  &lt;div class="event" 
    v-for="event in events" 
    v-if="event.room_id === room.id"
    :style="{ top: event.start + 'px', height: event.duration + 'px'}" 
    &gt;
  &lt;h5&gt;{{ event.title }}&lt;/h5&gt;
&lt;/div&gt;


It would be nicer if your events would be inside the rooms, as then you could write:

&lt;div class="room" v-for="room in rooms" :key="room.id"&gt;
  &lt;span&gt;{{ room.title }}&lt;/span&gt;
  &lt;div class="event" 
    v-for="event in room.events" 
    :style="{ top: event.start + 'px', height: event.duration + 'px'}" 
    &gt;
  &lt;h5&gt;{{ event.title }}&lt;/h5&gt;
&lt;/div&gt;


I would recommend in the future to use a Room component and a RoomEvent component so that you could write:

&lt;Room v-for="room in rooms" :key="room.id" /&gt;


And the room-component:

&lt;div class="room"&gt;
  &lt;span&gt;{{ room.title }}&lt;/span&gt;
  &lt;RoomEvent v-for="event in room.events" /&gt;
&lt;/div&gt;


I think that the &lt;h5&gt;{{ event.title }}&lt;/h5&gt; belongs inside the RoomEvent



Overall a nice job!