hi i used to use Options API and i converted my code completely to composition API but now im having a problem with styles which hides the original object i dunno what differs between these APIs but it should not affect the styling this is my both examples in both APIs
first is composition api
<script setup>
import {
QCalendarDay,
addToDate,
parseTimestamp,
isBetweenDates,
today,
parsed,
parseTime
} from '#quasar/quasar-ui-qcalendar/src/index.js'
import '#quasar/quasar-ui-qcalendar/src/QCalendarVariables.sass'
import '#quasar/quasar-ui-qcalendar/src/QCalendarTransitions.sass'
import '#quasar/quasar-ui-qcalendar/src/QCalendarDay.sass'
import { ref ,computed} from 'vue'
import NavigationBar from '../components/NavigationBar.vue'
const calendar=ref(null)
const selectedDate=ref(today())
const events=ref([
{
id: 1,
title: 'Meeting',
details: 'Time to pitch my idea to the company',
date: today(),
time: '09:00',
duration: 120,
bgcolor: 'red',
icon: 'fas fa-handshake'
},
{
id: 2,
title: 'Lunch',
details: 'Company is paying!',
date: today(),
time: '12:00',
duration: 60,
bgcolor: 'teal',
icon: 'fas fa-hamburger'
},
{
id: 3,
title: 'Conference',
details: 'Teaching Javascript 101',
date: today(),
time: '13:00',
duration: 240,
bgcolor: 'blue',
icon: 'fas fa-chalkboard-teacher'
},
{
id: 4,
title: 'Girlfriend',
details: 'Meet GF for dinner at Swanky Restaurant',
date: today(),
time: '19:00',
duration: 180,
bgcolor: 'teal-2',
icon: 'fas fa-utensils'
}
]
)
// computed: {
// convert the events into a map of lists keyed by date
const eventsMap = computed(() => {
const map = {}
// this.events.forEach(event => (map[ event.date ] = map[ event.date ] || []).push(event))
events.value.forEach(event => {
if (!map[ event.date ]) {
map[ event.date ] = []
}
map[ event.date ].push(event)
if (event.days) {
let timestamp = parseTimestamp(event.date)
let days = event.days
do {
timestamp = addToDate(timestamp, { day: 1 })
if (!map[ timestamp.date ]) {
map[ timestamp.date ] = []
}
map[ timestamp.date ].push(event)
} while (--days > 0)
}
})
return map
})
// methods: {
const badgeClasses =(event, type)=> {
let isHeader = type === 'header'
return {
[ `text-white bg-${ event.bgcolor }` ]: true,
'full-width': !isHeader && (!event.side || event.side === 'full'),
'left-side': !isHeader && event.side === 'left',
'right-side': !isHeader && event.side === 'right',
'rounded-border': true
}
}
const badgeStyles = (event, type, timeStartPos = undefined, timeDurationHeight = undefined) =>{
const s = {}
if (timeStartPos && timeDurationHeight) {
s.top = timeStartPos(event.time) + 'px'
s.height = timeDurationHeight(event.duration) + 'px'
}
s[ 'align-items' ] = 'flex-start'
return s
}
const getEvents =(dt) =>{
// get all events for the specified date
const events = eventsMap[ dt ] || []
if (events.length === 1) {
events[ 0 ].side = 'full'
}
else if (events.length === 2) {
// this example does no more than 2 events per day
// check if the two events overlap and if so, select
// left or right side alignment to prevent overlap
const startTime = addToDate(parsed(events[ 0 ].date), { minute: parseTime(events[ 0 ].time) })
const endTime = addToDate(startTime, { minute: events[ 0 ].duration })
const startTime2 = addToDate(parsed(events[ 1 ].date), { minute: parseTime(events[ 1 ].time) })
const endTime2 = addToDate(startTime2, { minute: events[ 1 ].duration })
if (isBetweenDates(startTime2, startTime, endTime, true) || isBetweenDates(endTime2, startTime, endTime, true)) {
events[ 0 ].side = 'left'
events[ 1 ].side = 'right'
}
else {
events[ 0 ].side = 'full'
events[ 1 ].side = 'full'
}
}
return events
}
const scrollToEvent =(event) => {
calendar.value.scrollToTime(event.time, 350)
}
const onToday= ()=> {
calendar.value.moveToToday()
}
const onPrev =() =>{
calendar.value.prev()
}
const onNext =() =>{
calendar.value.next()
}
const onMoved =(data)=> {
console.log('onMoved', data)
}
const onChange =(data)=> {
console.log('onChange', data)
}
const onClickDate =(data) =>{
console.log('onClickDate', data)
}
const onClickTime= (data)=> {
console.log('onClickTime', data)
}
const onClickInterval =(data)=> {
console.log('onClickInterval', data)
}
const onClickHeadIntervals =(data) =>{
console.log('onClickHeadIntervals', data)
}
const onClickHeadDay =(data)=> {
console.log('onClickHeadDay', data)
}
</script>
<style lang="sass" >
.my-event
position: absolute
font-size: 12px
justify-content: center
margin: 0 1px
text-overflow: ellipsis
overflow: hidden
cursor: pointer
.title
position: relative
display: flex
justify-content: center
align-items: center
height: 100%
.text-white
color: white
.bg-blue
background: blue
.bg-green
background: green
.bg-orange
background: orange
.bg-red
background: red
.bg-teal
background: teal
.bg-grey
background: grey
.bg-purple
background: purple
.full-width
left: 0
width: calc(100% - 2px)
.left-side
left: 0
width: calc(50% - 3px)
.right-side
left: 50%
width: calc(50% - 3px)
.rounded-border
border-radius: 2px
</style>
<template>
<div class="subcontent">
<navigation-bar
#today="onToday"
#prev="onPrev"
#next="onNext"
/>
<div class="row justify-center">
<div style="display: flex; max-width: 800px; width: 100%; height: 400px;">
<q-calendar-day
ref="calendar"
v-model="selectedDate"
view="day"
animated
bordered
transition-next="slide-left"
transition-prev="slide-right"
no-active-date
:interval-minutes="15"
:interval-start="24"
:interval-count="68"
:interval-height="28"
#change="onChange"
#moved="onMoved"
#click-date="onClickDate"
#click-time="onClickTime"
#click-interval="onClickInterval"
#click-head-intervals="onClickHeadIntervals"
#click-head-day="onClickHeadDay"
>
<template #head-day-event="{ scope: { timestamp } }">
<div style="display: flex; justify-content: center; flex-wrap: wrap; padding: 2px;">
<template
v-for="event in eventsMap[timestamp.date]"
:key="event.id"
>
<q-badge
v-if="!event.time"
:class="badgeClasses(event, 'header')"
:style="badgeStyles(event, 'header')"
style="width: 100%; cursor: pointer; height: 12px; font-size: 10px; margin: 1px;"
>
<div class="title q-calendar__ellipsis">
{{ event.title }}
<q-tooltip>{{ event.details }}</q-tooltip>
</div>
</q-badge>
<q-badge
v-else
:class="badgeClasses(event, 'header')"
:style="badgeStyles(event, 'header')"
style="margin: 1px; width: 100px; max-width: 100px; height: 100px; max-height: 100px; cursor: pointer"
#click="scrollToEvent(event)"
>
<q-tooltip>{{ event.time + ' - ' + event.details }}</q-tooltip>
</q-badge>
</template>
</div>
</template>
<template #day-body="{ scope: { timestamp, timeStartPos, timeDurationHeight } }">
<template
v-for="event in getEvents(timestamp.date)"
:key="event.id"
>
<div
class="my-event"
:class="badgeClasses(event, 'body')"
:style="badgeStyles(event, 'body', timeStartPos, timeDurationHeight)"
>
<div class="title q-calendar__ellipsis">
{{ event.title }}
<q-tooltip>{{ event.time + ' - ' + event.details }}</q-tooltip>
</div>
</div>
</template>
</template>
</q-calendar-day>
</div>
</div>
</div>
</template>
Now options api which has styles(badgestyle method only) run flawlessly
<script>
import {
QCalendarDay,
addToDate,
parseTimestamp,
isBetweenDates,
today,
parsed,
parseTime
} from '#quasar/quasar-ui-qcalendar/src/index.js'
import '#quasar/quasar-ui-qcalendar/src/QCalendarVariables.sass'
import '#quasar/quasar-ui-qcalendar/src/QCalendarTransitions.sass'
import '#quasar/quasar-ui-qcalendar/src/QCalendarDay.sass'
import { defineComponent } from 'vue'
import NavigationBar from '../components/NavigationBar.vue'
export default defineComponent({
name: 'WeekSlotDayBody',
components: {
NavigationBar,
QCalendarDay
},
data () {
return {
selectedDate: today(),
events: [
{
id: 1,
title: 'Meeting',
details: 'Time to pitch my idea to the company',
date: today(),
time: '09:00',
duration: 120,
bgcolor: 'red',
icon: 'fas fa-handshake'
},
{
id: 2,
title: 'Lunch',
details: 'Company is paying!',
date: today(),
time: '12:00',
duration: 60,
bgcolor: 'teal',
icon: 'fas fa-hamburger'
},
{
id: 3,
title: 'Conference',
details: 'Teaching Javascript 101',
date: today(),
time: '13:00',
duration: 240,
bgcolor: 'blue',
icon: 'fas fa-chalkboard-teacher'
},
{
id: 4,
title: 'Girlfriend',
details: 'Meet GF for dinner at Swanky Restaurant',
date: today(),
time: '19:00',
duration: 180,
bgcolor: 'teal-2',
icon: 'fas fa-utensils'
}
]
}
},
computed: {
// convert the events into a map of lists keyed by date
eventsMap () {
const map = {}
// this.events.forEach(event => (map[ event.date ] = map[ event.date ] || []).push(event))
this.events.forEach(event => {
if (!map[ event.date ]) {
map[ event.date ] = []
}
map[ event.date ].push(event)
if (event.days) {
let timestamp = parseTimestamp(event.date)
let days = event.days
do {
timestamp = addToDate(timestamp, { day: 1 })
if (!map[ timestamp.date ]) {
map[ timestamp.date ] = []
}
map[ timestamp.date ].push(event)
} while (--days > 0)
}
})
return map
}
},
methods: {
badgeClasses (event, type) {
const isHeader = type === 'header'
return {
[ `text-white bg-${ event.bgcolor }` ]: true,
'full-width': !isHeader && (!event.side || event.side === 'full'),
'left-side': !isHeader && event.side === 'left',
'right-side': !isHeader && event.side === 'right',
'rounded-border': true
}
},
badgeStyles (event, type, timeStartPos = undefined, timeDurationHeight = undefined) {
const s = {}
if (timeStartPos && timeDurationHeight) {
s.top = timeStartPos(event.time) + 'px'
s.height = timeDurationHeight(event.duration) + 'px'
}
s[ 'align-items' ] = 'flex-start'
return s
},
getEvents (dt) {
// get all events for the specified date
const events = this.eventsMap[ dt ] || []
if (events.length === 1) {
events[ 0 ].side = 'full'
}
else if (events.length === 2) {
// this example does no more than 2 events per day
// check if the two events overlap and if so, select
// left or right side alignment to prevent overlap
const startTime = addToDate(parsed(events[ 0 ].date), { minute: parseTime(events[ 0 ].time) })
const endTime = addToDate(startTime, { minute: events[ 0 ].duration })
const startTime2 = addToDate(parsed(events[ 1 ].date), { minute: parseTime(events[ 1 ].time) })
const endTime2 = addToDate(startTime2, { minute: events[ 1 ].duration })
if (isBetweenDates(startTime2, startTime, endTime, true) || isBetweenDates(endTime2, startTime, endTime, true)) {
events[ 0 ].side = 'left'
events[ 1 ].side = 'right'
}
else {
events[ 0 ].side = 'full'
events[ 1 ].side = 'full'
}
}
return events
},
scrollToEvent (event) {
this.$refs.calendar.scrollToTime(event.time, 350)
},
onToday () {
this.$refs.calendar.moveToToday()
},
onPrev () {
this.$refs.calendar.prev()
},
onNext () {
this.$refs.calendar.next()
},
onMoved (data) {
console.log('onMoved', data)
},
onChange (data) {
console.log('onChange', data)
},
onClickDate (data) {
console.log('onClickDate', data)
},
onClickTime (data) {
console.log('onClickTime', data)
},
onClickInterval (data) {
console.log('onClickInterval', data)
},
onClickHeadIntervals (data) {
console.log('onClickHeadIntervals', data)
},
onClickHeadDay (data) {
console.log('onClickHeadDay', data)
}
}
})
</script>
<style lang="sass" scoped>
.my-event
position: absolute
font-size: 12px
justify-content: center
margin: 0 1px
text-overflow: ellipsis
overflow: hidden
cursor: pointer
.title
position: relative
display: flex
justify-content: center
align-items: center
height: 100%
.text-white
color: white
.bg-blue
background: blue
.bg-green
background: green
.bg-orange
background: orange
.bg-red
background: red
.bg-teal
background: teal
.bg-grey
background: grey
.bg-purple
background: purple
.full-width
left: 0
width: calc(100% - 2px)
.left-side
left: 0
width: calc(50% - 3px)
.right-side
left: 50%
width: calc(50% - 3px)
.rounded-border
border-radius: 2px
</style>
<template>
<div class="subcontent">
<navigation-bar
#today="onToday"
#prev="onPrev"
#next="onNext"
/>
<div class="row justify-center">
<div style="display: flex; max-width: 800px; width: 100%; height: 400px;">
<q-calendar-day
ref="calendar"
v-model="selectedDate"
view="day"
animated
bordered
transition-next="slide-left"
transition-prev="slide-right"
no-active-date
:interval-minutes="15"
:interval-start="24"
:interval-count="68"
:interval-height="28"
#change="onChange"
#moved="onMoved"
#click-date="onClickDate"
#click-time="onClickTime"
#click-interval="onClickInterval"
#click-head-intervals="onClickHeadIntervals"
#click-head-day="onClickHeadDay"
>
<template #head-day-event="{ scope: { timestamp } }">
<div style="display: flex; justify-content: center; flex-wrap: wrap; padding: 2px;">
<template
v-for="event in eventsMap[timestamp.date]"
:key="event.id"
>
<q-badge
v-if="!event.time"
:class="badgeClasses(event, 'header')"
:style="badgeStyles(event, 'header')"
style="width: 100%; cursor: pointer; height: 12px; font-size: 10px; margin: 1px;"
>
<div class="title q-calendar__ellipsis">
{{ event.title }}
<q-tooltip>{{ event.details }}</q-tooltip>
</div>
</q-badge>
<q-badge
v-else
:class="badgeClasses(event, 'header')"
:style="badgeStyles(event, 'header')"
style="margin: 1px; width: 10px; max-width: 10px; height: 10px; max-height: 10px; cursor: pointer"
#click="scrollToEvent(event)"
>
<q-tooltip>{{ event.time + ' - ' + event.details }}</q-tooltip>
</q-badge>
</template>
</div>
</template>
<template #day-body="{ scope: { timestamp, timeStartPos, timeDurationHeight } }">
<template
v-for="event in getEvents(timestamp.date)"
:key="event.id"
>
<div
v-if="event.time !== undefined"
class="my-event"
:class="badgeClasses(event, 'body')"
:style="badgeStyles(event, 'body', timeStartPos, timeDurationHeight)"
>
<div class="title q-calendar__ellipsis">
{{ event.title }}
<q-tooltip>{{ event.time + ' - ' + event.details }}</q-tooltip>
</div>
</div>
</template>
</template>
</q-calendar-day>
</div>
</div>
</div>
</template>
fixed by adding .value to const events = eventsMap.value[ dt ] || []
Related
I have created a multi items carousel in which i slide one item at a time.
Initially i want to hide prev btn , but when clicked on next btn and one or more item is moved/slide to left in want the prev btn to be visible and when i am at end of the caorusel items i want to hide next button
template
<div class="main-container">
<div class="carousel-container position-relative" ref="container">
<div class="carousel-inner overflow-hidden">
<div class="carousel-track" >
<nuxt-link to="" class="card-container" v-for="(index, i) in 9" :key="i">
<div class="card"></div>
</nuxt-link>
</div>
</div>
<div class="btns-container">
<button class="prevBtn" #click="prev" >
prev
</button>
<button class="nextBtn" #click="next" >
next
</button>
</div>
</div>
</div>
script
methods: {
next() {
const track = document.querySelector('.carousel-track')
const item = document.querySelector('.card-container')
track.scrollLeft += item.clientWidth
},
prev() {
const track = document.querySelector('.carousel-track')
const item = document.querySelector('.card-container')
track.scrollLeft -= item.clientWidth
},
}
styles
.carousel-track{
display: flex;
overflow: auto;
scroll-snap-type: x mandatory;
scroll-behavior: smooth;
scrollbar-width: none;
}
.carousel-track::-webkit-scrollbar {
display: none;
}
.card-container{
flex-shrink: 0;
scroll-snap-align: start;
}
.btns-container button{
position: absolute;
top: 50%;
transform: translateY(-50%);
}
.prevBtn{
left: -1rem;
}
.nextBtn{
right: -1rem;
}
You should not use querySelectors but rather state since you're working with Vue.
Sorry, I didn't had a carousel example so I did something a bit different.
<template>
<div class="main-container">
<div ref="container" class="carousel-container position-relative">
<div class="carousel-inner overflow-hidden">
<div class="carousel-track">
<nuxt-link
v-for="(city, index) in cities"
:key="city.id"
to=""
class="card-container"
>
<div
class="card"
:class="index === currentCityIndex && 'active-city'"
>
{{ city.name }}
</div>
</nuxt-link>
</div>
</div>
<br />
<p>Current city index: {{ currentCityIndex }}</p>
<div class="btns-container">
<button v-show="currentCityIndex !== 0" class="prevBtn" #click="prev">
prev
</button>
<button
v-show="currentCityIndex !== cities.length - 1"
class="nextBtn"
#click="next"
>
next
</button>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
currentCityIndex: 0,
cities: [
{ name: 'New york', id: '1' },
{ name: 'Los Angeles', id: '2' },
{ name: 'Chicago', id: '3' },
{ name: 'Houston', id: '4' },
{ name: 'Philadelphia', id: '5' },
{ name: 'Phoenix', id: '6' },
{ name: 'San Antonio', id: '7' },
{ name: 'San Diego', id: '8' },
{ name: 'Dallas', id: '9' },
{ name: 'San Jose', id: '10' },
],
}
},
methods: {
next() {
this.currentCityIndex++
},
prev() {
this.currentCityIndex--
},
},
}
</script>
<style scoped>
.active-city {
border: 2px solid red;
}
</style>
The idea is mainly to do a check on the button with v-show="currentCityIndex !== 0" and display it depending on the current index you're on. You can of course also use visibility or any kind of cool CSS approach to avoid any shift regarding the location of the buttons.
v-show="currentCityIndex !== cities.length - 1" is checking if we are on the last element of your collection.
This is a basic carrousel I sometimes use and modify if I need it. It is originally an infinite carrousel but I added that function you are looking for.
You can copy the code and check how it works and sure I can be improve a lot. But so far it works.
Template
<template>
<div class="main-container">
<div class="carrousel-container">
<span ref="nextArrow" #click="nextSlide" class="slider-btn next">
<svg
width="25"
height="43"
viewBox="0 0 25 43"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M23.5858 20.0623L4.39859 0.875151C3.13866 -0.384778 0.984375 0.507553 0.984375 2.28936V40.6638C0.984375 42.4456 3.13866 43.3379 4.39859 42.078L23.5858 22.8908C24.3668 22.1097 24.3668 20.8434 23.5858 20.0623Z"
/>
</svg>
</span>
<span ref="prevArrow" #click="prevSlide" class="slider-btn prev">
<svg
width="25"
height="43"
viewBox="0 0 25 43"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M1.41421 20.0623L20.6014 0.875151C21.8613 -0.384778 24.0156 0.507553 24.0156 2.28936V40.6638C24.0156 42.4456 21.8613 43.3379 20.6014 42.078L1.41421 22.8908C0.633165 22.1097 0.633165 20.8434 1.41421 20.0623Z"
/>
</svg>
</span>
<!-- carousel -->
<div
:id="activeSlideIndex"
v-if="showSlides"
class="carousel-container"
>
<div
class="slide"
ref="slide"
v-for="(slide, idx) in slides"
:class="slide.position"
:key="slide.id"
>
{{ idx }}
</div>
</div>
<!-- carousel -->
</div>
</div>
</template>
Script and Styles
<script>
export default {
props: {
slides: {
type: Array,
default: () => [
{ id: 1, name: "sliderOne" },
{ id: 2, name: "slider Two" },
{ id: 3, name: "slider Three" },
],
},
},
mounted() {
this.orderSlides(this.slides, this.activeSlideIndex);
},
data() {
return {
activeSlideIndex: 0,
showSlides: false,
};
},
methods: {
nextSlide() {
++this.activeSlideIndex;
this.displayOrder(this.activeSlideIndex);
},
prevSlide() {
--this.activeSlideIndex;
this.displayOrder();
},
displayOrder() {
if (this.activeSlideIndex === this.slides.length) {
console.log(this.activeSlideIndex);
this.activeSlideIndex = 0;
} else if (this.activeSlideIndex < 0) {
this.activeSlideIndex = this.slides.length - 1;
}
this.orderSlides(this.slides, this.activeSlideIndex);
},
orderSlides(array, activeIndex) {
array.forEach((element, idx) => {
element.position = "nextSlide";
if (idx === activeIndex) {
element.position = "activeSlide";
} else if (
idx === activeIndex - 1 ||
(activeIndex === 0 && idx === array.length - 1)
) {
element.position = "lastSlide";
}
});
if (!this.showSlides) {
this.showSlides = true;
}
// toggle arrows
if (activeIndex === array.length - 1) {
this.$refs.nextArrow.style.display = "none";
} else if (activeIndex === 0) {
this.$refs.prevArrow.style.display = "none";
} else {
this.$refs.nextArrow.style.display = "block";
this.$refs.prevArrow.style.display = "block";
}
},
},
};
</script>
<style scoped>
.main-container {
height: 100vh;
width: 100%;
background: rgba(0, 0, 0, 0.6);
overflow: hidden;
display: grid;
place-content: center;
}
.carrousel-container {
width: 769px;
height: 631px;
position: relative;
padding-top: 37px;
padding-bottom: 20px;
}
.slider-btn {
position: absolute;
top: 50%;
transform: translateY(-50%);
}
.slider-btn svg {
fill: red;
}
.next {
right: 25px;
}
.prev {
left: 25px;
}
.carousel-container {
width: 600px;
height: 631px;
overflow: hidden;
position: relative;
display: flex;
background: white;
justify-content: center;
align-items: center;
flex-direction: column;
margin: 0 auto;
}
.slide {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 100%;
opacity: 0;
display: flex;
justify-content: center;
align-items: center;
font-size: 2rem;
transition: 0.3s all linear;
background: var(--primary-light);
border-radius: var(--border-radius-1);
}
.slide.activeSlide {
opacity: 1;
transform: translateX(0);
}
.slide.lastSlide {
transform: translateX(-100%);
}
.slide.nextSlide {
transform: translate(100%);
}
img {
width: 100%;
}
</style>
I'm learning Vuejs and I can't see any documentation or examples on how to have conditional class, based on the record.
I have a conditional class with a variable 'taskClassComputed':
<div
v-bind:key="task.id"
v-for="task in currenttasks"
v-bind:class="taskClassComputed"
>
I then have a computed function to determine the class to use:
taskClassComputed: function () {
var classType = "task-openTile";
if (this.state === "CLOSED") {
classType = "task-closedTile";
} else if (this.state === "OPEN") {
if (this.fasttrack != "undefined") {
classType = "task-tile";
} else if (this.score >= 2000) {
classType = "task-fastTrackedTiles";
}
classType = "task-tile";
}
return classType;
},
But the function always returns the default value. Can someone point me to documentation on how I learn how to do this - or tell me where I'm going wrong.
Many thanks.
I've stipped down the page (still working) to show the code being used.
<template #updateParentTasks="updateTasks">
<div id="todo-app" class="relative overflow-hidden">
<div id="data-list-list-view">
<vs-table
#updateParentTasks="updateTasks"
ref="tasktable"
v-model="selected"
:data="currenttasks"
>
<div
v-bind:key="task.id"
v-for="task in currenttasks"
v-bind:class="taskClassComputed"
>
<div>
<div
id="task-card"
v-on="$listeners"
#updateParentTasks="updateTasks"
>
<div #updateParentTasks="updateTasks">
<vs-row vs-w="12">
<vs-col
class="shape"
vs-type="flex"
vs-lg="1"
vs-sm="1"
vs-xs="1"
>Testing</vs-col
>
</vs-row>
</div>
</div>
</div>
</div>
</vs-table>
</div>
</div>
</template>
<script>
import consts from "#/const.js";
function update_itemsbystate(src, itemstate) {
const dest = [];
let i = 0,
j = 0;
for (i = 0; i < src.length; i++) {
if (src[i].state === itemstate) {
/*eslint-disable-next-line*/
console.log(
"item " + itemstate + ":" + i + " " + j + JSON.stringify(src[i])
);
dest[j] = JSON.parse(JSON.stringify(src[i]));
j++;
}
}
return dest;
}
function parseByState(tasks, page) {
let result = "OPEN";
if (page.showDeleted === true) {
result = "DELETED";
} else if (page.showClosed === true) {
result = "CLOSED";
}
return update_itemsbystate(tasks, result);
}
import tasksidebar from "./TaskSidebar";
import QuickTaskPopup from "./QuickTaskPopup";
import { mapGetters } from "vuex";
import taskutils from "../../utils/taskutils";
export default {
name: "TaskList",
components: {
tasksidebar,
QuickTaskPopup,
// NewTaskPopup,
},
data() {
return {
selected: [],
// tasks: [],
currenttasks: [],
isMounted: false,
showOpen: true,
showClosed: false,
showDeleted: false,
// Filter Sidebar
isFilterSidebarActive: true,
clickNotClose: true,
// Data Sidebar
addNewDataSidebar: false,
sidebarData: {},
isPopupActive: false,
isNewPopupActive: false,
};
},
computed: {
...mapGetters(["alltasks"]),
currentPage() {
if (this.isMounted) {
return this.$refs.tasktable.currentx;
}
return 0;
},
queriedItems() {
return this.$refs.tasktable
? this.$refs.tasktable.queriedResults.length
: this.currenttasks.length;
},
windowWidth() {
return this.$store.state.windowWidth;
},
taskClassComputed: function () {
var classType = "task-openTile";
if (this.state === "CLOSED") {
classType = "task-closedTile";
} else if (this.state === "OPEN") {
if (this.fasttrack != "undefined") {
classType = "task-tile";
} else if (this.score >= 2000) {
classType = "task-fastTrackedTiles";
}
classType = "task-tile";
}
return classType;
},
},
mounted() {
this.isMounted = true;
},
methods: {
addNewData() {
this.sidebarData = {};
this.toggleDataSidebar(true);
},
updateTasks() {
console.log("updating tasks in task list");
this.currenttasks = parseByState(this.alltasks, this);
this.$forceUpdate();
},
openTasks() {
if (this.showOpen === false) {
this.showOpen = true;
this.showDeleted = false;
this.showClosed = false;
this.updateTasks();
}
},
closedTasks() {
if (this.showClosed === false) {
this.showOpen = false;
this.showDeleted = false;
this.showClosed = true;
this.updateTasks();
}
},
deletedTasks() {
if (this.showDeleted === false) {
this.showOpen = false;
this.showDeleted = true;
this.showClosed = false;
this.updateTasks();
}
},
editData(data) {
this.sidebarData = data;
this.toggleDataSidebar(true);
},
},
beforeMount() {
this.currenttasks = parseByState(this.alltasks, this);
console.log("pre-mount");
},
created() {
this.setSidebarWidth();
},
};
</script>
<style lang="scss">
.task-fastTrackedTile {
padding: 40 !important;
overflow: hidden;
border: 1px solid;
border-color: red;
background: rgba(184, 96, 96, 0.07);
border-left-width: 7px;
border-left-color: red;
margin-bottom: 5px;
border-radius: 0.5rem;
}
.task-closedTile {
padding: 40 !important;
// overflow: hidden;
border: 1px solid;
border-color: gray;
background: rgba(239, 239, 255, 0.07);
border-left-width: 7px;
border-left-color: gray;
margin-bottom: 5px;
border-radius: 0.5rem;
}
.task-openTile {
padding: 40 !important;
// overflow: hidden;
border: 1px solid;
border-color: rgba(203, 203, 218, 0.4);
border-left-width: 7px;
border-left-color: rgba(25, 25, 170, 0.4);
margin-bottom: 5px;
border-radius: 0.5rem;
}
.taskFasttrackProp {
// overflow: hidden;
// text-overflow: ellipsis;
white-space: nowrap;
font-size: 0.7rem;
color: red;
margin-right: 15px;
}
.taskProp {
// overflow: hidden;
// text-overflow: ellipsis;
white-space: nowrap;
font-size: 0.7rem;
color: blue;
margin-right: 15px;
}
</style>
you can set multiple classes to vue element by using:
<my-componenet :class="['class1', condition1 ? 'class2' : 'class3']" ..
// condition1 can be anything data, computed, prop, ...
also you can check doc for more details
I have the following code CODEPEN
HTML
body
#__nuxt
#__layout
//- CSS Grid
.news-item(:key="item.feed_item_id" :ref="item.feed_item_id" role="listitem" tabindex="0")
.news-item-pubdate 1m
.news-item-title(:style="titleStyle") {{item.title}}
span.news-item-link example.com
.news-item-likes
span.icon.is-small.news-item-vote-icon
i.fa.fa-xs.fa-thumbs-up
span.news-item-vote-count {{item.likes}}
.news-item-dislikes
span.icon.is-small.news-item-vote-icon
i.fa.fa-xs.fa-thumbs-down
span.news-item-vote-count {{item.dislikes}}
.news-item-bullish
span.icon.is-small.news-item-vote-icon
i.fa.fa-xs.fa-arrow-up
span.news-item-vote-count {{item.bullish}}
.news-item-bearish
span.icon.is-small.news-item-vote-icon
i.fa.fa-xs.fa-arrow-down
span.news-item-vote-count {{item.bearish}}
.news-item-comments
span.icon.is-small.news-item-vote-icon
i.fa.fa-xs.fa-comment-alt
span.news-item-vote-count 0
.news-item-tags.has-text-right(:style="tagStyle")
.news-item-tag(v-for='(tag, i) in item.tags' :key='item.tag' #click.stop="updateTag(tag)")
a.button.is-paddingless.is-small.is-uppercase.is-text
|{{tag}}
span(v-if="lineCountTag - 1 === i && item.tags.length > lineCountTag") ...
span(v-else)
//- Flexbox
.news-item2(:key="item.feed_item_id" :ref="item.feed_item_id" role="listitem" tabindex="0")
.news-item-pubdate-wrapper
.news-item-pubdate2 1m
.news-item-content-wrapper
.news-item-title-wrapper
.news-item-title2(:style="titleStyle") {{item.title}}
span.news-item-link2 example.com
.news-item-votes-wrapper
.news-item-likes2
span.icon.is-small.news-item-vote-icon2
i.fa.fa-xs.fa-thumbs-up
span.news-item-vote-count2 {{item.likes}}
.news-item-dislikes2
span.icon.is-small.news-item-vote-icon2
i.fa.fa-xs.fa-thumbs-down
span.news-item-vote-count2 {{item.dislikes}}
.news-item-bullish2
span.icon.is-small.news-item-vote-icon2
i.fa.fa-xs.fa-arrow-up
span.news-item-vote-count2 {{item.bullish}}
.news-item-bearish2
span.icon.is-small.news-item-vote-icon2
i.fa.fa-xs.fa-arrow-down
span.news-item-vote-count2 {{item.bearish}}
.news-item-comments2
span.icon.is-small.news-item-vote-icon2
i.fa.fa-xs.fa-comment-alt
span.news-item-vote-count2 0
.news-item-tags-wrapper
.news-item-tags2.has-text-right(:style="tagStyle")
.news-item-tag2(v-for='(tag, i) in item.tags' :key='item.tag' #click.stop="updateTag(tag)")
a.button.is-paddingless.is-small.is-uppercase.is-text
|{{tag}}
span(v-if="lineCountTag - 1 === i && item.tags.length > lineCountTag") ...
span(v-else)
CSS
/**
Using CSS GRID
*/
:root {
--border-color: lightgray;
}
$grey: hsl(0, 0%, 48%);
$grey-light: hsl(0, 0%, 71%);
$size-7: 0.75rem;
$warning-light: hsl(48, 100%, 67%);
.news-item {
display: grid;
grid-template-areas:
'time title title title title title title tags'
'time likes dislikes bullish bearish comments . tags';
grid-template-rows: 1fr auto;
grid-template-columns: auto auto auto auto auto auto 1fr auto;
border-bottom: 1px solid var(--border-color);
}
.news-item-title {
grid-area: title;
overflow: hidden;
}
.news-item-likes {
grid-area: likes;
}
.news-item-dislikes {
grid-area: dislikes;
}
.news-item-bullish {
grid-area: bullish;
}
.news-item-bearish {
grid-area: bearish;
}
.news-item-comments {
grid-area: comments;
}
.news-item-tags {
grid-area: tags;
overflow: hidden;
}
a.news-item-tag {
color: $grey;
text-decoration: none;
}
.news-item-link {
color: $grey;
font-size: $size-7;
}
.news-item-pubdate {
grid-area: time;
align-self: center;
color: $grey-light;
font-size: $size-7;
}
.news-item-vote-icon {
color: $grey-light;
margin-right: 0.1rem;
}
.news-item-vote-count {
font-size: 0.75rem;
margin-right: 0.5rem;
color: $grey-light;
}
.news-item-selected {
background: $warning-light;
}
/** https://stackoverflow.com/questions/23608346/how-to-style-a-div-like-the-button-element */
.news-item {
cursor: pointer;
user-select: none;
}
a.button.is-paddingless.is-small.is-uppercase.is-text {
text-decoration: none;
line-height: 1.5;
color: $grey;
}
/**
Using FLEXBOX
*/
.news-item2 {
display: flex;
align-items: center;
border-bottom: 1px solid var(--border-color);
}
.news-item-content-wrapper {
flex: 1;
display: flex;
flex-direction: column;
}
.news-item-votes-wrapper {
display: flex;
}
.news-item-title2 {
overflow: hidden;
}
.news-item-link2 {
color: $grey;
font-size: $size-7;
}
.news-item-pubdate2 {
grid-area: time;
align-self: center;
color: $grey-light;
font-size: $size-7;
}
.news-item-vote-icon2 {
color: $grey-light;
margin-right: 0.1rem;
}
.news-item-vote-count2 {
font-size: 0.75rem;
margin-right: 0.5rem;
color: $grey-light;
}
.news-item-tags2 {
overflow: hidden;
}
Vue JS
new Vue({
el: "#__nuxt",
data() {
return {
item: {
feed_item_id: 1,
title: 'The first one is made with a grid layout while the second one is made with a flex layout. The templates are different, how do I load the right one based on what is supported by the browser?',
tags: ['trump', 'putin', 'defi'],
likes: 10,
dislikes: 5,
bullish: 6,
bearish: 0,
},
lineCountTag: 2,
lineCountTitle: 2,
heightPerLineTag: 30,
heightPerLineTitle: 24,
};
},
computed: {
tagStyle() {
return {
height: this.heightPerLineTag * this.lineCountTag + "px",
maxHeight: this.heightPerLineTag * this.lineCountTag + "px"
};
},
titleStyle() {
return {
height: this.heightPerLineTitle * this.lineCountTitle + "px",
maxHeight: this.heightPerLineTitle * this.lineCountTitle + "px"
};
}
}
});
I have made 2 rows, first row is made with grid layout
second one uses flexbox layout
I want a Vue component which basically can load one of them depending on whether the browser supports flexbox or grid
The problem is the templates are different from each other
How do I do this?
I think I got it, need 2 make 2 separate components, one with a flex and one with the css grid as the structure, cannot have both in one component because the structural layout of the item is different using css grid and flexbox, make a 3rd component that checks for support of CSS Grid in JS using a computed property CSS.supports('display', 'grid')
HTML
script#flex(type="text/x-template")
.news-item2(
:key="item.feed_item_id",
:ref="item.feed_item_id",
role="listitem",
tabindex="0"
)
.news-item-pubdate-wrapper
.news-item-pubdate2 1m
.news-item-content-wrapper
.news-item-title-wrapper
.news-item-title2(:style="titleStyle") {{ item.title }}
span.news-item-link2 example.com
.news-item-votes-wrapper
.news-item-likes2
span.icon.is-small.news-item-vote-icon2
i.fa.fa-xs.fa-thumbs-up
span.news-item-vote-count2 {{ item.likes }}
.news-item-dislikes2
span.icon.is-small.news-item-vote-icon2
i.fa.fa-xs.fa-thumbs-down
span.news-item-vote-count2 {{ item.dislikes }}
.news-item-bullish2
span.icon.is-small.news-item-vote-icon2
i.fa.fa-xs.fa-arrow-up
span.news-item-vote-count2 {{ item.bullish }}
.news-item-bearish2
span.icon.is-small.news-item-vote-icon2
i.fa.fa-xs.fa-arrow-down
span.news-item-vote-count2 {{ item.bearish }}
.news-item-comments2
span.icon.is-small.news-item-vote-icon2
i.fa.fa-xs.fa-comment-alt
span.news-item-vote-count2 0
.news-item-tags-wrapper
.news-item-tags2.has-text-right(:style="tagStyle")
.news-item-tag2(
v-for="(tag, i) in item.tags",
:key="item.tag",
#click.stop="updateTag(tag)"
)
a.button.is-paddingless.is-small.is-uppercase.is-text
| {{ tag }}
span(v-if="lineCountTag - 1 === i && item.tags.length > lineCountTag") ...
span(v-else)
script#grid(type="text/x-template")
.news-item(
:key="item.feed_item_id",
:ref="item.feed_item_id",
role="listitem",
tabindex="0"
)
.news-item-pubdate 1m
.news-item-title(:style="titleStyle") {{ item.title }}
span.news-item-link example.com
.news-item-likes
span.icon.is-small.news-item-vote-icon
i.fa.fa-xs.fa-thumbs-up
span.news-item-vote-count {{ item.likes }}
.news-item-dislikes
span.icon.is-small.news-item-vote-icon
i.fa.fa-xs.fa-thumbs-down
span.news-item-vote-count {{ item.dislikes }}
.news-item-bullish
span.icon.is-small.news-item-vote-icon
i.fa.fa-xs.fa-arrow-up
span.news-item-vote-count {{ item.bullish }}
.news-item-bearish
span.icon.is-small.news-item-vote-icon
i.fa.fa-xs.fa-arrow-down
span.news-item-vote-count {{ item.bearish }}
.news-item-comments
span.icon.is-small.news-item-vote-icon
i.fa.fa-xs.fa-comment-alt
span.news-item-vote-count 0
.news-item-tags.has-text-right(:style="tagStyle")
.news-item-tag(
v-for="(tag, i) in item.tags",
:key="item.tag",
#click.stop="updateTag(tag)"
)
a.button.is-paddingless.is-small.is-uppercase.is-text
| {{ tag }}
span(v-if="lineCountTag - 1 === i && item.tags.length > lineCountTag") ...
span(v-else)
script#item(type="text/x-template")
template(v-if="supportsCssGrid", :item="item")
grid(:item="item")
template(v-else)
flex(:item="item")
body
#__nuxt
#__layout
item(:item="item")
Vue JS
const lineClamp = {
data() {
return {
lineCountTag: 2,
lineCountTitle: 2,
heightPerLineTag: 30,
heightPerLineTitle: 24
};
},
computed: {
tagStyle() {
return {
height: this.heightPerLineTag * this.lineCountTag + "px",
maxHeight: this.heightPerLineTag * this.lineCountTag + "px"
};
},
titleStyle() {
return {
height: this.heightPerLineTitle * this.lineCountTitle + "px",
maxHeight: this.heightPerLineTitle * this.lineCountTitle + "px"
};
}
}
};
Vue.component("flex", {
template: "#flex",
mixins: [lineClamp],
props: {
item: {
type: Object,
default: () => {},
required: true
}
}
});
Vue.component("grid", {
template: "#grid",
mixins: [lineClamp],
props: {
item: {
type: Object,
default: () => {},
required: true
}
}
});
Vue.component("item", {
template: "#item",
props: {
item: {
type: Object,
default: () => {},
required: true
}
},
computed: {
supportsCssGrid() {
return CSS.supports("display", "grid");
}
}
});
new Vue({
el: "#__nuxt",
data() {
return {
item: {
feed_item_id: 1,
title:
"The first one is made with a grid layout while the second one is made with a flex layout. The templates are different, how do I load the right one based on what is supported by the browser?",
tags: ["trump", "putin", "defi"],
likes: 10,
dislikes: 5,
bullish: 6,
bearish: 0
},
lineCountTag: 2,
lineCountTitle: 2,
heightPerLineTag: 30,
heightPerLineTitle: 24
};
},
computed: {
tagStyle() {
return {
height: this.heightPerLineTag * this.lineCountTag + "px",
maxHeight: this.heightPerLineTag * this.lineCountTag + "px"
};
},
titleStyle() {
return {
height: this.heightPerLineTitle * this.lineCountTitle + "px",
maxHeight: this.heightPerLineTitle * this.lineCountTitle + "px"
};
}
}
});
I'm trying to make an animation when changing a slide. The old slide disappears with the animation, and the new one shows up with the animation. My animation is alternating. Help. Thank you all !!
var app = new Vue({
el: '#app',
data() {
return {
selectedIndex: 0,
message: "Test work vue",
isOpenSlide: true,
startVal: 0,
decimals: 0,
duration: 2.5,
options: {
useEasing: true,
useGrouping: true,
separator: ',',
decimal: '.',
prefix: '',
suffix: ''
},
items: [
{
title: 'Center of osteopatia and rehabilitation',
url_img: 'https://i.imgur.com/gQp3VSW.jpg',
info_block: [
{
incremental: '800',
description: 'Increasing the number of transactions from organic search results'
},
{
incremental: '240',
description: 'Raising your revenue'
}
]
},
{
title: 'SLide 2',
url_img: 'https://newevolutiondesigns.com/images/freebies/space-wallpaper-5.jpg',
info_block: [
{
incremental: '140',
description: 'Increasing the numb organic search results'
},
{
incremental: '790',
description: 'Raising your revenue'
}
]
},
{
title: ' SLIDE 3',
url_img: 'https://www.planwallpaper.com/static/images/4433836-space-wallpapers.jpg',
info_block: [
{
incremental: '110',
description: 'Increasing the number of trans'
},
{
incremental: '99',
description: 'Raising your revenue'
}
]
}
]
}
},
methods: {
select(index) {
this.selectedIndex = index
},
index_dotnav: function (index) {
this.selectedIndex = index
},
open() {
this.isOpenSlide = true;
},
close() {
this.isOpenSlide = false;
},
toggle() {
if (this.isOpenSlide) {
this.close();
} else {
this.open();
}
},
ChangeSlider() {
setTimeout(() => {
if (++this.selectedIndex === this.items.length) {
this.selectedIndex = 0;
}
this.toggle();
this.ChangeSlider()
}, 5000)
},
callback(instance) {
instance.start();
}
},
mounted() {
this.ChangeSlider();
}
})
.slide-leave-active,
.slide-enter-active {
transition: 1s;
}
.slide-enter {
transform: translate(100%, 0);
}
.slide-leave-to {
transform: translate(-100%, 0);
}
ul {
padding-left: 0;
margin: 0;
}
.img-block,
section > *,
.uk-slideshow,
.uk-slideshow > ul {
height: 100vh !important;
}
.information-slide .uk-container {
position: absolute;
z-index: 1;
top: 0;
bottom: 0;
right: 0;
left: 0;
margin: auto 0;
display: flex;
flex-direction: column;
justify-content: center;
color: #fff;
}
.slideshow > div.dotnav-block {
top: 50%;
left: 95%;
z-index: 2;
}
.slideshow > div.dotnav-block li a {
background: #fff;
}
.slideshow > div.dotnav-block li.active a {
width: 13px;
height: 13px;
}
.slideshow > div.dotnav-block ul {
align-items: center;
}
.slideshow .slideshow-items > li {
display: none;
}
.slideshow .slideshow-items > li.active {
display: block;
position: relative;
}
.slideshow .slideshow-items > li img {
height: 100%;
width: auto;
object-fit: cover;
}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.0.0-rc.14/css/uikit.min.css"/>
<body>
<div id="app">
<section>
<div class="uk-child-width-1-2" uk-grid>
<div>
<h1>{{ message }}</h1>
</div>
<div>
<div id="slideshow">
<div class="slideshow">
<ul class="slideshow-items">
<li v-for="(item,index) in items" :class="{'active':index===selectedIndex}"
v-on:click="select(index)">
<div class="information-slide">
<transition name="slide">
<div class="img-block" v-show="isOpenSlide">
<img v-bind:src="item.url_img" alt="">
</div>
</transition>
<div class="uk-container">
<div class="title title-1">{{item.title}}</div>
<div class="info-block">
<div class="info" v-for="(iblock,ind) in item.info_block">
<div class="incremental">
<span>+</span>
<!--<app-count-up-->
<!--:startVal="startVal"-->
<!--:endVal="iblock.incremental"-->
<!--:decimals="decimals"-->
<!--:duration="duration"-->
<!--:options="options"-->
<!--:callback="onReady"></app-count-up>-->
<span>%</span>
</div>
<div class="description descr-1">{{iblock.description}}</div>
</div>
</div>
</div>
</div>
</li>
</ul>
<div class="dotnav-block uk-position-bottom-center uk-position-small">
<ul class="uk-dotnav uk-dotnav-vertical">
<li :class="{'active':index===selectedIndex}" v-for="(item,index) in items"
v-on:click="index_dotnav(index)">
Item {{index}}</li>
</ul>
</div>
</div>
</div>
</template>
</div>
</div>
</section>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.17/dist/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.0.0-rc.14/js/uikit.min.js"></script>
I know I can use inherit to allow a child component to grab it's parent's properties, BUT the thing is.. is that I need to grab the property AFTER the parent ready method has ran. I'm having this issue everywhere in order to get width and height of parent components that are set in the ready method.
var Carousel = Vue.component('carousel', {
template: '#carousel',
replace: true,
data: function() {
return {
current: 1,
slideWidth: 600,
count: 6,
style: {
width: 600,
viewport: 600,
marginLeft: 0
}
}
},
computed: {
styles: function() {
return {
width: this.style.width + 'px',
marginLeft: this.style.marginLeft + 'px'
}
},
viewport: function() {
return {
width: this.style.viewport + 'px'
}
},
rounds: Math.floor(this.count / this.show)
},
props: ['show', 'slideMargin'],
ready: function() {
this.slideWidth = $(this.$el).width();
this.count = this.$children.length;
this.style.width = (this.slideWidth * this.count) + (this.slideMargin * (this.count * 2));
this.style.viewport = (this.slideWidth * this.show) + (this.slideMargin * (this.show * 2));
}
});
var CarouselSlide = Vue.component('carouselslide', {
template: '#slide',
replace: true,
data: function() {
return {
style: {
width: 200
}
}
},
computed: {
styles: function() {
return {
width: this.style.width + 'px'
}
}
},
ready: function() {
this.style.width = this.$parent.$get('slideWidth');
}
});
new Vue({
el: '#testimonials'
});
#testimonials {
width: 50%;
margin: 0 auto;
position: relative;
float: left;
min-height: 1px;
padding-left: 1.25rem;
padding-right: 1.25rem;
display: block;
}
h3 {
color: #b50937;
text-transform: uppercase;
margin: 0 0 20px;
font-size: 1.75rem;
}
.carousel {
position: relative;
overflow: hidden;
}
.carousel .slides {
overflow: hidden;
margin: 0 auto;
}
.carousel .slides .viewport {
overflow: hidden;
-webkit-transform: translateZ(0);
transform: translateZ(0);
transition: all 800ms cubic-bezier(0.77, 0, 0.175, 1);
transition-timing-function: cubic-bezier(0.77, 0, 0.175, 1);
}
.carousel .slides .slide {
position: relative;
display: block;
float: left;
margin: 0 2px;
}
.carousel .slides .slide .box {
background-color: #d1dbe5;
box-sizing: border-box;
padding: 15px 20px;
}
.view-all {
text-align: right;
}
.arrows {
position: relative;
text-align: right;
width: 100%;
}
.arrows .arrow {
background-color: #d3d3d3;
color: #fff;
padding: 2px 13px;
position: static;
transition: 0.4s ease-in-out;
display: inline-block;
cursor: pointer;
}
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css" rel="stylesheet"/>
<script src="http://cdnjs.cloudflare.com/ajax/libs/vue/0.12.13/vue.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script type="x-template" id="carousel">
<div class="carousel">
<div class="slides" v-style="viewport">
<div class="viewport" v-style="styles">
<content></content>
</div>
</div>
<div class="view-all">View all <i class="fa fa-angle-double-right"></i></div>
<div class="arrows">
<div class="arrow prev" v-on="click: prevSlide"><i class="fa fa-chevron-left"></i></div>
<div class="arrow next" v-on="click: nextSlide"><i class="fa fa-chevron-right"></i></div>
</div>
</div>
</script>
<script type="x-template" id="slide">
<div class="slide" v-style="styles">
<content></content>
</div>
</script>
<section id="testimonials">
<h3>What People Are Saying About Us</h3>
<carousel show="1" slide-margin="2">
<carouselslide>
<div class="phrase">
<div class="box">
We were looking to upgrade our equipment when we came across Ventrac. It was "wow" for
us, why did we suffer for the first six years with these other pieces of equipment when we could of had this.
</div>
</div>
</carouselslide>
<carouselslide>
<div class="phrase">
<div class="box">
We were looking to upgrade our equipment when we came across Ventrac. It was "wow" for
us, why did we suffer for the first six years with these other pieces of equipment when we could of had this.
</div>
</div>
</carouselslide>
</carousel>
</section><!-- END #TESTIMONIALS -->
Here is my Vue code since it's the only part that's relevant, although you can see what I'm having issues with upstairs ^^ (the snippet)
var Carousel = Vue.component('carousel', {
template: '#carousel',
replace: true,
data: function() {
return {
current: 1,
slideWidth: 600,
count: 6,
style: {
width: 600,
viewport: 600,
marginLeft: 0
}
}
},
computed: {
styles: function() {
return {
width: this.style.width + 'px',
marginLeft: this.style.marginLeft + 'px'
}
},
viewport: function() {
return {
width: this.style.viewport + 'px'
}
},
rounds: Math.floor(this.count / this.show)
},
props: ['show', 'slideMargin'],
ready: function() {
this.slideWidth = $(this.$el).width();
this.count = this.$children.length;
this.style.width = (this.slideWidth * this.count) + (this.slideMargin * (this.count * 2));
this.style.viewport = (this.slideWidth * this.show) + (this.slideMargin * (this.show * 2));
}
});
var CarouselSlide = Vue.component('carouselslide', {
template: '#slide',
replace: true,
data: function() {
return {
style: {
width: 200
}
}
},
computed: {
styles: function() {
return {
width: this.style.width + 'px'
}
}
},
ready: function() {
this.style.width = this.$parent.$get('slideWidth');
}
});
new Vue({
el: '#testimonials'
});
The reason I need to get it from the parent is because the clientWidth includes padding which I can't. So I can't do $(this.$el).width() in the data or computed properties data since $el is not available yet. From my child, I need to get this width AFTER the ready method has fired.
Thanks for any insight.
Without looking too closely at your code, my first thought to get parent data in the child is:
computed: {
val: this.$parent.val;
}
But I'm not certain that will work for you. Alternatively you might be able to change your parent's ready method to compiled so it runs before the child.