I've tried this:
<template lang="pug">
b-carousel(
id='categoryRoulette'
controls
no-animation
ref="myRoulette"
)
<script lang="ts">
import Vue from 'vue'
export default Vue.extend({
mounted(): void {
this.$refs.myRoulette.pause()
},
But, I've got the following error:
From bootstrap-vue docs:
To pause the carousel from auto sliding, set the interval prop to 0.
To restart a paused carousel, set the interval back to the desired
number of ms.
CHECK THIS DEMO: https://jsfiddle.net/me3610uy/3/
<b-carousel v-model="slide" :interval="interval" >
// your content here
</b-carousel>
new Vue({
//...
data() {
return {
slide: 0,
interval: 3000
}
},
mounted() {
this.interval = 0; // Set the interval variable to zero to pause the carousel
}
})
Get the input value of timer you want to set or set conditional value as below.
setSliderTimer: function (e) {
var setSliderTime = document.getElementById("time-input")
var newTimer = setSliderTime.value
if(newTimer > 0){
newTimer = newTimer;
}else{
newTimer = 3000;
}
this.interval = newTimer;
},
Related
<template>
<div>
<Acomponent />
<Bcomponent />
<div #click="openWindow()">hellow</div>
</div>
</template>
<script>
export default {
data() {
return {}
},
methods: {
openWindow() {
const width = '1000'
const height = '600'
const left = Math.ceil((window.screen.width - width) / 2)
const top = Math.ceil((window.screen.height - height) / 2)
window.open(location.href, `width=${width}, height=${height}, left=${left}, top=${top}, resizable=yes, scrollbars=yes`)
},
},
}
</script>
I hope that after the new window opens, Components A and B will not be seen in the new window. Is there a way?
Yes, create a new attribute in data, default true, and in method openWindow(), set the attribute to false.
In the A and B components, put v-if="this.yourattribute".
I have a loop, in which I get several result from my API call.
Each of them has an property called processing_time that shows how many seconds it has left until something happens.
How can I implement the countdown for each interval?
Here is my <progressbar> component which needs a value for initially displaying the progress (I need it to be dynamic)
<progress-bar :options="options"
:value="data.properties.processing_time"
/>
<span class="progress-bar-seconds"
>{{ data.properties.processing_time }} Seconds left
...</span>
I feel like I need to use computed but I don't exactly know how to do it.
A computed prop is probably not the best solution, since you need to change the timer value locally. I recommend using a local copy that is updated periodically:
Create a local data property (a ref).
Copy the value prop to the local data prop upon mounting.
Use setInterval to periodically decrement the value.
<template>
<div>
<span class="progress-bar-seconds">{{ seconds }} Seconds left ...</span>
</div>
</template>
<script>
import { ref, onMounted, onUnmounted } from 'vue'
export default {
props: {
value: {
type: Number,
default: 0,
required: true,
},
},
setup(props) {
const seconds = ref(0) // 1️⃣
let _timerId = null
onMounted(() => {
seconds.value = props.value // 2️⃣
if (seconds.value > 0) {
// 3️⃣
_timerId = setInterval(() => {
seconds.value--
if (seconds.value <= 0) {
clearInterval(_timerId)
}
}, 1000)
}
})
onUnmounted(() => clearInterval(_timerId))
return { seconds }
}
}
</script>
demo
I have a filter input field and want to filter a list of items. The list is large so I want to use debounce to delay the filter being applied until the user has stopped typing for improved user experience. This is my input field and it's bound to filterText that is used to filter the list.
<input type="text" v-model="state.filterText" />
I didn't find any nice solution as I wanted to see my binding in my template so I decided to share my solution. I wrote a simple debounce function and use the following syntax to bind the behavior:
setup() {
...
function createDebounce() {
let timeout = null;
return function (fnc, delayMs) {
clearTimeout(timeout);
timeout = setTimeout(() => {
fnc();
}, delayMs || 500);
};
}
return {
state,
debounce: createDebounce(),
};
},
And the template syntax:
<input
type="text"
:value="state.filterText"
#input="debounce(() => { state.filterText = $event.target.value })"
/>
Hi first time answering something here, so correct my answer as much as you want, I'd appreciate it.
I think that the prettiest and lightest solution is to create a directive globally that you can use as much as you want in all of your forms.
you first create the file with your directive, eg.
debouncer.js
and you create the function for the debouncing
//debouncer.js
/*
This is the typical debouncer function that receives
the "callback" and the time it will wait to emit the event
*/
function debouncer (fn, delay) {
var timeoutID = null
return function () {
clearTimeout(timeoutID)
var args = arguments
var that = this
timeoutID = setTimeout(function () {
fn.apply(that, args)
}, delay)
}
}
/*
this function receives the element where the directive
will be set in and also the value set in it
if the value has changed then it will rebind the event
it has a default timeout of 500 milliseconds
*/
module.exports = function debounce(el, binding) {
if(binding.value !== binding.oldValue) {
el.oninput = debouncer(function(){
el.dispatchEvent(new Event('change'))
}, parseInt(binding.value) || 500)
}
}
After you define this file you can go to your main.js import it and use the exported function.
//main.js
import { createApp } from 'vue'
import debounce from './directives/debounce' // file being imported
const app = createApp(App)
//defining the directive
app.directive('debounce', (el,binding) => debounce(el,binding))
app.mount('#app')
And its done, when you want to use the directive on an input you simply do it like this, no imports or anything.
//Component.vue
<input
:placeholder="filter by name"
v-model.lazy="filter.value" v-debounce="400"
/>
The v-model.lazy directive is important if you choose to do it this way, because by default it will update your binded property on the input event, but setting this will make it wait for a change event instead, which is the event we are emitting in our debounce function. Doing this will stop the v-model updating itself until you stop writing or the timeout runs out (which you can set in the value of the directive).
I hope this was understandable.
<template>
<input type="text" :value="name" #input="test" />
<span>{{ name }}</span>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue'
function debounce<T> (fn: T, wait: number) {
let timer: ReturnType<typeof setTimeout>
return (event: Event) => {
if (timer) clearTimeout(timer)
timer = setTimeout(() => {
if (typeof fn === 'function') {
fn(event)
}
}, wait)
}
}
export default defineComponent({
setup () {
const name = ref('test')
function setInputValue (event: Event) {
const target = event.target as HTMLInputElement
name.value = target.value
}
const test = debounce(setInputValue, 1000)
return { name, test }
}
})
</script>
With Lodash, you have an easier solution:
<template>
<input type="text" :value="name" #input="onInput" />
<span>{{ name }}</span>
</template>
<script>
import debounce from "lodash/debounce"
export default {
setup () {
const onInput = debounce(() => {
console.log('debug')
}, 500)
return { onInput }
}
}
</script>
<input #input="updateValue"/>
const updateValue = (event) => {
const timeoutId = window.setTimeout(() => {}, 0);
for (let id = timeoutId; id >= 0; id -= 1) {
window.clearTimeout(id);
}
setTimeout(() => {
console.log(event.target.value)
}, 500);
};
You can try this one
Here's an example with Lodash and script setup syntax using a watcher to fire the debounced api call:
<script setup>
import { ref, watch } from 'vue'
import debounce from 'lodash.debounce'
const searchTerms = ref('')
const getFilteredResults = async () => {
try {
console.log('filter changed')
// make axios call here using searchTerms.value
} catch (err) {
throw new Error(`Problem filtering results: ${err}.`)
}
}
const debouncedFilter = debounce(getFilteredResults, 250) // 250ms delay
watch(() => searchTerms.value, debouncedFilter)
</script>
<template>
<input v-model="searchTerms" />
</template>
https://www.npmjs.com/package/vue-debounce now works for vue 3
It can be registered also with composition API like this
setup() {
...
},
directives: {
debounce: vue3Debounce({ lock: true })
}
In my nuxtjs app static folder I have a file called data.json
in my component I use this data like so
<script>
import data from '~/static/data.json';
export default {
data ({ params }) {
return {
data
}
}
}
</script>
now I have a method that will basically take values from that data and create a little counting up animation like so
methods: {
countUp(value) {
for (let i = 0; i <= value; i++) {
setTimeout(() => {
return i;
}, 100);
}
}
}
and in my template I am calling it like so
<template>
<div>
<p>{{countUp(data.number)}}</p>
</div>
</template>
now the expected result is for the number to quickly change from 0 to the value but nothing is being printed on the dom if I inspect the html element its empty??
What am I doing wrong??
setTimeout doesn't work the way you think it does:
You can't return a value from inside the callback function; nothing is being returned from the countUp method.
The call to setTimeout doesn't block, meaning it will return immediately after being called and the callback function passed to it is scheduled for execution asynchronously after the timeout has passed. So every setTimeout call in the for loop will be executed all at once after 100 ms instead of staggered.
You will need to store the current counter value as data on the component so Vue knows to rerender when its value is changed.
The simplest example I can provide follows, but you might want to encapsulate the logic in a separate reusable component.
const value = 50
new Vue({
el: '#app',
data: {
counter: 0,
},
methods: {
countUp() {
const interval = setInterval(() => {
this.counter++
if (this.counter >= value) {
clearInterval(interval)
}
}, 100)
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<button #click="countUp">Count Up</button>
{{ counter }}
</div>
I'm trying to listen to a scroll event inside the specific element but it doesn't seem to be working inside the created function, below is my attempt and here's the fiddle.
Try to un-comment the scroll event outside the Vue instance and you'll know
new Vue({
el : '#vueapp',
data : {
showSearchBar : 0
},
created(){
const _self = this;
document.querySelector('#app').onscroll = function() {
alert();
if(document.querySelector('#app').scrollTop >= 10) {
_self.showSearchBar = 1;
}else{
_self.showSearchBar = 0;
}
}
// --
}
});
While moving the event handler to mounted (as suggested by Sovalina in the comments) works, it isn't the Vue way to do this.
With Vue, you should embed the event handler information inside the html template instead:
(Basing this on the code you posted on jsfiddle)
<div id="vueapp">
<div id="app" #scroll="handleScroll">
</div>
</div>
JavaScript:
new Vue({
el : '#vueapp',
data : {
showSearchBar : 0
},
methods: {
handleScroll(evt) {
if(evt.target.scrollTop >= 10) {
this.showSearchBar = 1;
}else{
this.showSearchBar = 0;
}
}
},
});