How to access ReactJS DOM elements using JQuery - javascript

I am trying to get the height of the header element using Jquery's height() method. But it gives NAN when I console the values
Here's my react snippet
import React, { Component } from "react";
import $ from 'jquery'; //un-used
export default class HomepageNavigationBar extends Component {
render() {
return (
<header className="header_area">
<div className="main_menu">
<nav className="navbar navbar-expand-lg navbar-light">
<div className="container">
<a className="navbar-brand logo_h" href="index.html">
<img src="img/logo.png" alt="" />
</a>
<button
className="navbar-toggler"
type="button"
data-toggle="collapse"
data-target="#navbarSupportedContent"
aria-controls="navbarSupportedContent"
aria-expanded="false"
aria-label="Toggle navigation"
>
<span className="icon-bar" /> <span className="icon-bar" />
<span className="icon-bar" />
</button>
.
.
.
//dots used to denote that code further exists but to make this minimal I have removed them.
</div>
</header>
);
}
}
and here's my external theme.js file
(function($) {
"use strict";
var nav_offset_top = $("header").height() + 50;
console.log(nav_offset_top); //gives 'NAN' when console, even after I scroll
function navbarFixed() {
if ($(".header_area").length) {
$(window).scroll(function() {
var scroll = $(window).scrollTop();
if (scroll >= nav_offset_top) {
alert('Hi');
$(".header_area").addClass("navbar_fixed");
} else {
alert('no Hi');
$(".header_area").removeClass("navbar_fixed");
}
});
}
}
navbarFixed();
})(jQuery);
Problems are:
1)
console.log(nav_offset_top);
this above code gives NAN when console the value even after I scroll the page up and down
2)
$(".header_area").length
header_area length is always 0 even after I scroll up and down the page
Can someone here help me out?

I believe you're getting NaN because you're accessing header when it is not yet rendered.
Put your code in componentDidMount() instead to make sure that elements are rendered before accessing it.
Read more: https://reactjs.org/docs/react-component.html#componentdidmount
The docs state that:
Initialization that requires DOM nodes should go here.
This is exactly what you're doing, accessing DOM nodes using jQuery.
class HomepageNavigationBar extends React.Component {
componentDidMount() {
var nav_offset_top = $("header").height() + 50;
console.log(nav_offset_top);
function navbarFixed() {
if ($(".header_area").length) {
$(window).scroll(function() {
var scroll = $(window).scrollTop();
if (scroll >= nav_offset_top) {
alert('Hi');
$(".header_area").addClass("navbar_fixed");
} else {
alert('no Hi');
$(".header_area").removeClass("navbar_fixed");
}
});
}
}
navbarFixed();
}
render() {
return (
<header className="header_area">
<div className="main_menu">
<nav className="navbar navbar-expand-lg navbar-light">
<div className="container">
<a className="navbar-brand logo_h" href="index.html">
<img src="img/logo.png" alt="" />
</a>
<button
className="navbar-toggler"
type="button"
data-toggle="collapse"
data-target="#navbarSupportedContent"
aria-controls="navbarSupportedContent"
aria-expanded="false"
aria-label="Toggle navigation"
>
<span className="icon-bar" /> <span className="icon-bar" />
<span className="icon-bar" />
</button>
</div>
</nav>
</div>
</header>
);
}
}
ReactDOM.render(<HomepageNavigationBar />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root" style="height: 1000px;"></div>

Related

Invalid hook cal

I am using Gatsby with the CSS framework Bulma, In order for the Mobile navbar to work, you have to add an event listener for a button that only becomes available when to screens size is a certain dimension. in previous versions of Gatsby, it worked fine, only in the recent week have I been running to problems. Now I get an Invalid hook call
import { Link } from 'gatsby'
let Header = () => {
useEffect(() => {
let burger = document.getElementById(`burger`);
let menu = document.getElementById(`navMenu`)
burger.addEventListener(`click`, function () {
burger.classList.toggle(`is-active`);
menu.classList.toggle(`is-active`)
})
});
return (
<>
<nav className="navbar is-fixed-top" id="navbar">
<div className="navbar-brand">
<Link to="/">
<p className="navbar-item">CMJR DEVELOPMENT</p>
</Link>
<a role="button" id="burger" className="navbar-burger burger" aria-label="menu" aria-expanded="false" data-target="navbarBasicExample">
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
</a>
</div>
<div className="navbar-menu" id="navMenu">
<div className="navbar-end">
<Link to={"/service"} className="navbar-item ">Services</Link>
<Link to={"/portfolio"} className="navbar-item ">Portfolio</Link>
<Link to={"/contact"} className="navbar-item ">Contact</Link>
</div>
</div>
</nav>
</>
)
}
export default Header;
I know I'm doing something wrong, just not what.

javascript runs a method from other module too early

I'm trying to make a site that loads pages dynamically by injecting html elements with Javascript. I had it work correctly when I had all the code in one file. Now I'm learning to code in modules using webpack, but I have a problem.
So as you can see, html file only has a navigation. By clicking on the menu javascript will inject template to the wed-spa div.
Problem is that when Home is loaded on window.load javascript also runs a method setPosition from TriCouple, which is supposed to style the html template elements that are injected from Couple.js, which is of course non existent at the moment of window.load.
To clear up the explanation, the proper behavior would be:
1. window loads up and injects Home template immediately,
2. when clicking on "Couple" from navigation it should inject Couple template,
3. the styling for Couple template should be applied via methods from TriCouple.js.
Problem:
javascript is trying to do number 3 while being in number 1 where Couple elements don't appear.
HTML:
<!doctype html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no, maximum-scale=1, shrink-to-fit=no">
<link href="https://fonts.googleapis.com/css?family=Lato:400,900|Roboto:400,900|Tangerine&subset=latin-ext" rel="stylesheet">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.2/css/bootstrap.min.css" integrity="sha384-PsH8R72JQ3SOdhVi3uxftmaW6Vc51MKb0q5P2rRUpPvrszuE4W1povHYgTpBfshb" crossorigin="anonymous">
<!-- Custom CSS -->
<link rel="stylesheet" type="text/css" href="./assets/styles/css/style.css">
<title>
Wedding template
</title>
</head>
<body>
<div class="container-fluid wed-home">
<nav class="wed-nav navbar navbar-expand-lg navbar-light bg-light">
<a class="navbar-brand" href="#">John and John</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNavAltMarkup" aria-controls="navbarNavAltMarkup" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNavAltMarkup">
<div class="navbar-nav">
<a class="nav-item nav-link active" id="home">Home <span class="sr-only">(current)</span></a>
<a class="nav-item nav-link" id="couple">Couple</a>
<a class="nav-item nav-link" id="bridesmaid">Bridesmaid</a>
<a class="nav-item nav-link" id="groomsmen">Groomsmen</a>
<a class="nav-item nav-link" id="events">Events</a>
<a class="nav-item nav-link" id="story">Story</a>
<a class="nav-item nav-link" id="rsvp">RSVP</a>
</div>
</div>
</nav>
<div class="wed-spa"></div>
</div>
<script src="./temp/scripts/bundle.js"></script>
</body>
</html>
my main app.js:
import Home from './modules/Home';
import Couple from './modules/Couple';
import TriCouple from './modules/TriCouple';
var home = new Home();
window.addEventListener("load", function() {
var loader = new Home;
loader.loadHome();
})
var couple = new Couple();
var triCouple = new TriCouple();
Home.js
class Home {
constructor() {
this.template = `
<div class="wed-heading row">
<div class="wed-heading-wrapper col">
<h1>Angelo & Klaudia
<br>
<span class="std">Save the date</span>
<span class="wed-date">22.08.2015</span>
</h1>
</div>
</div>
`;
this.homeMenu = document.querySelector("#home");
this.spa = document.querySelector(".wed-spa");
this.homeSection = document.querySelector(".wed-home");
this.homeClick();
};
homeClick() {
var that = this;
this.homeMenu.addEventListener("click", function(){
that.loadHome();
})
};
loadHome() {
this.homeSection.classList.add('wed-front');
this.loadTemplate();
};
loadTemplate() {
this.spa.innerHTML = this.template;
}
}
export default Home;
Couple.js
class Couple {
constructor() {
//Start of HTML Template
this.template = `
<div class="message-popup"></div>
<div class="wed-couple container">
<div class="wed-couple-newlyweds wed-couple-bride">
<div class="wed-couple-newlyweds-img wed-couple-bride-img">
<div class="wed-couple-name-row row">
<div class="wed-couple-desc wed-couple-name wed-couple-name-bride col-md-auto">
<h1>Klaudia Kim</h1>
</div>
<div class="wed-couple-desc wed-couple-position wed-couple-position-bride col-md-auto">
<span>The Bride</span>
</div>
</div>
<div class="wed-couple-newlyweds-message wed-couple-newlyweds-message-bride">
<span>Message from the Bride</span>
</div>
</div>
</div>
<div class="wed-couple-newlyweds wed-couple-groom">
<div class="wed-couple-newlyweds-img wed-couple-groom-img">
<div class="wed-couple-name-row row">
<div class="wed-couple-desc wed-couple-name wed-couple-name-groom col-md-auto">
<h1>Angelo Kim</h1>
</div>
<div class="wed-couple-desc wed-couple-position wed-couple-position-groom col-md-auto">
<span>The Groom</span>
</div>
</div>
<div class="wed-couple-newlyweds-message wed-couple-newlyweds-message-groom">
<span>Message from the Groom</span>
</div>
</div>
</div>
</div>
`;
// End of HTML Template
//DOM declaration
this.spa = document.querySelector(".wed-spa");
this.coupleButton = document.querySelector('#couple');
this.homeSection = document.querySelector(".wed-home");
//initialize methods
this.loadCouple();
};
// End Constructor
// Start methods
loadCouple() {
var _this = this;
this.coupleButton.addEventListener("click", function() {
_this.homeSection.classList.remove('wed-front');
_this.spa.innerHTML = _this.template;
});
};
}
export default Couple;
Tricouple.js
class TriCouple {
constructor() {
this.wedCouple = document.querySelector('.wed-couple');
this.coupleButton = document.querySelector('#couple');
this.wedCoupleBride = document.querySelector(".wed-couple-bride");
this.wedCoupleBrideImg = document.querySelector(".wed-couple-bride-img");
this.wedCoupleGroom = document.querySelector(".wed-couple-groom");
this.wedCoupleGroomImg = document.querySelector(".wed-couple-groom-img");
this.wedCoupleNewlyweds = document.querySelectorAll(".wed-couple-newlyweds");
// Detect initial Viewport
this.initialWindowWidth = window.innerWidth;
this.initialWindowHeight = window.innerHeight;
this.diagonal = Math.sqrt(Math.pow(this.initialWindowWidth, 2) + Math.pow(this.initialWindowHeight, 2));
// Calculate sinus
this.sineX = this.initialWindowWidth / this.diagonal
// Calculate angle for rotation
this.sinDegree = Math.asin(this.sineX) * (180 / Math.PI);
//Initiate methods
this.setHeight();
this.setPosition();
};
//SET HEIGHT
setHeight() {
this.wedCoupleNewlyweds.forEach((partner) => {
console.log('log for each partner');
partner.style.height = this.diagonal + 'px';
})
};
//POSITION TO LEFT & RIGHT
setPosition(callback, obj){
this.wedCoupleBride.style.left = -this.initialWindowWidth + 'px';
this.wedCoupleBrideImg.style.left = this.initialWindowWidth + 'px';
this.wedCoupleGroom.style.right = -this.initialWindowWidth + 'px';
this.wedCoupleGroomImg.style.right = this.initialWindowWidth + 'px';
callback.call(obj, null);
}
}
export default TriCouple;

Why localstorage is not working firefox 57 and Vuejs2?

I want to change the language by click in the language name , i am using vuex-i18n for set the language in the front end. and i am using localStorage but the localStorage is not working in firefox , i am testing in Firefox 57 , i test in Chrome and Edge and is working there but not in firefox.(I already check in the config and dom.storage.enabled is true)
My component code is :
<template>
<nav class="navbar navbar-inverse navbar-fixed-top" role="navigation">
<div class="container-fluid">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" id="menu-toggle" #click ="OpenMenu(menuclicked)"><span class="glyphicon glyphicon-list" aria-hidden="true"></span></a>
</div>
<div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav navbar-right">
<li><a href="" #click="setLanguage('en')" >English</a></li>
<li> Spanish</li>
<li v-for ="item in topNavbarOptions"><router-link v-on:click.native="item.clickEvent" :to="{name:item.route}"><span :class="item.icon"></span> {{ item.name}}</router-link></li>
</ul>
</div>
</div>
</nav>
</template>
<script>
import 'vue-awesome/icons';
import {HTTP} from '../common/http-common';
export default {
props:['topNavbarOptions'],
data: function () {
return {
menuclicked: false
}
},
created:function(){
this.$i18n.set(localStorage.getItem("locale"));
},
methods: {
OpenMenu: function (menuclicked) {
this.menuclicked = !menuclicked;
this.$emit('openmenu', this.menuclicked );
},
setLanguage:function(locale)
{
HTTP.get('lang/'+locale)
.then(response =>{
//Set locale from backend
localStorage.setItem("locale", locale);
})
.catch(error=>{
console.log(error);
});
}
}
}
</script>
i am usign axios in my HTTP call.There is a way to set the language without using localstorage or sessionstorage?. what i have to change in my code to make compatible with Firefox?.
Thank you.
Did you try window.localStorage? This should be context- and scope-unreliant.
try to
delete the local storage for this site in settings. URL=about:preferences#privacy
close FF
restart FF
it worked in my case - I had updated to version 57 - somehow my profile got corrupted
in Windows the FF profile is located at:
C:\Users[youraccountname]\AppData\Local\Mozilla\Firefox\Profiles\
I had to change my code to solve the problem . The problem is when the LocalStorage is inside of an axios http response (setLanguage method) It works in Chrome but in firefox LocalStorage is empty. when i move the LocalStorage outside the response it works.
<script>
import 'vue-awesome/icons';
import {HTTP} from '../common/http-common';
export default {
props:['topNavbarOptions'],
data: function () {
return {
menuclicked: false,
locale:'en'
}
},
mounted:function(){
if(localStorage.getItem("locale"))
{
this.locale = localStorage.getItem("locale");
}
this.$i18n.set(this.locale);
},
methods: {
OpenMenu: function (menuclicked) {
this.menuclicked = !menuclicked;
this.$emit('openmenu', this.menuclicked );
},
setLanguage:function(localecode)
{
//Set front end locale
localStorage.setItem("locale",localecode);
//Set backend locale
HTTP.get('lang/'+localecode)
.then(response =>{
})
.catch(error=>{
console.log(error);
});
}
}
}
</script>
Try this:
browser.storage.local.get() - to retrive data
browser.storage.local.set() - to post data

Changing state of component with OnClick in React

I am trying to change state of the component and render it to page.
var navbarValue = [{"Category":"Home","Status":1},{"Category":"About","Status":0},{"Category":"Contact","Status":0}];
class NavbarList extends React.Component {
constructor() {
super();
this.onClick = this.handleClick.bind(this);
}
handleClick(event) {
const {id} = event.target;
console.log(id);
if(!navbarValue[id].Status){
{navbarValue.map((obj, index) =>{
if(navbarValue[index].Status){
navbarValue[index].Status = 0;
return <li key={index}><a id={index} onClick={this.onClick}>{obj.Category} </a></li>
}
})}
navbarValue[id].Status = 1;
return <li className="active" key={id}><a id={id} onClick={this.onClick}>{navbarValue[id].Category}</a></li>
}
}
render() {
return (
<div className="navbar-wrapper">
<div className="container">
<nav className="navbar navbar-fixed-static-top navbar-inverse">
<div className="container">
<div className="navbar-header">
<button type="button" className="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
<span className="sr-only">Toggle navigation</span>
<span className="icon-bar"></span>
<span className="icon-bar"></span>
<span className="icon-bar"></span>
</button>
<a className="navbar-brand" href="#">BrandName</a>
</div>
<div id="navbar" className="collapse navbar-collapse">
<ul className="nav navbar-nav">
{navbarValue.map((obj, index) => {
if (obj.Status)
return <li className="active" key={index}><a id={index} onClick={this.onClick}>{obj.Category}</a></li>
return <li key={index}><a id={index} onClick={this.onClick}>{obj.Category} </a></li>
})}
</ul>
</div>
</div>
</nav>
</div>
</div>
)};
};
ReactDOM.render(
<NavbarList />,
document.getElementById('root')
);
<script src="https://netdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js"></script>
<link href="https://netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
I have an if statement in handleClick(event) which validates if function has to be run and rerender elements.
First it checks if button which is already active is not being clicked. Next if statment is in loop to find previous active element, change objects property to 0 and render to not active.
At the end render new active element to active and set objects property to 1.
Put navbarValue in a state object and update the state onClick. You don't need if/else statements here. Because your components will be rerendered on state update.
Like this: https://stackoverflow.com/a/45134876/4953199

Fix behavior of collapse/expand blocks

I use bootstrap 4 alpha 6 version. I have several blocks in my page. I want expand/collapse these blocks by clicking main button (id='expand-collapse'). Also every button has there own individual buttons which would open/close concrete block. Right know I use next js code and have strange behavior.
For example: I open first block by clicking first button, then I click main button (id='expand-collapse') to open other blocks. But in fact first block closed and other blocks opened. How to fix this problem?
HTML:
<div class="card">
<div class="card-header">
<button id='expand-collapse' type="button" data-parent="#blocks" data-toggle="collapse" data-target=".block" aria-expanded="false" aria-controls=".block">
</button>
</div>
<div class="card-block">
<div id="blocks">
<div class="list-group">
<div class="list-group-item">
<a data-toggle="collapse" href="#block-1" aria-expanded="false" aria-controls="block-1">OPEN/CLOSE FIRST</a>
<div class="collapse block" id="block-1">
FIRST BLOCK BLOCK-->
</div>
</div>
<div class="list-group-item">
<a data-toggle="collapse" href="#block-2" aria-expanded="false" aria-controls="block-2">OPEN/CLOSE SECOND</a>
<div class="collapse block" id="block-2">
SECOND BLOCK
</div>
</div>
<div class="list-group-item">
<a data-toggle="collapse" href="#block-3" aria-expanded="false" aria-controls="block-3">OPEN/CLOSE THIRD</a>
<div class="collapse block" id="block-3">
THIRD BLOCK
</div>
</div>
</div>
</div>
</div>
</div>
JAVASCRIPT:
$(function() {
$('#expand-collapse').on('click', function() {
var target = $(this).attr('data-target');
$(target).each(function() {
if ($(this).hasClass('show')) {
$(this).collapse('hide');
} else {
$(this).collapse('show');
}
});
});
});
That kind of behaviour is due to data-toggle attribute. Take that off from the main button and change the script to this-
HTML
<button id='expand-collapse' type="button" data-parent="#blocks" data-target=".block" aria-expanded="false" aria-controls=".block">
</button>
JQUERY:
$(function() {
var showAll = false;
$('#expand-collapse').on('click', function() {
var target = $(this).attr('data-target');
//console.log('showAll=' + showAll);
$(target).each(function() {
if(showAll === false) {
$(this).collapse('show');
}
else {
$(this).collapse('hide');
}
});
if(showAll === false) {
showAll = true;
}
else {
showAll = false;
}
//console.log('showAll=' + showAll);
});
});

Categories