Need to click element twice - javascript

I have seen most of the posts about this issue but none seems to work for me. (I am new to React)
Basically I have this js function:
export function toggle() {
"use strict"; // Start of use strict
// Configure tooltips for collapsed side navigation
$('.navbar-sidenav [data-toggle="tooltip"]').tooltip({
template: '<div class="tooltip navbar-sidenav-tooltip" role="tooltip" style="pointer-events:
none;
"><div class="
arrow "></div><div class="
tooltip - inner "></div></div>'
})
// Toggle the side navigation
$("#sidenavToggler").click(function(e) {
e.preventDefault();
$("body").toggleClass("sidenav-toggled");
$(".navbar-sidenav .nav-link-collapse").addClass("collapsed");
$(".navbar-sidenav .sidenav-second-level, .navbar-sidenav .sidenav-third-
level ").removeClass("
show ");
});
// Force the toggled class to be removed when a collapsible nav link is clicked
$(".navbar-sidenav .nav-link-collapse").click(function(e) {
e.preventDefault();
$("body").removeClass("sidenav-toggled");
});
// Prevent the content wrapper from scrolling when the fixed side navigation hovered over
$('body.fixed-nav .navbar-sidenav, body.fixed-nav .sidenav-toggler, body.fixed-nav .navbar-
collapse ').on('
mousewheel DOMMouseScroll ', function (e) {
var e0 = e.originalEvent,
delta = e0.wheelDelta || -e0.detail; this.scrollTop += (delta < 0 ? 1 : -1) * 30; e.preventDefault();
});
})(jQuery); // End of use strict
which is used to make a sidebar smaller. The point is that I need to click twice to make the sidebar smaller. I am doing it like this. Here I receive the function:
const Border = ({ isClicked }) => (
And then calling it from the element:
<a onClick="{isClicked}" className="nav-link text-center" id="sidenavToggler">
<i className="fa fa-fw fa-angle-left"></i>
</a>
This is the class that calls the const:
class CitasPage extends React.Component {
handleToggleCreate = () => {
toggle();
this.setState({});
};
render() {
return (
<div className="content-wrapper">
<Border isClicked={this.handleToggleCreate}></Border>
<Citas />
</div>
);
}
}
export default CitasPage;

Related

Remain at the same vertical coordinate when loading more data in Vue.js

I have a load more button which loads more data to a component. However, after pressing the load button the user is scrolled at the bottom of screen since the load more button is also located at the bottom of the screen.
The user has to scroll up to see the loaded content. Is there any way to make the user to remain at the same vertical coordinate when pressing the button?
One solution if you like to scroll to original position where the Load More button locates:
uses ref to mark the related VNodes (scrolling Container ref=container and the anchor ref=test)
when Load Button is pressed, get current button position
After new content is loaded, call scrollTo method to scroll to the position it got in Step 2 inside nextTick callback
new Vue ({
el:'#app',
data () {
return {
rows: Array.from({length: 100}).map((_, index) => index),
current: 5,
currentCoords: {top: 0, left: 0}
}
},
computed: {
computedRows: function () {
return this.rows.slice(0, this.current)
}
},
methods: {
loadMore: function () {
this.currentCoords.top = this.$refs.test.offsetTop
this.currentCoords.left = this.$refs.test.offsetLeft
this.current += 15
this.$nextTick(() => {
this.$refs.container.scrollTo(this.currentCoords.left, this.currentCoords.top - 10)
})
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<div id="app">
<div class="container">
<div ref="container" style="max-height: 200px;overflow:auto">
<p v-for="(row, index) in computedRows" :key="index">{{row}}</p>
<button ref="test" #click="loadMore()">Load More</button>
</div>
</div>
</div>

Recognizing when sidebar is active or not

I want to use javaScript to recognize when a sidebar is classed "active" or not. I'm using bootstraps' sidebar toggle button, which when clicked, assigns a class of "active" to the sidebar.
<button type="button" id="sidebarCollapse" class="btn btn-info" style="font-family:'Poppins'; position:absolute; z-index:9; margin-left:7vh; margin-top:2vh;font-size: 1.5em">
<span class="glyphicon glyphicon-filter"></span> Filter
</button>
The CSS:
#sidebar {
background: #202020;
color: #fff;
display:inline-block;
}
#sidebar.active {
margin-left: -250px;
}
And, the JS:
//Check to see whether sidebar has class 'active'
var sideBar = document.getElementById('sidebar')
console.log(sideBar.className)
if (sideBar.className == ('active')){
console.log('active')
}
else (console.log('not active'))
To be clear, the active class is only assigned when the sidebarCollapse button is clicked, and the active class is removed when the button is clicked again. The above code doesn't work. It only logs 'not active', even when the sidebar is clearly classed 'active' and is visible. I want it to dynamically read the status of the sidebar (either classed active, or not active).
var sideBar = document.getElementById('sidebar');
console.log(sideBar.className)
if (sideBar.classList.contains('active')){
console.log('active')
}
else (console.log('not active'))
Here's pictures of the HTML, showing the two states of the sidebar (active/not active):
You code should work. There are 2 reasons why your code is always showing 'not active'
Your code is executed on page load
You are fetching the sidebar div before sidebar got opened and the dom object is not updated later.
Move your code to a function and call that function when ever you need to check.
Sample code below.
function isSidebarOpen() {
var sideBar = document.getElementById('sidebar');
//console.log(sideBar.classList)
if (sideBar.classList.contains('active')) {
console.log('active')
} else(console.log('not active'))
}
<div id="sidebar" class="active">
test
<button onclick='isSidebarOpen()'>
Check</button>
</div>
Use MutationObserver.
Add the code below to observe the change:
const targetNode = document.getElementById('sidebarCollapse'); //listen to the sidebar
const config = { attributes: true }; //listen for changes in attributes
const callback = function(mutationsList, observer) {
for(let mutation of mutationsList) {
if (mutation.type === 'attributes') {
if (targetNode.classList.contains('active')){
console.log('active');
}
}
}
};
const observer = new MutationObserver(callback); //construct observer
observer.observe(targetNode, config); //start observing
A working pen here.

Scroll event not working in framework7 - Vue

Am currently using framework7 and I have this problem wherein I need to get a button floating once the user pass scrolling a specific element.
But for some reason am not able to make the scroll event work. Even used a native event listener but still no luck.
Here is my code. In my component:
export default {
methods: {
handleScroll(event) {
alert('should work')
}
},
created() {
window.addEventListener('scroll', this.handleScroll);
},
destroyed() {
window.removeEventListener('scroll', this.handleScroll);
},
mounted() {
window.addEventListener('scroll', this.handleScroll)
this.handleScroll;
var element = document.querySelector(".similar-adventures");
var top = element.offsetTop;
window.scrollTo(0, top);
}
}
And here is my native event listener code:
window.addEventListener(‘scroll’, function(e){
// Get the new Value
newValue = window.pageYOffset;
//Subtract the two and conclude
if(oldValue - newValue < 0){
console.log(“Up”);
} else if(oldValue - newValue > 0){
console.log(“Down”);
}
// Update the old value
oldValue = newValue;
});
I know this is old now but i will answer for future reference, so i think the problem here is that the window is not actually scrolling as framework7 uses pages/views.
In vue the renders to 2 divs like so..
<f7-page>
<div slot="fixed">Fixed element</div>
<p>Page content goes here</p>
</f7-page>
<!-- Renders to: -->
<div class="page">
<div>Fixed element</div>
<div class="page-content">
<p>Page content goes here</p>
</div>
</div>
i found that its the page-content class that you want to put the eventListenter on best way to do this is Dom7 like so...
let page = $$('.page-content')
page.on('scroll', () => {
console.log(page.scrollTop()) // will show page top position
page.scrollTop(0) // will scroll to top
})
//if you have multiple pages
let page = $$('.page-content')
let home = $$(page[0])
let about = $$(page[1])
page.on('scroll', () => {
console.log(home.scrollTop()) //home page top position
console.log(about.scrollTop()) //about page top position
})
//more options
page.scrollTop(position, duration, callback)
page.scrollTo(left, top, duration, callback)
just remember to import $$ from 'Dom7'
This code retrieves all the pages from the f7 component in an array
let pages = document.querySelectorAll('.page-content');
Then to make a page scrollable, select the respective index and do:
pages[0].addEventListener('scroll', function () { console.log('is scrolling...') } );
For the same code but in a more beautiful way as we don't want to specify the page by index:
add an id to your f7-page tag
<f7-page name="whatever" id='myPage'>
then do this code for example in mounted:
let f7page = document.getElementById('myPage');
let scrollableDiv = f7page.querySelector('.page-content');
scrollableDiv.addEventListener('scroll', function () { console.log('is scrolling...') } );
special thanks to BiscuitmanZ's comment for finding the underlying issue

How to conditionally call different classNames in ReactJs styling

I have a progressBar in my React component.The progressBar is as shown below in the image:
So, when I am in the second page, the style be as shown below:
And the next image is for the third page:
So, what I have done is I have created the styling for the second page.
The code looks like this:
<div className={classes.sceProgressBar}>
<div className={classes.sceProgressBarText}>
<i className={ 'fas fa-check ' + this.progressBarStyleHandler} />
</div>
</div>
<hr className={classes.sceProgressBarUnderline} />
<div className={classes.sceProgressBarSecondText}>
<div className={classes.sceProgressBarText}>2</div>
<hr className={classes.sceProgressBarSecondUnderline} />
</div>
<div className={classes.sceProgressBarThirdText}>
<div className={classes.sceProgressBarText}>3</div>
</div>
Now what I want is, I want to make it a common component, so that for each page I don't have to add the style,I can directly import the page and show which page it is by passing the page details in the props.
So, I have added 9 states :
this.state = {
firstPage: false, //white background for Progress Bar
secondPage: false,
thirdPage: false,
firstPageDisplay: false, //green background for Progress Bar
secondPageDisplay: false,
tihrdPageDisplay: false,
firstPageCompleted: false, //tick mark for Progress Bar
secondPageCompleted: true,
thirdPageCompleted: false
};
And, I have added a function where it will check the value of the state which will determine which page it is in.The function looks like this:
progressBarStyleHandler = () => {
let progressbarClassname;
if (this.state.firstPageCompleted) {
progressbarClassname = classes.sceCheckIcon;
}
return progressbarClassname;
}
But for my current page, the function is not working, i.e. its not taking the className. What is wrong with my code?Can anyone please help me with that. Also, if anyone can suggest a better way of doing it, I will follow the same.
You are not actually calling your style handler.
You need to have className={'fas fa-check ' + this.progressBarStyleHandler()} instead of className={'fas fa-check ' + this.progressBarStyleHandler}.
But your approach of managing three booleans per page will not scale well. What if you want to re-use this component and have additional steps? I suggest an approach like below:
function Step({ number, status="NOT_DONE" }) {
switch (status) {
case "DONE":
return <div className="done"><i className="fas fa-check"/></div>
case "CURRENT":
return <div className="active">{number}</div>
case "NOT_DONE":
default:
return <div className="not-done">{number}</div>
}
}
function ProgressBar({ numberOfSteps = 0, currentStep = 0 }) {
if (!numberOfSteps) return null;
const steps = [];
for (let i = 0; i < numberOfSteps; i++) {
const status = i < currentStep ? 'DONE' : i === currentStep ? 'CURRENT' : 'NOT_DONE';
steps.push(<Step number={i} status={status} />)
}
return (
<div>
{steps}
</div>
)
}
And then it can be used like <ProgressBar numberOfSteps={3} currentStep={1}/>

Long magnetic scroll page in Ionic 2

Hey Guys i need your help please,
is started to working on an Ionic 2 App. My Navigation is not that complicated. I have one menu if i click one item another menu opens with a submenu and if i click on an item in the submenu a third page should render above it and this works really fine. Now the third activity should be a very long scrolling site with a lot of section (the sections are on top of each other). And every section should have a toolbar with one back button to go back to the submenu and two arrow keys for the previous or next section.
Here a small picture
now my problems:
how can i achieve the magnetic part? I think it like so: the Bar sits on the top of the page and above the content. When i scroll the content goes underneath and i can scroll to the end. When iam at the end everything should stop and when i pull further the next Section Bar jumps to the top of my site.
I hope you can help me thank you ;)
Plunker Demo
To make this work you need to:
Create a function that scrolls your scroll-content element to the top
Track the scroll position of scroll-content
Use *ngIf on your scroll to top button to conditionally show after scroll-content has reached a certain threshold.
Scroll to top function
I adapted this SO answer to apply to the scroll-content element
scrollToTop(scrollDuration) {
let scrollStep = -this.ionScroll.scrollTop / (scrollDuration / 15);
let scrollInterval = setInterval( () => {
if ( this.ionScroll.scrollTop != 0 ) {
this.ionScroll.scrollTop = this.ionScroll.scrollTop + scrollStep;
} else {
clearInterval(scrollInterval);
}
}, 15);
Track scroll-content position
This example uses the window height as the threshold for showing the scroll to top button like this:
this.ionScroll.addEventListener("scroll", () => {
if (this.ionScroll.scrollTop > window.innerHeight) {
this.showButton = true;
} else {
this.showButton = false;
}
});
Button Html
<button *ngIf="showButton" (click)="scrollToTop(1000)">Scroll Top</button>
Full component Typescript
import { NavController } from 'ionic-angular/index';
import { Component, OnInit, ElementRef } from "#angular/core";
#Component({
templateUrl:"home.html"
})
export class HomePage implements OnInit {
public ionScroll;
public showButton = false;
public contentData = [];
constructor(public myElement: ElementRef) {}
ngOnInit() {
// Ionic scroll element
this.ionScroll = this.myElement.nativeElement.children[1].firstChild;
// On scroll function
this.ionScroll.addEventListener("scroll", () => {
if (this.ionScroll.scrollTop > window.innerHeight) {
this.showButton = true;
} else {
this.showButton = false;
}
});
// Content data
for (let i = 0; i < 301; i++) {
this.contentData.push(i);
}
}
// Scroll to top function
// Adapted from https://stackoverflow.com/a/24559613/5357459
scrollToTop(scrollDuration) {
let scrollStep = -this.ionScroll.scrollTop / (scrollDuration / 15);
let scrollInterval = setInterval( () => {
if ( this.ionScroll.scrollTop != 0 ) {
this.ionScroll.scrollTop = this.ionScroll.scrollTop + scrollStep;
} else {
clearInterval(scrollInterval);
}
}, 15);
}
}
Full component Html
<ion-navbar primary *navbar>
<ion-title>
Ionic 2
</ion-title>
<button *ngIf="showButton" (click)="scrollToTop(1000)">Scroll Top</button>
</ion-navbar>
<ion-content class="has-header" #testElement>
<div padding style="text-align: center;">
<h1>Ionic 2 Test</h1>
<div *ngFor="let item of contentData">
test content-{{item}}
</div>
</div>
</ion-content>

Categories