vue transition with animate.css not working as expected with fadeInUp - vuejs2

For some reason animate.css is not working exactly how I expected it to.
I have this component:
<transition
appear
enter-active-class="animated fadeInUp"
leave-active-class="animated fadeOutDown"
mode="out-in"
>
<span
:key="rotateindex"
:style="{ color: rotatingText[rotateindex].colour }"
>
{{ rotatingText[rotateindex].title }}
</span>
</transition>
The list of text that is rotation is just this:
[
{
"title":"Test 1",
"colour":"#00FFFF"
},
{
"title":"Test 2",
"colour":"#0000FF"
},
{
"title":"Test 3",
"colour":"#FF00FF"
}
]
In my code, I do this:
const textRotate = () => {
rotateindex.value = rotateindex.value + 1;
const index = rotateindex.value;
const text = rotatingText.value;
console.log("text to rotate", text, text.length);
if (index >= text.length) {
rotateindex.value = 0;
}
// Show current Index - For Debug
console.log(rotateindex.value);
console.log(text[rotateindex.value]);
console.log(text[rotateindex.value].title);
};
const startAnimation = () => {
setInterval(() => {
textRotate();
}, 2000);
};
watch(
rotatingText,
(text) => {
if (!text) return;
console.log("text", text);
startAnimation(); // Start the animation
},
{
immediate: true,
}
);
And my text starts animating, the only issue is that it doesn't fadeInUp or fadeOutDown, instead it just fades in and out (opacity only).
Does anyone know how I can get it to move vertically too?

Related

Error when attempting to disable Navigation Buttons in VueJs

In my ticket processing application I currently have a back and forward button contained in my TicketRunner.vue Component, I would like to change it so that these buttons only appear if I have an associated case file, for which I've used V-If:
TicketRunner.Vue
<div class="level nav-btns" v-if='!currentTicketCaseFiles.length'>
<div class="buttons has-addons level-left">
<b-button
#click.prevent="navGoPrev()"
:disabled="currentStepIndex === 0 || navWaiting"
size="is-medium"
>
</div>
export default {
name: 'TicketRunner',
mixins: [NavStepsByIndexMixin()],
components: {
StagePresenter,
CaseFilesStage,
ParticipantsStage,
AttachmentsStage,
CaseFilesRunner,
TicketContextButtons,
},
data: function() {
return {
firstComponentsInitialization: true,
loadingConfirm: false,
confirmationModalActive: false,
confirmationSucceeded: undefined
}
},
props: {
ticketId: {
type: Number,
required: true,
},
},
provide() {
return {
contextButtons: {
capture: (name, callback, title) => this.$refs['contextButtons'].captureButton(name, callback, title),
release: (name) => this.$refs['contextButtons'].releaseButton(name),
enable: (name) => this.$refs['contextButtons'].enableButton(name),
disable: (name) => this.$refs['contextButtons'].disableButton(name),
},
};
},
computed: {
...mapGetters(['currentTicket', 'ticketCaseFiles', 'allCurrentTicketAttachments', 'currentTicketCaseFileNotAssociated',
'currentRequesterType', 'currentTicketStage', 'lastCaseFile']),
caseFiles() {
return this.ticketCaseFiles(this.ticketId);
},
ticketHasAttachments() {
return this.allCurrentTicketAttachments.length > 0;
},
isTicketAssociatedWithCaseFile() {
return !this.currentTicketCaseFileNotAssociated;
},
isFirstNavInitializationInProgress() {
return !this.navReady && this.firstComponentsInitialization;
},
isShowAttachmentsStep() {
return this.ticketHasAttachments && this.currentRequesterType !== 'unknown' &&
(this.isFirstNavInitializationInProgress || this.isTicketAssociatedWithCaseFile)
},
isCurrentTicketResolved() {
return this.currentTicket.status === 'resolved';
},
islastStep() {
return this.navLastStep() && this.lastCaseFile;
}
},
watch: {
ticketId(){
this.navigator.reset();
},
navReady() {
this.moveForwardIfReady();
this.firstComponentsInitialization = false;
}
},
methods: {
...mapActions(['confirmTicket']),
moveForwardIfReady() {
if (this.navigator.currentIndex === 0 && this.firstComponentsInitialization) {
let steps = 0
const step_names = ['case_files_stage']
for(const [_idx, name] of step_names.entries()) {
const ref_name = `step[${name}]`;
if (this.$refs.hasOwnProperty(ref_name) && this.$refs[ref_name].navReady) {
steps += 1
} else {
break
}
}
this.navigator.currentIndex += steps
}
},
confirm() {
this.$buefy.dialog.confirm({
message: this.t('tickets.stages.confirmation.simplified_confirm_reply'),
onConfirm: () => this.confirmStep()
})
},
async confirmStep() {
this.loadingConfirm = true;
const promise = this.confirmTicket(this.ticketId);
return promise.then((response) => {
this.confirmationModalActive = true;
this.confirmationSucceeded = true;
return true; // true is correct here. for goNext it makes parent to stay on on the current step
}).catch(() => {
this.confirmationModalActive = true;
this.confirmationSucceeded = false;
return true; // true is correct here. for goNext it makes parent to stay on on the current step
}).finally(() => this.loadingConfirm = false);
},
},
};
I then receive the following Console Error:
[Vue warn]: Property or method "currentTicketCaseFiles" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property.
I know that "!currentTicketCaseFiles.length" works successfully in the Component CaseFilesStage.vue, which makes me believe I should somehow connect the two? But importing it doesn't seem right to me either. I'm not quite sure how to tackle this issue as I'm quite new at VueJS, and would be happy for any pointers. I'll attach the CaseFilesStage.vue Component below.
CaseFilesStage.vue
<template>
<div class="hero">
<div class="block">
<template v-if="!currentTicket.spamTicket">
<b-field>
<b-input
v-model="filter"
:loading="loading"
:placeholder="t('tickets.stages.case_files.search.tooltip')"
v-on:keyup.enter.native="searchCaseFiles"
type="search"
icon="search"
:class="{ 'preview-enabled': showAttachmentsPreview}"
/>
</b-field>
<template v-if="foundCaseFiles.length">
<h4 class="title is-4 table-title">{{ t('tickets.stages.case_files.search.table_title') }}</h4>
<CaseFilesSearchTable
:case-files="foundCaseFilxes"
:found-by-data-points="foundCaseFilesByParticipant"
:show-header="true"
v-slot="cf">
<b-checkbox v-if="cfBelongsToCurrentTicket(cf.id)" :disabled="true" :value="true"></b-checkbox>
<b-checkbox v-else #input="onFoundCaseFile(cf.id, $event)"></b-checkbox>
</CaseFilesSearchTable>
</template>
<div v-else-if="lookupStatus === 'notFound'">
{{ t('tickets.stages.case_files.search.not_found') }}
<!-- display button here if above is activated -->
</div>
</template>
</div>
<template v-if='currentTicketCaseFiles.length'>
<h4 class="title is-4 table-title">{{ t('tickets.stages.case_files.table_title') }}</h4>
<CaseFilesTable :case-files="currentTicketCaseFiles" :show-header="true" v-slot="cf">
<DeleteButton
:model-id="cf.id"
modelName="CaseFile" >
</DeleteButton>
</CaseFilesTable>
</template>
</div>
</template>
<script>
import CaseFilesTable from '../tables/CaseFilesTable';
import CaseFilesSearchTable from '../tables/CaseFilesSearchTable';
import DeleteButton from '../../../../shared/components/controls/DeleteButton';
import { mapGetters, mapActions } from 'vuex';
import { mapServerActions } from "../../../../../../_frontend_infrastructure/javascript/lib/crudvuex_new";
export default {
name: 'CaseFilesStage',
data() {
return {
lookupStatus: 'waitingInput',
filter: '',
waiting: {},
foundCaseFiles: [],
foundCaseFilesByParticipant: {}
};
},
components: {
CaseFilesTable,
CaseFilesSearchTable,
DeleteButton
},
computed: {
...mapGetters(
['currentTicketCaseFiles', 'currentTicketCaseFileNotAssociated', 'currentTicket', 'showAttachmentsPreview']
),
loading() {
return this.lookupStatus === 'waitingServer';
},
allCaseFilesMix(){
this.currentTicketCaseFiles + this.foundCaseFiles
},
foundCaseFilesEx() {
return this.foundCaseFiles.filter((x) => !this.cfBelongsToCurrentTicket(x.id))
},
checkboxValue() {
if(!this.currentTicketCaseFileNotAssociated) {
return null;
}
return true;
},
navReady() {
return this.currentTicket.spamTicket || this.currentTicketCaseFiles.length > 0 || this.checkboxValue;
},
markSpam: {
get: function() {
return this.currentTicket.spamTicket
},
set: function(val) {
return this.updateTicket([this.currentTicket.id, { spam_ticket: val }]);
},
}
},
methods: {
...mapActions(['updateTicket']),
...mapServerActions(['createCaseFile', 'deleteCaseFile']),
cfBelongsToCurrentTicket(id){
return this.currentTicketCaseFiles.map((x) => x.caseFileId).includes(id);
},
cantAssignCaseFileCheckbox(isChecked){
if(isChecked) {
this.createCaseFile({ isCfNotAssociated: true });
} else {
this.deleteCaseFile(this.currentTicketCaseFileNotAssociated);
}
},
onFoundCaseFile(id, useIt){
console.log("onFoundCaseFile: ", id, useIt);
if(useIt) {
this.createCaseFile({ caseFileId: id });
} else {
this.deleteCaseFile(this.currentTicketCaseFiles.find({ caseFileId: id }));
}
},
searchCaseFiles() {
const newData = this.filter;
if (newData.length < 3) { // TODO: some smarter condition here
this.foundCaseFiles = [];
this.lookupStatus = 'waitingInput';
return;
}
this.lookupStatus = 'waitingServer';
this.$axios.get('case_files', { params: { "case_files.filter" : newData } })
.then((response) => {
this.foundCaseFiles = response.data.caseFilesSearchResult.caseFiles;
this.foundCaseFilesByParticipant = response.data.caseFilesSearchResult.foundByPrivateInfo;
if(this.foundCaseFiles.length > 0) {
this.lookupStatus = 'success';
} else {
this.lookupStatus = 'notFound';
}
}).catch(() => this.lookupStatus = 'error');
}
},
};
</script>
</style>
Add this to your TicketRunner.vue Component script:
computed: {
...mapGetters(['currentTicketCaseFiles'])
}

Automatically Sliding Carousel

I have a carousel in vue which has left and right arrows. So the carousel is changing when you click one of them. What I am trying to achieve is to change the carousel automatically after 5 seconds for example.
So I have a carousel component:
<template>
<div class="carousel" #keydown="checkSlide($event)" tabindex="0">
<slot></slot>
<button #click.prevent="next" class="btn btn-next"><i class="fa fa-angle-right"></i></button>
<button #click.prevent="prev" class="btn btn-prev"><i class="fa fa-angle-left"></i></button>
</div>
</template>
<script>
export default {
data () {
return {
index : 0,
slides : [],
slideDirection: '',
}
},
computed: {
slidesLength() {
return this.slides.length;
}
},
mounted(){
this.slides = this.$children;
this.slides.map( (slide,index) => {
slide.index = index;
});
},
methods: {
next(){
this.index++;
if(this.index >= this.slidesLength){
this.index = 0;
}
this.slideDirection = 'slide-right';
},
prev(){
this.index--;
if(this.index < 0){
this.index = this.slidesLength - 1;
}
this.slideDirection = 'slide-left';
},
checkSlide(event){
if(event.keyCode === 39){
this.next();
}else if (event.keyCode === 37){
this.prev();
}else {
return;
}
},
}
}
</script>
And I also have carouselslide component:
<template>
<transition :name="dir">
<div v-show="visible">
<slot></slot>
</div>
</transition>
</template>
<script>
export default {
data() {
return {
index : 0,
}
},
computed : {
visible() {
return this.index === this.$parent.index;
},
dir() {
return this.$parent.slideDirection;
},
}
}
</script>
At the end I am calling my carousel in my home page like this:
<carousel >
<carousel-slide v-for="ticket in tickets" :key="ticket.id" class="carousel-slider">
<img :src="ticket.src" :alt="ticket.name">
</carousel-slide>
</carousel>
Hope my question is clear and thanks for your helps...
You could use setInterval() to call next() function. After that you should add a beforeDestroy() method to clear the interval.
You can also add a button to to start/stop the interval with the same code.
Example to start auto-slide on page mounted()
mounted(){
....
this.interval = setInterval(() => { this.next() }, 5000)
},
beforeDestroy () {
clearInterval(this.interval)
}
I think we should have a method that do this with a setInterval stored so we can clear it when we call next or prev
data() {
return {
...
interval: null,
}
},
methods: {
switchInterval() {
// if it's already set we clear so we reset calculation
if (this.interval !== null) clearinterval(this.interval);
this.interval = setInterval(() => {
// call next or prev logic
}, 5000)
},
next() {
...
// you can use the same logic in prev()
this.switchInterval()
},
...
},
beforeDestroy() {
// just make sure this.interval is not null
if (this.interval) clearInterval(this.interval)
}

How to set default settings for switch turned on enabled with VueJS?

I have a script coded in VueJS. It currently has two switch buttons that are called R-18 & R18G and they both currently unchecked on default. The function of these switches do is it will filter content that is displayed on the site if you toggle the switch to checked. What I want to do is have both switches to be set checked on default. How can I fix this?
<template>
<div class="setting">
<van-cell center title="cache" :label="size.local | bytes">
<template #right-icon>
<van-button type="primary" size="small" #click="clearCache('local')">clean up</van-button>
</template>
</van-cell>
<van-cell center title="runtime cleanup" :label="size.session | bytes">
<template #right-icon>
<van-button type="info" size="small" #click="clearCache('session')">clean up</van-button>
</template>
</van-cell>
<van-cell center title="R-18" label="NSFW">
<template #right-icon>
<van-switch :value="currentSETTING.r18" #input="onR18Change($event, 1)" size="24" />
</template>
</van-cell>
<van-cell center title="R-18G" label="Extreme NSFW">
<template #right-icon>
<van-switch :value="currentSETTING.r18g" #input="onR18Change($event, 2)" size="24" />
</template>
</van-cell>
</div>
</template>
<script>
import { Cell, Switch, Button, Dialog } from "vant";
import { mapState, mapActions } from "vuex";
import { LocalStorage, SessionStorage } from "#/utils/storage";
export default {
name: "Setting",
data() {
return {
currentSETTING: {
r18: false,
r18g: false
},
size: {
local: 0,
session: 0
}
};
},
computed: {
...mapState(["SETTING"])
},
watch: {
$route() {
this.calcCacheSize();
}
},
methods: {
onR18Change(checked, type) {
let name;
if (type === 1) name = "R-18";
if (type === 2) name = "R-18G";
if (checked) {
Dialog.confirm({
message: `Are you sure you want to enable the display of R-18`,
confirmButtonColor: "black",
cancelButtonColor: "#1989fa",
closeOnPopstate: true
})
.then(() => {
if (type === 1) this.currentSETTING.r18 = checked;
if (type === 2) {
this.currentSETTING.r18g = checked;
setTimeout(() => {
Dialog.alert({
message: `Please note that turning on R-18G switch may have irreversible effects `
});
}, 200);
}
})
.catch(() => {
console.log("cancel");
});
} else {
if (type === 1) this.currentSETTING.r18 = checked;
if (type === 2) this.currentSETTING.r18g = checked;
}
},
calcCacheSize() {
this.size.local = LocalStorage.size;
this.size.session = SessionStorage.size;
},
clearCache(type) {
let showName;
switch (type) {
case "local":
showName = "cache";
break;
case "session":
showName = "runtime cache";
break;
default:
break;
}
Dialog.confirm({
message: `Are you sure you want to clean up?`,
confirmButtonColor: "black",
cancelButtonColor: "#1989fa",
closeOnPopstate: true
}).then(() => {
if (type === "local") LocalStorage.clear();
if (type === "session") SessionStorage.clear();
this.calcCacheSize();
this.$toast.success("cleaned up");
});
},
...mapActions(["saveSETTING"])
},
filters: {
bytes(bytes) {
bytes = Number(bytes);
if (bytes === 0) return "0 B";
const k = 1024;
const dm = 0;
const sizes = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + " " + sizes[i];
}
},
mounted() {
this.currentSETTING = JSON.parse(JSON.stringify(this.SETTING));
this.calcCacheSize();
},
updated() {
this.saveSETTING(JSON.parse(JSON.stringify(this.currentSETTING)));
},
components: {
[Cell.name]: Cell,
[Button.name]: Button,
[Switch.name]: Switch
}
};
</script>
<style lang="stylus" scoped>
.setting {
}
</style>
The comment of Excalibaard is correct.
When you declare your data in the vue component, whatever value you pass to them, that will be the inital state for them.
In your case if you data values to true will work for you.
Be careful, that when we request and populate our component's data, we declare them as null. That will prevent any unwanted initial app states, and ensure that you will only have access on them after request response.

How can I change selected item in qselect on page load

I use a QSelect Dropdown with some options on my page header, like the following:
<q-select
filled
v-model="model"
use-input
hide-selected
fill-input
input-debounce="0"
:options="options"
#filter="filterFn"
hint="Basic autocomplete"
style="width: 250px; padding-bottom: 32px"
emit-value
map-options
>
<template v-slot:no-option>
<q-item>
<q-item-section class="text-grey">
No results
</q-item-section>
</q-item>
</template>
</q-select>
const stringOptions = [
{label:'Google', value:'g1111111111'}, {label:'Facebook', value:'f2222222222'}, {label:'Twitter', value:'t3333333'}, {label:'Apple', value:'a44444444'}, {label:'Oracle', value:'o555555555'}
]
new Vue({
el: '#q-app',
data () {
return {
model: 'f2222222222',
options: stringOptions
}
},
methods: {
filterFn (val, update, abort) {
update(() => {
const needle = val.toLowerCase()
this.options = stringOptions.filter(v => v.label.toLowerCase().indexOf(needle) > -1)
})
}
}
})
How can I use a method to change the selected value on pageload for example from facebook to google?
I think with something like the following but cant get it working:
mounted: function () {
this.model = 'g1111111111'
},
codepen: https://codepen.io/aquadk/pen/JQbbKw
Thanks
You can use updated method, it called after the data changed and virtual dom is created for that component. Then you can update the value of the model.
const stringOptions = [
{label:'Google', value:'g1111111111'}, {label:'Facebook', value:'f2222222222'}, {label:'Twitter', value:'t3333333'}, {label:'Apple', value:'a44444444'}, {label:'Oracle', value:'o555555555'}
]
new Vue({
el: '#q-app',
data () {
return {
model: 'f2222222222',
options: stringOptions
}
},
methods: {
filterFn (val, update, abort) {
update(() => {
const needle = val.toLowerCase()
this.options = stringOptions.filter(v => v.label.toLowerCase().indexOf(needle) > -1)
})
}
},
updated(){
// Update the value of model
this.model = 'g1111111111';
}
})
The mounted should work, if it's not working the way you expect, try inside-mounted nextTick().
Here is an example with your code:
mounted () {
this.$nextTick(() => {
this.model = 'a44444444'
})
},

vuejs get ref element height on window resize

I'm trying to get the height of the h1 ref element however it is showing as undefined
how can I get the height of my h1 element?
export default {
data() {
return {
h1: null,
};
},
methods: {
getH1Height() {
console.log(this.h1);
},
},
mounted() {
this.$nextTick(() => {
this.h1 = this.$refs.h1;
});
window.addEventListener('resize', () => {
this.getH1Height();
});
},
};
template.js
<h1
ref="h1">
{{ productTitle }}
</h1>
you can try :
this.$refs.h1.offsetHeight