I am using react for my application, and I have a bootstrap navigation bar menu has three tabs. I want to highlight the selected tab.
Here is the html code in my render() function.
<div className="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul className="nav navbar-nav navbar-left">
<li onClick={event => this.handleClick('tab1', event)} className={(this.state.activeTabClassName === "tab1") ? "active" : ""}>HOME<span className="sr-only">(current)</span></li>
<li onClick={event => this.handleClick('tab2', event)} className={(this.state.activeTabClassName === "tab2") ? "active" : ""}>RESOURCES</li>
<li onClick={event => this.handleClick('tab3', event)} className={(this.state.activeTabClassName === "tab3") ? "active" : ""}>CONTACT</li>
</ul>
</div>
I use the handleClick function to change the tabName:
handleClick(tabName, event) {
this.setState ({activeTabClassName : tabName});
//this.state.activeTabClassName = tabName;
}
I also set the initial state of activeTabClassName as 'tab1' in my constructor:
constructor() {
super();
this.state = {activeTabClassName : "tab1"};
// this.handleClick = this.handleClick.bind(this);
}
The code for the whole Nav.js component
import React from 'react';
export default class Nav extends React.Component {
constructor() {
super();
this.state = {activeTabClassName : "tab1"};
}
handleClick(tabName, event) {
this.setState ({activeTabClassName : tabName});
}
render(){
return(
<nav className="navbar navbar-default" role="navigation">
<div className="container-fluid">
<div className="navbar-header">
<button type="button" className="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
<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 navbar-utimg" href="https://www.xxx.xxxx" target="_blank">
<img alt="logo" src="/dist/assets/coe-logo.png"/>
</a>
</div>
<div className="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul className="nav navbar-nav navbar-left">
<li onClick={event => this.handleClick('tab1', event)} className={(this.state.activeTabClassName === "tab1") ? "active" : ""}>HOME<span className="sr-only">(current)</span></li>
<li onClick={event => this.handleClick('tab2', event)} className={(this.state.activeTabClassName === "tab2") ? "active" : ""}>RESOURCES</li>
<li onClick={event => this.handleClick('tab3', event)} className={(this.state.activeTabClassName === "tab3") ? "active" : ""}>CONTACT</li>
</ul>
<form className="navbar-form navbar-right" role="search">
<div className="form-group">
<input type="text" className="form-control" placeholder="Search"/>
</div>
<button type="submit" className="btn btn-default">Submit</button>
</form>
</div>
</div>
</nav>
)
}
}
However, it does not work well. Everytime when click the tab, it does not highlight the selected tab unless I clicked it again. Why does the onClick function not change the state right away? Is there any better solution for this problem?
Thanks!
Related
I am making a newsapp i want it to have different categories, instead of using react-router-dom for navigation what i want to do is create a state object and create a key in it named category and set current category as it's value and i have sent that key as a props to news component where i fetch news and embed that category to the fetch URL
I have made a function to set the category and its in app.js I have sent it to navbar component as props, the issue i am facing is that i can't select a category, because for some reason the onClick of the very last category is being called continuously and I know this because I console logged the category in setCategory function, can anyone tell me why this is happening
code in app.js:
import './App.css';
import React, { Component } from 'react'
import Navbar from './components/Navbar';
import News from './components/News';
export default class App extends Component {
constructor() {
super()
this.state = {
darkMode: "light",
country: "us",
category: "general",
key: "general"
}
}
setCategory = (cat)=> {
this.setState({
category: cat
})
console.log(this.state.category)
}
setCountry = (cntry)=> {
this.setState({
category: cntry
})
}
setDarkMode = () => {
if (this.state.darkMode === "light") {
this.setState({ darkMode: "dark" })
document.body.style.backgroundColor = "black"
} else {
this.setState({ darkMode: "light" })
document.body.style.backgroundColor = "white"
}
}
render() {
return (
<div>
<Navbar setCategory={this.setCategory} setCountry={this.setCountry} setDarkMode={this.setDarkMode} darkMode={this.state.darkMode} />
<News key={this.state.category} category={this.state.category} country={this.state.country} pageSize={18} darkMode={this.state.darkMode} />
</div>
)
}
}
code in Navbar component:
import React, { Component } from 'react'
export default class Navbar extends Component {
constructor(props) {
super(props)
this.setCategory = this.props.setCategory
}
render() {
return (
<div>
<nav className={`navbar navbar-expand-lg navbar-${this.props.darkMode} bg-${this.props.darkMode}`}>
<a className="navbar-brand" href="/">NewsMonkey</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="navbar-toggler-icon"></span>
</button>
<div className="collapse navbar-collapse" id="navbarSupportedContent">
<ul className="navbar-nav mr-auto">
<li className="nav-item active">
<a className="nav-link" href="/">Home <span className="sr-only">(current)</span></a>
</li>
<li className="nav-item">
<a className="nav-link" href="/about">About</a>
</li>
<li className="nav-item dropdown">
<a className="nav-link dropdown-toggle" href="/" role="button" data-toggle="dropdown" aria-expanded="false">
Categories
</a>
<div className="dropdown-menu">
<p className="dropdown-item cursor-pointer" onClick={this.setCategory("business")}>Business</p>
<p className="dropdown-item cursor-pointer" onClick={this.setCategory("science")}>Science</p>
<p className="dropdown-item cursor-pointer" onClick={this.setCategory("technology")}>Technology</p>
<p className="dropdown-item cursor-pointer" onClick={this.setCategory("entertainment")}>Entertainment</p>
<p className="dropdown-item cursor-pointer" onClick={this.setCategory("health")}>Health</p>
<p className="dropdown-item cursor-pointer" onClick={this.setCategory("sports")}>Sports</p>
<div className="dropdown-divider"></div>
<p className="dropdown-item cursor-pointer" onClick={this.setCategory("general")}>General</p>
</div>
</li>
</ul>
{/* <form className="form-inline my-2 my-lg-0">
<input className="form-control mr-sm-2" type="search" placeholder="Search" aria-label="Search" />
<button className="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button>
</form> */}
<div className={`custom-control custom-switch text-${this.props.darkMode === "light" ? "dark" : "light"}`}>
<input type="checkbox" className="custom-control-input" onClick={this.props.setDarkMode} id="customSwitch1" />
<label className={`custom-control-label`} htmlFor="customSwitch1">Dark mode</label>
</div>
</div>
</nav>
</div>
)
}
}
This doesn't do what you think it does:
onClick={this.setCategory("business")}
This calls the setCategory function immediately and uses the result of that function as the onClick handler. Don't pass the result of calling a function to onClick, pass a function itself:
onClick={() => this.setCategory("business")}
When I press the sync button, I need to run the Check Routine function. How can I do this ?
const CheckRoutine = require('../routines/check-at');
export default ({ className }) => (
<ul className={ `nav flex-column ${className || ''}` }>
<li>
<button className="btn btn-primary"
onClick={CheckRoutine} >
<i className="fa fa-refresh"> </i>
<span>Sync</span>
</button>
</li>
</ul>
);```
check-at:
module.exports = atCheck;
function atCheck() {
console.log("Cheking...");
}
If your check Routine is in the same component, you can directly give,
<button className="btn btn-primary"
onClick={CheckRoutine} >
<i className="fa fa-refresh"> </i>
<span>Sync</span>
</button>
or If your Check routine is in parent component, you can use call back function inside your component like below.
const CheckRoutine =(event) =>{
event.preventDefault();
props.checkRoutine();
}
<button className="btn btn-primary"
onClick={CheckRoutine} >
<i className="fa fa-refresh"> </i>
<span>Sync</span>
</button>
you can use this,
CheckRoutine.js
const CheckRoutine = e => {
console.log(e)
}
export default CheckRoutine
fileName.js
import CheckRoutine from './CheckRoutine'
export default ({ className }) => (
<ul className={ `nav flex-column ${className || ''}` }>
<li>
<button className="btn btn-primary"
onClick={CheckRoutine} >
<i className="fa fa-refresh"> </i>
<span>Sync</span>
</button>
</li>
</ul>
);
or you can in single file
const CheckRoutine = e => {
console.log(e)
}
export default ({ className }) => (
<ul className={ `nav flex-column ${className || ''}` }>
<li>
<button className="btn btn-primary"
onClick={CheckRoutine} >
<i className="fa fa-refresh"> </i>
<span>Sync</span>
</button>
</li>
</ul>
);
import atCheck from '../routines/check-at'
export default ({ className }) => (
<ul className={ `nav flex-column ${className || ''}` }>
<li>
<button className="btn btn-primary"
onClick={atCheck} >
<i className="fa fa-refresh"> </i>
<span>Sync</span>
</button>
</li>
</ul>
);
//../routines/check-at
export default const atCheck => (e) {
console.log("Cheking...");
}
I work on content editor in React admin interface.
And I'd love to install my favorite block content editor. But it's an old one and have no react version.
I know how to link .js and .css in head with ReactHelmet
But have no idea how to run following script:
<script>
$(function () {
$("#editor").brickyeditor({
ignoreHtml: true,
blocksUrl: 'data.json',
templatesUrl: 'templates.html',
onChange: function(data) {
console.log(data.html);
}
});
});
</script>
Here is initial html structure
<body>
<header>
<nav class="container navbar navbar-expand-lg navbar-light">
<a class="navbar-brand" href="index.html">BrickyEditor</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav mr-auto">
<li class="nav-item active">
<a class="nav-link" href="http://brickyeditor.info/examples.html">More Examples</a>
</li>
<li class="nav-item">
<a class="nav-link" href="https://github.com/yakovlevga/brickyeditor">GitHub Repository</a>
</li>
</ul>
</div>
</nav>
</header>
<main>
<div class="container">
<div class="row">
<div class="col-md-12">
<div id="editor"></div>
</div>
</div>
</div>
</div>
</main>
</body>
Im using it like so:
import PageTitle from "../components/common/PageTitle";
import Helmet from "react-helmet";
import $ from 'jquery';
class NewsEditor extends React.Component {
constructor(props) {
super(props);
this.state = {
};
}
render() {
const {
} = this.state;
return (
<Container fluid className="main-content-container px-4">
{/* Page Header */}
<Row noGutters className="page-header py-4">
<PageTitle sm="4" title="News editor" subtitle="Drag and drop interface" className="text-sm-left" />
</Row>
<Helmet
title="Nested Title"
link={[
{"rel": "stylesheet", "href": "https://cdn.jsdelivr.net/npm/brickyeditor/dist/jquery.brickyeditor.min.css"}
]}
script={[
{"src": "https://cdn.jsdelivr.net/npm/brickyeditor/dist/jquery.brickyeditor.min.js"},
]}
/>
<header>
<script>
$(function () {
$("#editor").brickyeditor({
ignoreHtml: true,
blocksUrl: 'data.json',
templatesUrl: 'templates.html',
onChange: function(data) {
console.log(data.html);
}
});
});
</script>
<nav class="container navbar navbar-expand-lg navbar-light">
<a class="navbar-brand" href="index.html">BrickyEditor</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav mr-auto">
<li class="nav-item active">
<a class="nav-link" href="http://brickyeditor.info/examples.html">More Examples</a>
</li>
<li class="nav-item">
<a class="nav-link" href="https://github.com/yakovlevga/brickyeditor">GitHub Repository</a>
</li>
</ul>
</div>
</nav>
</header>
<main>
<div class="container">
<div class="row">
<div class="col-md-12">
<div id="editor"></div>
</div>
</div>
</div>
</main>
</Container>
);
}
}
export default NewsEditor;
On this stage all I have is Failed to compile error.
UPD: Following advices I keep on getting TypeErrors
I always make re-usable components for external libraries. So in your case, it would be BrickyEditor component which could look like this:
class BrickyEditor extends React.Component {
editorRef = React.createRef();
componentDidMount() {
window.$(this.editorRef.current).brickyeditor(this.props);
}
render() {
return <div ref={this.editorRef}></div>
}
}
// in your NewsEditor component you can use it like so
<BrickyEditor
ignoreHtml={true}
blocksUrl="data.json"
templatesUrl="templates.html"
onChange={function(data) {
console.log(data.html);
}}
/>
I have a simple VueJS App with a Navigation Bar from Bootstrap:
<template>
<header id="header">
<nav class="navbar mynavbar navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar-collapse">
<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="logo" href="index.html"><img src="images/logo.png" alt=""></a>
</div>
<div class="collapse navbar-collapse" id="navbar-collapse">
<ul class="nav navbar-nav navbar-right">
<li><router-link to="/home"><a>Home</a></router-link></li>
<li><router-link to="/about"><a>About Us</a></router-link></li>
</ul>
</div><!-- /.navbar-collapse -->
</div><!-- /.container -->
</nav>
</header>
</template>
Now I want to ensure that when I change the route, the Bootstrap Menu gets closed. What is the best way to accomplish this?
Instead of adding event handlers to every router-link, you can simply watch the $route property for changes:
<script>
export default {
watch: {
'$route' () {
$('#navbar-collapse').collapse('hide');
}
}
}
</script>
Without Bootstrap and jQuery, can be easily achieved using class toggle and watch route changes.
<a role="button" class="navbar-burger" aria-label="menu" aria-expanded="false"
#click="toggledNav = !toggledNav"
>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
</a>
Script:
export default {
data () {
return {
toggledNav: false
}
},
watch: {
'$route' () {
this.toggledNav = false
}
}
}
You could give this a try:
<template>
<header id="header">
<nav class="navbar mynavbar navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar-collapse">
<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="logo" href="index.html"><img src="images/logo.png" alt=""></a>
</div>
<div class="collapse navbar-collapse" id="navbar-collapse">
<ul class="nav navbar-nav navbar-right">
<li><router-link #click.native="closeMenu()" to="/home"><a>Home</a></router-link></li>
<li><router-link #click.native="closeMenu()" to="/about"><a>About Us</a></router-link></li>
</ul>
</div><!-- /.navbar-collapse -->
</div><!-- /.container -->
</nav>
</header>
</template>
<script>
export default {
methods: {
closeMenu() {
$('#navbar-collapse').collapse('hide');
}
}
}
</script>
With vue3 and bootstrap5, adding this to the router-link element:
data-bs-toggle="collapse" data-bs-target=".navbar-collapse"
did not work for me: the menu would close without the link being followed.
So, I added this to router/index.js:
router.beforeEach(() => {
document.getElementById('navbarCollapse').classList.remove('show');
})
with navbarCollapse being the id of the div holding the menu/nav items.
It seemed to do the trick.
If necessary you can adjust the hamburger button state: its class list would need to contain "collapsed" and aria-expanded set to "false".
This gets corrected though when the user clicks the button again, so I didn't opt to write that code.
If you are using bootstrap-vue and vue-router.
<script>
export default {
watch: {
'$route' () {
const element = document.querySelector("#nav-collapse");
let isShown = element.classList.contains("show");
if(isShown){
this.$root.$emit('bv::toggle::collapse', 'nav-collapse')
}
}
}
}
</script>
<template>
<b-navbar toggleable="lg" type="" class="p-0">
<b-navbar-toggle target="nav-collapse" id="navbar-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</b-navbar-toggle>
<b-collapse id="nav-collapse" is-nav>
<div class="nav-wrapper w-100">
<ul class="app-navigation__list">
<router-link to="/whatever" tag="li" exact class="app-navigation__list__item">
<a href="">
<span class="link-text">Home</span>
</a>
</router-link>
<router-link to="/whatever" tag="li" exact class="app-navigation__list__item">
<a href="">
<span class="link-text">About</span>
</a>
</router-link>
<router-link to="/whatever" tag="li" exact class="app-navigation__list__item">
<a href="">
<span class="link-text">Store</span>
</a>
</router-link>
</ul>
</div>
</b-collapse>
</b-navbar>
</template>
I know this is an old question but my answer might help someone.
do this in your router/index.js
const router = createRouter({}); //P.S I am using Vue3
then add this before each route entering like so.
router.beforeEach(() => {
$('.navbar-collapse').collapse('hide'); //Be sure to import jquery
});
Because this is such a simple task, I try to make it as simple as my simple website.
Vue.mixin((()=> {
let store = Vue.observable({
indexMenu: false,
})
return{
computed: {
menu: {
get() {
return store.indexMenu
},
set(val) {
store.indexMenu = val
}
}
},
watch: {
'$route' () {
this.menu = false
}
}
}})())
router.beforeEach((from,to,next) => {
$('.navbar-collapse').collapse('hide'); //Be sure to import jquery
next();
});
This works
I have programmed a navbar using Bootstrap and react. In order to obtain the functionality of bootstrap must be installed and bootstrap.js jquery.js. I just want to basically use the CSS file of bootstrap and the functionality of reactjs. Does it make sense to use Bootstrap with reactjs?
I need to realize with reactjs a little help to program the navigation.
Here the source of my header. I need help to programm the navbar in reactjs without bootstrap.js and jquery.min.js
import React from "react"
export class Header extends React.Component {
render() {
return (
<nav className="navbar-kwp-header navbar-default navbar-fixed-top">
<div className="container">
<div className="navbar-header">
<button type="button" className="navbar-toggle collapsed" data-toggle="collapse" data-target="#Navbar">
<span className="sr-only">Navigation ein- / ausblenden</span>
<span className="icon-bar"></span>
<span className="icon-bar"></span>
<span className="icon-bar"></span>
</button>
<a className="navbar-brand" href="#"><img src="images/logo.jpg" alt="" /></a>
</div>
<div id="Navbar" className="navbar-collapse collapse">
<ul className="nav navbar-nav">
<li>Home</li>
<li className="dropdown"><a className="dropdown" data-toggle="dropdown" role="button" aria-expanded="false">Service <span className="caret"></span></a>
<ul className="dropdown-menu" role="menu">
<li>Downloads</li>
<li>Glossar</li>
<li>Newsletter</li>
</ul>
</li>
</ul>
</div>
</div>
</nav>
);
}
}
You can manually code a state variable to handle the toggling of the navbar:
class App extends Component {
state = {
navCollapsed: true
}
_onToggleNav = () => {
this.setState({ navCollapsed: !this.state.navCollapsed })
}
render () {
const {navCollapsed} = this.state
return (
<nav className='navbar navbar-default'>
<div className='navbar-header'>
<a className='navbar-brand' href='/'>Your Brand</a>
<button
aria-expanded='false'
className='navbar-toggle collapsed'
onClick={this._onToggleNav}
type='button'
>
<span className='sr-only'>Toggle navigation</span>
<span className='icon-bar'></span>
<span className='icon-bar'></span>
<span className='icon-bar'></span>
</button>
</div>
<div
className={(navCollapsed ? 'collapse' : '') + ' navbar-collapse'}
>
<ul className='nav navbar-nav navbar-right'>
<li>
<a>About</a>
</li>
</ul>
</div>
</nav>
)
}
}
You can easily use bootstrap in your react components by using react-bootstrap package.
https://react-bootstrap.github.io/
This is an example with navbar which you want to use.
import React from "react"
import { Navbar, Nav, NavItem, NavDropdown, MenuItem } from 'react-bootstrap';
export class Header extends React.Component {
render() {
return (
<Navbar>
<Navbar.Header>
<Navbar.Brand>
React-Bootstrap
</Navbar.Brand>
</Navbar.Header>
<Nav>
<NavItem eventKey={1} href="#">Link</NavItem>
<NavItem eventKey={2} href="#">Link</NavItem>
<NavDropdown eventKey={3} title="Dropdown" id="basic-nav-dropdown">
<MenuItem eventKey={3.1}>Action</MenuItem>
<MenuItem eventKey={3.2}>Another action</MenuItem>
<MenuItem eventKey={3.3}>Something else here</MenuItem>
<MenuItem divider />
<MenuItem eventKey={3.3}>Separated link</MenuItem>
</NavDropdown>
</Nav>
</Navbar>
);
}
}