Pull to refresh not disabling on particular screens (React js) - javascript

Iam trying to do is prevent the default state for forms in react app, in mobile view on default pull to refresh is there,
So if i accidentally do pull to refresh my page(form component) whole form value will be reset. Is there any way to prevent that component from pull to refresh, i tried with onTouchMove method and try to call event.preventDefault(),
but onTouchMove method is not firing, please let me know if there are some others methods to solve this issue, thanks in advance!.
`
class SwipeTest extends React.Component {
constructor(props) {
super(props);
this.state = {
startX: 0,
startY: 0,
currentX: 0,
currentY: 0,
direction: 'none',
threshold: 150,
}
}
touchStart(e) {
alert("i am in touchStart")
}
touchMove(e) {
alert("i am in touchMove")
}
touchEnd(e)
{
alert("i am in touchEnd")
}
render() {
return (
<div
className="w-100 bg-blue db pa4"
onTouchStart={this.touchStart.bind(this)}
onTouchMove={this.touchMove.bind(this)}
onTouchEnd={this.touchEnd.bind(this)}
>
Swipe me (up or down)
</div>
)
}
}
window.onload = () => {
ReactDOM.render(
<SwipeTest />,
document.getElementById("main")
);
};
`

I was curious about your problem so I googled a solution. The one I found basically created a wrapper around your content and with a higher z index capture the pull event and prevent it to reach your browser.
.body,
.wrapper {
/* Break the flow */
position: absolute;
top: 0px;
/* Give them all the available space */
width: 100%;
height: 100%;
/* Remove the margins if any */
margin: 0;
/* Allow them to scroll down the document */
overflow-y: hidden;
}
.body {
/* Sending body at the bottom of the stack */
z-index: 1;
}
.wrapper {
/* Making the wrapper stack above the body */
z-index: 2;
}
<!doctype html>
<html>
<head>
<!-- Put the above styles here -->
</head>
<body class="body">
<div class="wrapper">
<!-- Your content goes here -->
<div id="root" />
</div>
</body>
</html>
Here is the source of the idea: https://w3bits.com/prevent-chrome-pull-to-refresh-css/

Related

How ignore directive event if out side click is in the button? ( Vue 3)

May be somebody can help me.
I have the popup and button, when I click to create button the popup window has to open and when I click outside or on button the popup has to hide
I implement the example in sandbox (unfortunately it works locally but doesn't work in sandbox, I can't understand the reason of problem in sandbox, code base the same, I hope the example will be useful)
I implement directive:
export default {
name: 'click-outside',
mounted: function (el, binding, vnode) {
el.clickOutsideEvent = function (event) {
event.stopPropagation();
if (!(el === event.target || el.contains(event.target))) {
binding.value;
}
};
document.addEventListener('click', el.clickOutsideEvent);
},
unmounted: function (el) {
document.removeEventListener('click', el.clickOutsideEvent);
},
};
simple make up:
<template>
<div class="component">
<button ref="button" #click="isDisplay = true">Create</button>
<div v-if="isDisplay" class="popup-box" v-click-outside="onClose">
Test Popup Box
</div>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data() {
return {
isDisplay: true,
};
},
method: {
onClose() {
this.isDisplay = false;
},
},
};
</script>
<style scoped>
.component {
display: flex;
justify-content: column;
}
.popup-box {
position: absolute;
left: 50%;
top: 50px;
transform: translateX(-50%);
background: #f0f8ff;
border-radius: 1px;
box-shadow: 1px 1px 15px 0 rgba(0, 0, 0, 0.2);
padding: 40px;
color: #555585;
}
</style>
and make global the connection for directive:
import { createApp } from 'vue';
import App from './App.vue';
import ClickOutside from './directives/clickOutside.js';
const app = createApp(App);
app.directive('click-outside', ClickOutside);
app.mount('#app');
in the result Yes it works....
when I am clicking the create button 'isDisplay' set firstly as true (click event) then false (directive) and it is problem which I don't know how to fix, I tried to use ref for button but I don't clearly understand how to ingore the ref attribute in directive ( I didn't find any place where I can check ref and current click with, to understand in which place click event is triggered)
With your code base you need to assign v-click-outside on your component, or on the inner wrapper
<template>
<div class="component" v-click-outside="onClose">
<button ref="button" #click="isDisplay = true">Create</button>
<div v-if="isDisplay" class="popup-box">
Test Popup Box
</div>
</div>
</template>
And in your code you have a misspell in method field. You need to methods instead

Prevent elements behind from the overlay being clicked

The issue
https://streamable.com/e/9z6lev (the flickering in the video is caused by the overlay being reopened every time meal plan is selected)
It "feels" like during the initial overlay open it's not the focused element and as result is's children can be clicked through :sad:
Overlay Template
The logic for the overlay is quite simple, and allow to nest any type of content inside:
<template>
<div class='swipeableWrapper'
#click.stop.prevent // not original code, just attempt to fix the issue
#touch.stop.prevent> // not original code, just attempt to fix the issue
<slot />
</div>
</template>
.swipeableWrapper {
height: 100%;
left: 0;
min-height: 100%;
position: fixed;
top: 0;
width: 100%;
z-index: 100;
}
Items List Template
<template>
<div>
...
<ListProduct v-for='(product, index) in products'
...
:showProduct='showProduct'
:key='index' />
</div>
<template>
// List Item
<template>
<div class='listProduct'
...
#click='showProduct'>
...
</div>
</template>
Intended approaches:
The following logic added to the overlay template to prevent events from bubbling:
#click.stop.prevent
#touch.stop.prevent
Global logic that will listen to opened overlay and add the following CSS class to the body element, in order to allow click on the overlay items, but still not much luck
.overlayOpened {
& * {
pointer-events: none;
touch-action: none;
}
.swipeableWrapper {
&,
& * {
pointer-events: auto;
touch-action: auto;
}
}
}
I am a bit puzzled with this dark magic behaviour and will really appreciate your opinion on the origin of the behaviour and possible solutions :bow:
Try this
#click.self.prevent="function"
Edited:
For the list item and function as prop
:showProduct="() => showProduct(item/index)"

Divs Reverse scroll with translateY() in react.js

I'm trying to create with React.js a type of scroll like this one: http://spassky-fischer.fr/, where two divs are scrolling in inverse directions. They are using transform: translateY(), and I tried to implement it as well but I don't get where I'm wrong here. Here's the architecture of the projet. The current version is also here: http://noiseless-tendency.surge.sh/
App.js:
ComponentDidMount(){
window.addEventListener("scroll", this.scrollHandler);
}
...
scrollHandler = () => {
this.setState({
scrollPositionY: window.scrollY
})
}
...
render() {
return (
<div className="App">
<MainItemsContainer {...this.state} />
</div>
);
}
MainItemsContainer.js:
render() {
let style_first = {
transform: `translateY(${this.props.scrollPositionY})`,
overflow: "hidden"
}
let style_second = {
transform: `translateY(-${this.props.scrollPositionY})`,
overflow: "hidden"
}
return (
<div className="main_items_container">
<section
style={style_first}
className="main_items_container_child">
<ItemsContainer {...this.props}/>
</section>
<section
style={style_second}
className="main_items_container_child">
<ItemsContainer {...this.props}/>
</section>
</div>
);
}
App.css:
.main_items_container {
width: 100vw;
display: flex;
align-items: center;
justify-content: center;
position: fixed;
}
.main_items_container .main_items_container_child{
width: 50%;
height: 100vh;
overflow: scroll;
}
The sample site you linked actually uses the wheel event rather than the scroll event. It looks like they use this library to accomplish it: https://swiperjs.com/demos/ . My understanding is that the scroll event only fires if there's a scrollbar, which is why your event handler didn't fire.
I've created a Code Sandbox that produces the effect you want in React. It does rely on jQuery to compute the height of the whole element, and to set the initial transformation for the left half. However, those are just convenience methods, and if you don't want jQuery as a dependency, you can find workarounds for those pretty easily.
So you could use hooks and pass a custom css var through inline styling on state change to update your translateY. I have not tested but I hope you get my drift.
let elRef = useRef(null)
let[ height, setHeight] = useState()
use useLayoutEffect hook to add the event listener
useLayoutEffect (()=>{
if(!elRef) return
elRef.current.addEventListener("scroll", setHeight(elRef.current.scrollY));
return elRef.current.removeEventListener("scroll", setHeight());
}, )
and put the ref on you outermost div perhaps , so your outer div would look like
<div className='container' ref={elRef} style{{ --height: height}} >
<div className='columOne' > </div>
<div className='columTwo' > </div>
</div>
in your css (I haven't put all that is required but just showing how you custom css var is used
.container{
display: flex;
flex-direction: row
}
And within that equal sized columns
.columnOne{
transform: `translateY(calc(var(--height) * 1px)`,
overflow: "hidden"
}
.columnTwo{
transform: `translateY(-calc(var(--height) * 1px)`,
overflow: "hidden"
}
Does that help. Let me know if I could be more clear. Or use styled components and pass a prop in to achieve the same result.

How to add vanilla JavaScript to vue.js project?

Good Day, I'm very new to Vue.js and want a navbar, which is transparent by default, but changes its background on scrolling. Unfortunately, it does not work. I tried few solutions, but none of this worked. So this JavaScript code is an example from Stack Overflow, which works in a Fiddle. If you need more information and/or code, please let me know.
Navigation.vue
<template>
<div id="navigation">
<nav class="nav-items">
<router-link class="item" to="/home">Home</router-link>
<router-link class="item" to="/about">About</router-link>
<router-link class="item" to="/japan">Japan</router-link>
</nav>
</div>
</template>
<script>
export default {
name: 'navigation'
}
import scroll from '../assets/js/scroll.js';
</script>
scroll.js
const navbar = document.querySelector('#navigation')
window.addEventListener('scroll', function(e) {
const lastPosition = window.scrollY
if (lastPosition > 50 ) {
navbar.classList.add('colored')
} else if (navbar.classList.contains('colored')) {
navbar.classList.remove('colored')
} else {
navbar.classList.remove('colored')
}
})
navigation.scss
FYI: I've removed unneccessary code here.
#navigation {
background: transparent;
.colored {
background: #fff;
transition: 0.3s;
}
}
Note: To view how to import custom code in a Vue component (general case), scroll down past the last <hr>.
Vue is a JavaScript framework and therefore you can insert vanilla code anywhere in it and it will run perfectly fine.
IMHO, you issue is not about importing vanilla code. It's about running it at the correct moment.
You have to run your code inside mounted() hook, because that's when #navigation exists in DOM:
Vue.config.devtools = false;
Vue.config.productionTip = false;
Vue.component('navigation', {
template: '#navigationTemplate',
mounted() {
window.addEventListener('scroll',
() => document.querySelector('#navigation')
.classList.toggle('colored', window.scrollY > 50)
)
}
})
new Vue({
el: '#app'
});
#app {
min-height: 200vh;
background: url("https://picsum.photos/id/237/1024/540") no-repeat center center /cover;
}
#navigation {
background: transparent;
position: fixed;
top: 0;
padding: 1rem;
transition: 0.3s;
width: 100%;
box-sizing: border-box;
color: white;
}
#navigation.colored {
background: rgba(255, 255, 255, .85);
color: black;
}
body {
margin: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script id="navigationTemplate" type="text/template">
<div id="navigation">
<nav class="nav-items">
<a class="item" to="/home">Home</a>
<a class="item" to="/about">About</a>
<a class="item" to="/japan">Japan</a>
</nav>
</div>
</script>
<div id="app">
<navigation />
</div>
your scroll.js can safely be written as:
window.addEventListener('scroll',
() => document.querySelector('#navigation')
.classList.toggle('colored', window.scrollY > 50)
)
Your SCSS seems incorrect:
#navigation {
.colored {
declaration
}
}
will apply declaration to any element with a class of .colored that's inside an element with the id of navigation. But your code toggles the class colored on #navigation. Therefore your SCSS should look like this:
#navigation {
&.colored {
declaration
}
}
Might not seem like much, but the & makes your code apply (or not).
You probably want to apply transition to #navigation, as it should apply when it has the colored class and when it doesn't. If you don't, the return transition (from .colored to :not(.colored)) will not be animated.
For the record and to also answer your initial question, the proper way to import custom code into a Vue component is:
a) export your code as a function:
(in scroll.js)
export function menuScroll = function() {
/* your custom code here */
}
b) import it:
(in your component)
import { menuScroll } from 'path/to/scroll'
c) run it exactly where you need it:
(i.e: in mounted)
export default {
name: 'navigation',
mounted() {
menuScroll();
}
}
Obviously, you want to rename the function in accordance with its purpose/role and the project's naming conventions.
Last, but not least, if your function needs to take params, you might want to use it as a method:
export function someName = function(...args) {
/** do stuff with args **/
}
... and, in component:
import { someName } from 'path/to/it'
export default {
name: 'whatever',
methods: {
someName,
/* more methods... */
}
}
just like that
<template>
.... your HTML
</template>
<script>
export default {
data: () => ({
......data of your component
}),
mounted() {
let recaptchaScript = document.createElement('script')
recaptchaScript.setAttribute('src', 'https://www.google.com/recaptcha/api.js')
document.head.appendChild(recaptchaScript)
},
methods: {
......methods of your component
}
}
</script>
source : Link

Class name reverts to original state after change

I am trying to create a Lightbox-like effect with CSS and Javascript. I'm getting an element by it's id (OverlayContainer) and it will change it's classname to accomodate the dark background for now. I have set up the code in a way that it checks classname value of the element (OverlayContainer) to see whether the classname is set to inactive(normal background) or active (darker). However when i press the submit button to change the state it appears to change classes for a second (screen gets darker for a split second) but then reverts back to original state (OverlayInactive). If anyone has any kind of explanation for this happening please respond.
Here is my CSS code:
.OverlayBoxInactive {
background-color: rgba(0, 0, 0, 0);
position: absolute;
width: 0%;
height: 0%;
top: 0px;
left: 0px;
}
.OverlayBoxActive {
background-color: rgba(0, 0, 0, 0.85);
position: absolute;
width: 100%;
height: 100%;
top: 0px;
left: 0px;
}
and here is my Javascript code:
function ActivateOverlay() {
var overlayBox = document.getElementById("OverlayContainer");
var elementClassName = overlayBox.className;
if (elementClassName == "OverlayBoxInactive") {
overlayBox.setAttribute("class", "OverlayBoxActive");
//alert('Overlay Activated');
} else if (elementClassName == "OverlayBoxActive") {
overlayBox.setAttribute("class", "OverlayBoxInactive");
//alert('Overlay Inactivated');
}
}
Thanks in advance,
-Realitiez
EDIT POST: http://jsfiddle.net/bk5e9t0e/
The default action of an input type="submit" is to post the form's data back to the server, which causes your page to reload. This is why your class is removed.
If you wish to prevent the page reload, you need to prevent the default action. The easiest way to do this is to return false from the onclick handler:
onclick="ActivateOverlay(); return false;"
Your code was not working because:
You were using input type=submit [so you were getting a refresh page kind of feel], which should be type=button or return false; in click handler
You were calling function ActivateOverlay which was defined later than the call itself.
Find your solution here in jsFiddle
<script>
function ActivateOverlay() {
//alert('Overlay Activated');
var overlayBox = document.getElementById("OverlayContainer");
var elementClassName = overlayBox.className;
if (elementClassName == "OverlayBoxInactive") {
overlayBox.setAttribute("class", "OverlayBoxActive");
//alert('Overlay Activated');
} else if (elementClassName == "OverlayBoxActive") {
overlayBox.setAttribute("class", "OverlayBoxInactive");
//alert('Overlay Inactivated');
}
}
</script>
<div id="OverlayContainer" class="OverlayBoxInactive"></div>
<div class="main"></div>
<fieldset>
<form>
<input type="button" onclick="ActivateOverlay();return false" value="Hit Me"></input>
</form>
</fieldset>
<script type="text/javascript" src="index.js"></script>
http://jsfiddle.net/4queag8m/
You need to add an preventDefault() in your function. it's reloading the page.
First add the element to your call:
onclick="ActivateOverlay(this)"
and then add the parameter with the prevent to your function - like this"
function ActivateOverlay(evt) {
evt.preventDefault()
...
}

Categories

Resources