Prevent Scrolling in VueJS - javascript

I am trying to prevent scrolling only when the lightbox component is open, but cannot seem to do so. I hope to not use any outside libraries or plug-ins to do this.
My App.vue contains the "LightBox" component, so I am assuming the prevent scrolling function should live in the App.vue as well.
App.vue snippet:
<template>
<div class="SocialAlbumWidget">
<div v-if="isModalVisible && media[activeIndex]">
<LightBox
...
/>
I currently have a "showModal ()" function in the "methods" section, so was thinking of passing that through another function.
Methods:
mothods: {
...
showModal () {
this.isModalVisible = true
},
closeModal () {
this.isModalVisible = false
}
I expect the body to have scroll when the"Lightbox" component is closed and disabled when the "Lightbox" component is open. Thanks! Let me know what other code would be useful.

Prevent scrolling events on LightBox modal itself -
<LightBox
#wheel.prevent
#touchmove.prevent
#scroll.prevent
/>
style overflow: hidden might create some concerns.
such as;
Visibility of scrollbar
UI bounce w.e.f overflow toggle

You could use a watcher to react to changes in isModalVisible and disable the scrolling function by using style="overflow: hidden".
Something along these lines:
// HTML
<btn #click="dialog = !dialog" >Click Me </btn>
// JS
new Vue({
el: '#app',
data () {
return {
dialog: false,
}
},
watch: {
isModalVisible: function() {
if(this.isModalVisible){
document.documentElement.style.overflow = 'hidden'
return
}
document.documentElement.style.overflow = 'auto'
}
}
})

Related

Hide element in VueJs while scrolling

I am making vue project.
I want to hide some component while mouse scrolling, but when scroll ends, want to show component again.
I know using scroll event, but again doesn't shows component.
<div class="table" #scroll="handleScroll()">
.....
</div>
....
<div class="table" id="sumTable">
....
</div>
.....
methods: {
handleScroll() {
$('#sumTable').hide();
},
}
Is this possible in vue?
I resolved this issue.
handleScroll() {
if(this.timer !== null) {
clearTimeout(this.timer);
$("#sumTable").hide();
}
this.timer = setTimeout(function() {
$("#sumTable").show();
}, 150);
},
timer variable is applied.

vue dialog doesn't close/hide

I can't close or hide my vue-dialog and I don't know why. This is my js file from which I call the dialog:
<ItemChooserDialog v-model="showItemChooser" #onItemSelected="onStockSelected" />
export default {
data() {
return {
showItemChooser: false,
}
}),
methods: {
chooseItem(context) {
var self = this;
self.showItemChooser = true;
},
onStockSelected(result) {
var self = this;
let id = result.id;
let name = result.name;
self.showItemChooser = false;
},
}
and this is my Dialog:
<template>
<v-dialog v-model="show" max-width="600">
...
</v-dialog>
</template>
computed: {
show: {
get () {
return this.value
},
set (value) {
this.$emit('input', value)
}
}
},
props: {
value: Boolean
},
methods: {
rowClick{
this.$emit('onItemSelected', clicked_item);
}
}
If I choose an item in the dialog the callback-method "onStockSelected" of the js file runs and self.showItemChooser is set to false but the dialog is still visible.
You don't have any code that actually hides the dialog. The most common way to conditionally hide/show an element is to use the v-if directive.
On your dialog element:
<template>
<v-dialog v-if="value" v-model="show" max-width="600">
...
</v-dialog>
</template>
Check this codesandbox I made: https://codesandbox.io/s/stack-70146776-6tczf?file=/src/components/ItemChooserDialog.vue
I can see you may took as example one of my previous answers. In this case, since you're using the prop value of your custom dialog component to handle the v-dialog v-model. You can close the dialog in two ways.
Closing the dialog from the parent component by setting up your showItemChooser to false. As you're doing on your example. Which I think it's not working because you declared your rowClick method without parentheses in your child component.
Also on my example I decided to use kebab-case on my event name but that just a convention from eslint. Everything else looks alright.
onStockSelected(result) {
var self = this;
let id = result.id;
let name = result.name;
self.showItemChooser = false;
},
Closing the dialog from the child component. Since you're using the computer property show on the v-model of your v-dialog. You can close the dialog by simply setting the show value to false.
closeFromChild() {
this.show = false
}
Last but not least, v-dialog's by default close themselves if you click outside the dialog. If you want to avoid this functionality you can set the persistent prop to your dialog as I did on my example.

How to trigger load event listener in useEffect everytime component rerenders?

I'm trying to convert some static html/css site to react.js. In script tag there is this function that applies some css transition when the window loads everytime. Here's the function below:
window.addEventListener('load', function() {
document.querySelectorAll('.progress-custom-bar-fill').forEach(e => {
e.style.width = `${e.getAttribute('fill-progress')}%`;
})
})
<div
className={`progress-custom-bar-fill ${goodOrOk}`}
fill-progress={progress}
/>
I tried appyling style property directly to the div like this:
<div
style={{ width: `${progress}%` }}
className={`progress-custom-bar-fill ${goodOrOk}`}
fill-progress={progress}
/>
It worked, but it doesn't appy css transiton
I tried useEffect, it works only first time when the window loads, but when switching between pages it doesn't work. This is what I tried:
useEffect(() => {
function updateProgressBar() {
document.querySelectorAll('.progress-custom-bar-fill').forEach((e) => {
e.style.width = `${e.getAttribute('fill-progress')}%`;
});
}
window.addEventListener('load', updateProgressBar);
return () => window.removeEventListener('load', updateProgressBar);
});
How to make useEffect to rerender on load event? Or is there any other solution for this? Thanks in advance

Vue.js + Call the click event for whole page document

With JQuery, click event of the any item in the page can be captured as below.
$(document).click(function(event){
// event.target is the clicked element object
});
How to do the same with Vue.js?
The answer provided by M U is correct and works.
Yet if you don't like messing with your template (e.g. not put a lot of event handlers in it) or your Vue app is only a small part of a bigger application, it's also perfectly fine and acceptable to register event handlers manually.
To add global event handlers in your script the Vue way you should register them in the mounted and remove them in the beforeDestroy hooks.
Short example:
var app = new Vue({
el: '#app',
mounted: function () {
// Attach event listener to the root vue element
this.$el.addEventListener('click', this.onClick)
// Or if you want to affect everything
// document.addEventListener('click', this.onClick)
},
beforeDestroy: function () {
this.$el.removeEventListener('click', this.onClick)
// document.removeEventListener('click', this.onClick)
},
methods: {
onClick: function (ev) {
console.log(ev.offsetX, ev.offsetY)
}
}
})
All of the answers provided works, but none of them mimic the real behavior of $(document).click(). They catch just clicks on the root application element, but not on the whole document. Of course you can set your root element to height: 100% or something. But in case you want to be sure, it's better to modify Bengt solution and attach event listener directly to document.
new Vue({
...
methods: {
onClick() {},
}
mounted() {
document.addEventListener('click', this.onClick);
},
beforeDestroy() {
document.removeEventListener('click', this.onClick);
},
...
});
Remember you need to use #click.stop in children elements if you for some reason need to stop event propagation to the main handler.
Create div as top node, right after <body>
Make it main container and mount VueJS on it.
<div id='yourMainDiv' #click='yourClickHandler'>
In your VueJS <script> part use it:
methods: {
yourClickHandler(event) {
// event.target is the clicked element object
}
}
Also, if you need to track click event outside of specific element, you
can use vue-clickaway component. Example from the demo:
<div id="demo">
<p v-on-clickaway="away" #click="click" :style="{ color: color }">{{ text }}</p>
</div>
new Vue({
el: '#demo',
mixins: [VueClickaway.mixin],
data: {
text: 'Click somewhere.',
color: 'black',
},
methods: {
click: function() {
this.text = 'You clicked on me!';
this.color = 'green';
},
away: function() {
this.text = 'You clicked away...';
this.color = 'red';
},
},
});

angular ui-router stuck in between states

I am using UI-Router in a project. I am using the state resolve functionality provided by the router. When I want to display a loader in between two states and I change states very often the spinner pops up but don't disappear anymore.
The same effect can be found here.
http://rp.js.org/angular-ui-view-spinner/example/index.html
If one clicks fast between the two states the loader won't hide.
I am waiting for the stateChangeStart broadcast and display the loader and on statChangeSuccess, stateChangeError and viewContentLoaded I want't to hide the loader. The stateChangeStart gets fired but stateChangeSuccess doesn't. Any idea why this behaviour appears?
I am using angular-ui-router in version 0.2.18
Here the Code for show and hide:
$rootScope.$on('$stateChangeStart', showLoading);
$rootScope.$on('$stateChangeSuccess', hideLoading);
$rootScope.$on('$stateChangeError', hideLoading);
$rootScope.$on('$viewContentLoaded', hideLoading);
function showLoading() {
$timeout(function () {
angular.element('.loading-indicator').show();
}, 50);
}
function hideLoading() {
$timeout(function () {
angular.element('.loading-indicator').hide();
}, 50);
}
You need to cancel previous timer. See documentation here: https://docs.angularjs.org/api/ng/service/$timeout.
var yourTimer;
function showLoading() {
if (yourTimer) {$timeout.cancel(yourTimer);}
yourTimer = $timeout(function () {
angular.element('.loading-indicator').show();
}, 50);
}
function hideLoading() {
if (yourTimer) {$timeout.cancel(yourTimer);}
yourTimer = $timeout(function () {
angular.element('.loading-indicator').hide();
}, 50);
}
I can't understand for which reason you use a timer for loading spinner, i recommend use only css if you use for the animation.
Here a little of my code:
HTML
<div ui-view class="fade container-fluid"></div>
<div class="spinner modal-viewer" hidden>
<div class="transparente"></div>
<div class="contenedor">
<div class="center-middle">
<div class="sk-circle">
<div class="sk-circle1 sk-child"></div>
<div class="sk-circle2 sk-child"></div>
...
<div class="sk-circle11 sk-child"></div>
<div class="sk-circle12 sk-child"></div>
</div>
</div>
</div>
</div>
You need manage them out of the uiView, because when you let out of a state, you will lose control of the state controller, then you can't disappear the spinner.
For that, put the spinner out of the uiView element, as above example.
JS
document.querySelector('.spinner')['style'].display = 'none';
My apologies for my poor previous answer.

Categories