getChildRoutes block parent rendering - react-router

I've tried using setTimout ( 10 sec ) in getChildRoutes to simulate low latency network. let say www.example.com/user, I got server side rendering on "/user" path. when I access /user, I got blank page instead of the page from server side rendering, then after 10 sec, I get my page rendering.
var routes = [{
path: '/',
component: App,
indexRoute: { component: DashBoardPage },
getChildRoutes(location, cb) {
if (typeof window !== 'undefined') {
console.log("set sleep");
setTimeout(function () {
var test = [{path: 'about', component: DashBoardPage},
{path: 'feed', component: FeedChannelPage},
{path: 'host', component: HostPage},
{path: 'user', component: UserPage}];
console.log("location is " + location);
cb(null, test);
}, 10000);
}else{
var test = [{path: 'about', component: DashBoardPage},
{path: 'feed', component: FeedChannelPage},
{path: 'host', component: HostPage},
{path: 'user', component: UserPage}];
console.log("location is " + location);
cb(null, test);
}
}
}]
export default routes;
This my App.jsx
class App extends React.Component {
render () {
return (
<div id="wrapper">
<nav className="navbar navbar-default navbar-static-top" role="navigation" style={{marginBottom: 0}}>
<div className="navbar-header">
<a className="navbar-brand" href="index.html">SB Admin v2.0</a>
</div>
<div className="navbar-default sidebar" role="navigation">
<div className="sidebar-nav navbar-collapse">
<ul className="nav" id="side-menu">
<li className="sidebar-search">
<div className="input-group custom-search-form">
</div>
</li>
<li>
<Link to="/about"><i className="fa fa-dashboard fa-fw"></i> Dashboard</Link>
</li>
<li>
<Link to="/host"><i className="fa fa-dashboard fa-fw"></i> Host</Link>
</li>
<li>
<Link to="/user"><i className="fa fa-dashboard fa-fw"></i> User</Link>
</li>
</ul>
</div>
</div>
</nav>
<div id="page-wrapper" style={{'minHeight':'400px'}}>
{this.props.children}
</div>
</div>
)
}
}

Related

Logo does not change on scrolling using React

Summary:
I have this logo in my website header, I want this logo (image [1]) to change to another one (image [2]) on scrolling down, and to change back to the original logo (image [1]) when I scroll back to the top.
What i tried:
I tried to make it with EventListener and useEffect in the header page, but I'm getting this error below:
ERROR in src\layouts\Navbar\index.jsx
Line 12:3: 'listenScrollEvent' is not defined no-undef
My code:
import React, { useState } from 'react'
import { useEffect } from "react";
export default () => {
useState = {
imageSrc: '',
imageAlt: ''
}
listenScrollEvent = e => {
if (window.scrollY > 400) {
this.setState({
imageSrc: './/img/Smartlogger_logo.png',
imageAlt: 'smartlogger white logo'
})
} else {
this.setState({
imageSrc: './../../views/Home/image/smartLoggerheader_logo.png',
imageAlt: 'smartlogger colored logo'
})
}
}
useEffect(() => {
window.addEventListener('scroll', this.listenScrollEvent)
}, []);
return (
<header className='header-area header-sticky'>
<div className='container'>
<div className='row'>
<div className='col-12'>
<nav className='main-nav'>
{/* ***** Logo Start ***** */}
<a href='/#' className='logo'>
<style>{css}</style>
<img
src={this.setState}
alt='Smartlogger logo'
/>
</a>
{/* ***** Logo End ***** */}
</nav>
</div>
</div>
</div>
</header>
)
}
You need to make the following changes in your code. It should fix the issue.
Inside render() - img src replace src={this.setState} with src={this.state.imageSrc}
Inside listenScrollEvent function replace window.scrollY with event.srcElement.body.scrollY
it will look like this (I have used random images here):
listenScrollEvent = event => {
if (event.srcElement.body.scrollY > 400) {
this.setState({
imageSrc: 'https://c.tenor.com/57w9du3NrV0AAAAS/css-html.gif',
imageAlt: 'smartlogger white logo'
})
} else {
this.setState({
imageSrc: 'https://c.tenor.com/57w9du3NrV0AAAAS/css-html.gif',
imageAlt: 'smartlogger colored logo'
})
}
}
Full working code : (I have added style={{height:'200vh'}} on container div just to test it on my local. You can remove it)
import React from 'react'
import { Link } from 'react-router-dom'
export default class App extends React.Component {
state = {
imageSrc: 'https://c.tenor.com/TReUojNlZ6wAAAAi/js-javascript.gif',
imageAlt: ''
}
listenScrollEvent = event => {
if (event.srcElement.body.scrollY > 400) {
this.setState({
imageSrc: 'https://c.tenor.com/57w9du3NrV0AAAAS/css-html.gif',
imageAlt: 'smartlogger white logo'
})
} else {
this.setState({
imageSrc: 'https://c.tenor.com/57w9du3NrV0AAAAS/css-html.gif',
imageAlt: 'smartlogger colored logo'
})
}
}
componentDidMount() {
window.addEventListener('scroll', this.listenScrollEvent)
}
render() {
return (
<header className='header-area header-sticky'>
<div className='container' style={{height:"200vh"}}>
<div className='row'>
<div className='col-12'>
<nav className='main-nav'>
{/* ***** Logo Start ***** */}
<a href='/#' className='logo'>
{/* <style>{css}</style> */}
<img
src={this.state.imageSrc}
alt='Smartlogger logo'
/>
</a>
{/* ***** Logo End ***** */}
</nav>
</div>
</div>
</div>
</header>
)
}
}
Hope that's how you wanted it to work. Try running it on your local and then you can modify it as per your requiremnets.
In your useState hook you want to have your src and your alt.
Remember useState return an array of 2 elements, the first is the value and the second is the setter for that value.
You can use the setter in your listenScrollEvent function and you can use the value in your jsx.
You are also using a css variable in you jsx that isn't defined anywhere.
It should look something like this:
import React, { useState, useEffect } from "react";
export default () => {
const [image, setImage] = useState({
src: "",
alt: "",
});
const listenScrollEvent = (e) => {
if (window.scrollY > 400) {
setImage({
src: "../img/Smartlogger_white_logo.png",
alt: "smartlogger white logo",
});
} else {
setImage({
src: "../img/Smartlogger_colored_logo.png",
alt: "smartlogger colored logo",
});
}
};
useEffect(() => {
window.addEventListener("scroll", listenScrollEvent);
}, []);
return (
<header className="header-area header-sticky">
<div className="container">
<div className="row">
<div className="col-12">
<nav className="main-nav">
{/* ***** Logo Start ***** */}
<a href="/#" className="logo">
<style>{css}</style>
<img src={require(image.src)} alt={image.alt} />
</a>
{/* ***** Logo End ***** */}
</nav>
</div>
</div>
</div>
</header>
);
};
An alternative solution that looks a little cleaner to me:
import React, { useState, useEffect } from "react";
import whiteLogo from "../img/Smartlogger_white_logo.png";
import coloredLogo from "../img/Smartlogger_colored_logo.png";
export default () => {
const [isScrolled, setIsScrolled] = useState(false);
const listenScrollEvent = (e) => setIsScrolled(window.scrollY > 400);
useEffect(() => {
window.addEventListener("scroll", listenScrollEvent);
}, []);
return (
<header className="header-area header-sticky">
<div className="container">
<div className="row">
<div className="col-12">
<nav className="main-nav">
{/* ***** Logo Start ***** */}
<a href="/#" className="logo">
<style>{css}</style>
<img
src={isScrolled ? whiteLogo : coloredLogo}
alt={
isScrolled
? "SmartLogger white logo"
: "SmartLogger colored logo"
}
/>
</a>
{/* ***** Logo End ***** */}
</nav>
</div>
</div>
</div>
</header>
);
};
EDIT: added note about css variable, fixed typo in code and formatted better
EDIT2: fixed image link and added the require in the img src attribute, this should fix the image loading
EDIT3: added alternative solution

How to style an a element that redirects to react component?

App.js:
import './App.css';
import logo from './images/logo.png';
import Home from './components/Home';
import About from './components/About';
import Calculators from './components/Calculators';
import Classes from './components/Classes';
import Riddles from './components/Riddles';
import { useRoutes, BrowserRouter as Router } from 'react-router-dom';
const MenuBar = () => {
return (
<header className='App-header'>
<div className="container">
<a id="home" className="content-tab" href="/"> Home</a>
<a id="about" className="content-tab" href="/about"> About</a>
<a id="calcs" className="content-tab" href="/calculators"> Calculators</a>
<a id="riddles" className="content-tab" href="/riddles">Riddles</a>
<a id="classes" className="content-tab" href="/classes">Classes</a>
</div>
</header>
)
}
const App = () => {
let routes = useRoutes([
{ path: "/", element: <Home /> },
{ path: "about", element: <About /> },
{ path: "classes", element: <Classes />},
{ path: "calculators", element: <Calculators />},
{ path: "riddles", element: <Riddles /> },
// ...
]);
return routes;
};
function AppWrapper() {
return (
<div className="App">
<MenuBar />
<Router>
<App />
</Router>
</div>
);
}
export default AppWrapper;
Now, I want to make that whenever you select a page, like home, about, calculators, etc; it marks the link using border-bottom: 1px solid white;, but when using
.container a.active {
border-bottom: 1px solid white;
}
It just doesn't work.
Any ideas why?
Can it be because it's redirecting to a different url?
If so, then should I also import app.css into my Home, About, etc components?
You should be using Link, or NavLink if you want to apply active styling, instead of the raw anchor <a /> tag. Use the function callback for the className prop which is passed an isActive prop.
NavLink
import { NavLink } from 'react-router-dom';
const MenuBar = () => {
const getLinkClassNames = ({ isActive }) => [
"content-tab",
isActive ? "active-tab" : null,
]
.filter(Boolean)
.join(" ");
return (
<header className='App-header'>
<div className="container">
<NavLink
id="home"
className={getLinkClassNames}
to="/"
>
Home
</NavLink>
<NavLink
id="about"
className={getLinkClassNames}
to="/about"
>
About
</NavLink>
<NavLink
id="calcs"
className={getLinkClassNames}
to="/calculators"
>
Calculators
</NavLink>
<NavLink
id="riddles"
className={getLinkClassNames}
to="/riddles"
>
Riddles
</NavLink>
<NavLink
id="classes"
className={getLinkClassNames}
to="/classes"
>
Classes
</NavLink>
</div>
</header>
);
}
CSS
.active-tab {
border-bottom: 1px solid white;
}
If you prefer the v5 syntax then create a custom NavLink component.
import { NavLink as BaseNavLink } from "react-router-dom";
const NavLink = React.forwardRef(
({ activeClassName, activeStyle, ...props }, ref) => {
return (
<BaseNavLink
ref={ref}
{...props}
className={({ isActive }) =>
[
props.className,
isActive ? activeClassName : null
]
.filter(Boolean)
.join(" ")
}
style={({ isActive }) => ({
...props.style,
...(isActive ? activeStyle : null)
})}
/>
);
}
);
Usage:
<NavLink
id="home"
className="content-tab"
activeClassName="active-tab"
to="/"
>
Home
</NavLink>

Show/Hide Submenu by click

I have this part of my code in sidebar.component.html :
<ul class="nav">
<li routerLinkActive="active" *ngFor="let menuItem of menuItems" class="{{menuItem.class}} nav-item">
<a class="nav-link" [routerLink]="[menuItem.path]">
<i class="material-icons">{{menuItem.icon}}</i>
<p>{{menuItem.title}}</p>
</a>
<ng-container *ngIf="menuItem.children && menuItem.children.length > 0">
<ul class="nav">
<li routerLinkActive="active" *ngFor="let childmenu of menuItem.children"
class="{{menuItem.class}}">
<a class="nav-link" [routerLink]="[childmenu.path]">
<p>{{childmenu.title}}</p>
</a>
</li>
</ul>
</ng-container>
</li>
</ul>
and this is my code in sidebar.component.css :
export const ROUTES: RouteInfo[] = [
{ path: '/dashboard', title: 'dashbord', icon: 'dashboard', class: '', children: '' },
{
path: '/user-List', title: 'Parent', icon: 'apps', class: '', children: [
{ path: '#', title: 'Child Menu 1', icon: 'dashboard', class: '' },
{ path: '#', title: 'Child Menu 2', icon: 'add_shopping_cart', class: '' },
{ path: '#', title: 'Child Menu 3', icon: 'sports_soccer', class: '' },
]
}
];
can you help me please to show/hide submenu by click ?
In your parent component ts file create a property to store the submenu state:
showSubMenu: boolean = false;
In you parent template give your sub-menu an *ngIf and a button to toggle it:
<button (click)="showSubMenu = !showSubMenu">Toggle Sub Menu</button>
<sub-menu *ngIf="showSubMenu"></sub-menu>

Angular 4 switch with different components

I'm trying to make my menu load according to the click on the "Cadastros" action but I believe the problem is the "workspaceSelected" property that is not visible to all components.
I believe the correct location for this case would be the property "workspaceSelected" being in the component sidenav, but I do not know how to handle this type of situation.
I would like to click on the action "Cadastros" and she make the switch to load the correct html component.
principal component class:
export class PrincipalComponent implements OnInit {
workspaceSelecionada: string;
constructor() { }
ngOnInit() {
}
}
Principal component:
<header>
<app-navbar></app-navbar>
<app-sidenav></app-sidenav>
</header>
<div class="container" [ngSwitch]="workspaceSelecionada">
<app-cadastros *ngSwitchCase="'cadastros'"></app-cadastros>
<app-movimentacoes *ngSwitchCase="'movimentacoes'"></app-movimentacoes>
<app-administracao *ngSwitchCase="'administracao'"></app-administracao>
<app-relatorios *ngSwitchCase="'relatorios'"></app-relatorios>
<app-configuracoes *ngSwitchCase="'configuracoes'"></app-configuracoes>
<app-dashboard *ngSwitchDefault></app-dashboard>
</div>
app-sidenav:
<!--SideNav-->
<ul id="slide-out" class="side-nav grey darken-2">
<li>
<div class="userView">
<div class="background">
<img src="images/office.jpg">
</div>
<img class="circle" src="images/yuna.jpg">
<span class="white-text name">John Doe</span>
<span class="white-text email">jdandturk#gmail.com</span>
</div>
</li>
<li>
<a (click)="workspaceSelecionada = 'cadastros'" class="btn-large waves-effect waves-light indigo darken-3">CADASTROS</a>
</li>
<li>
<a class="btn-large waves-effect waves-light purple darken-3">MOVIMENTAÇÕES</a>
</li>
<li>
<a class="btn-large waves-effect waves-light orange darken-3">ADMINISTRAÇÃO</a>
</li>
<li>
<a class="btn-large waves-effect waves-light yellow darken-3">RELATÓRIOS</a>
</li>
<li>
<a class="btn-large waves-effect waves-light light-green darken-3">CONFIGURAÇÕES</a>
</li>
</ul>
<a data-activates="slide-out" class="button-collapse"><i class="material-icons">menu</i></a>
As suggested above in the comment, define a routing module for the application:
import { NgModule } from '#angular/core';
import { Routes, RouterModule } from '#angular/router';
import {CadastrosComponent} from './...component';
....
const appRoutes: Routes = [
{ path: '', redirectTo: '/dashboard', pathMatch: 'full' },
{ path: 'dashboard', component: DashboardComponent },
{ path: 'cadastros', component: CadastrosComponent}
];
#NgModule({
imports: [RouterModule.forRoot(appRoutes)],
exports: [RouterModule]
})
export class AppRoutingModule {
}
Then import the routing module in your app module:
imports: [AppRoutingModule]
Then instead of switch case statement in your principal component, define the router outlet as below:
<router-outlet></router-outlet>
Then in the anchor tag in your side nav component template, define the router link as below:
<a routerLink="/cadastros">CADASTROS</a>
Hope this helps! Do let me know if you face any challenges implementing it.

Cannot get items inside a JSON file to use inside an angular partial

What I have is this:
A link to a views/:productId page
A /views/products folder populated with json files for each product
The problem is this: I get a correct redirect to the page, but that page gives me {{product.name}} rather than the correct data.
app.js
app.config(function ($routeProvider) {
$routeProvider
.when('/', {
templateUrl: 'views/featured.html',
controller: 'FeaturedCtrl'
})
.when('/products', {
templateUrl: 'views/products.html',
controller: 'ProductListCtrl'
})
.when('/products/:productId', {
templateUrl: 'views/product-detail.html',
controller: 'ProductDetailCtrl'
});
});
ProductDetailCtrl
angular.module('nameApp')
.controller('ProductDetailCtrl', ['$scope', '$routeParams', 'Product',
function ($scope, $routeParams, Product) {
$scope.product = Product.get({
productId: $routeParams.productId
});
}]);
Products.html
<div class="container">
<ol class="breadcrumb">
<li><a ng-href="#/">Parent</a></li>
<li><a ng-href="#/child">child</a></li>
<li class="active">{{product.name}}</li>
</ol>
<div class="row">
<div class="col-xs-12">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">{{product.name}}</h3>
</div>
<div class="panel-body">
<p class="text-justify">
{{product.description}}
</p>
</div>
</div>
</div>
</div>
<ol class="breadcrumb">
<li><a ng-href="#/">Parent</a></li>
<li><a ng-href="#/child">child</a></li>
<li class="active">{{product.name}}</li>
</ol>
</div>
productN.json
{
"name": "Name",
"type": [
"type1",
"type2",
"type3",
"type4",
"type5",
"type6"
],
"wood": [
"wood1",
"wood2",
"wood3",
"wood4",
"wood5"
]
}