Add active class to link (React JS) - javascript

Have a component that's display menus from array
import React from 'react'
import { Link, browserHistory,IndexLink } from 'react-router'
$( document ).ready(function() {
$( "ul.tabs li a" ).first().addClass("current");
$("li:not(:first-child)").click(function() {
$( "ul.tabs li a" ).first().removeClass("current");
});
});
function Tabs (props) {
const numbers = props.menuitems;
const listItems = numbers.map((number) =>
<li key={number.link} ><Link to={number.link} activeClassName="current" className="tab-link">{number.linkName}</Link></li>
);
return (
<div>
<ul className="tabs" >{listItems}</ul>
<div className="tabs-header-stripe"></div>
</div>
);
}
export default Tabs
I added "curent" class by Jquery to first element, the problem is When I go from another page, class not adding, but when I just refresh page It's add normaly.

What you say is happening because the class is added in documentReady event. When yo arrive from another page the event has already been raised but of course the following code cannot find the dom element because it is not present in the page:
$( "ul.tabs li a" ).first()
What I can suggest is to avoid using jquery (and modifying the dom from outside react) and add the class directly in the react code.
I guess you wanted to do something like this:
import React from 'react'
import { Link, browserHistory,IndexLink } from 'react-router'
function Tabs (props) {
const numbers = props.menuitems;
const listItems = numbers.map((number, index) =>
<li key={number.link} ><Link to={number.link} activeClassName="current" className={index === 0 ? "tab-link current" : "tab-link"}>{number.linkName}</Link></li>
);
return (
<div>
<ul className="tabs" >{listItems}</ul>
<div className="tabs-header-stripe"></div>
</div>
);
}
export default Tabs

Related

rendering has not updated after componentdidmount,advice?

I'm building an application to save locations i.e countries cities regions etc. When clicking on my on click function the states of two div tags change changing the class name and making one invisible and one visible. advice?
import React, { useState }from "react";
import Area from "../ReadFolder/geographicMainComponents/areaMainComponent.jsx";
import City from "../ReadFolder/geographicMainComponents/cityMainComponent.jsx";
import Country from "../ReadFolder/geographicMainComponents/countryMainComponent.jsx";
import Neighborhood from "../ReadFolder/geographicMainComponents/neighborhoodMainComponent.jsx";
import Region from "../ReadFolder/geographicMainComponents/regionMainComponent.jsx";
import { default as AreaW} from "../WriteFolder/geographicMainComponents/areaMainComponent.jsx";
import { default as CityW} from "../WriteFolder/geographicMainComponents/cityMainComponent.jsx";
import { default as CountryW} from "../WriteFolder/geographicMainComponents/countryMainComponent.jsx";
import { default as NeighborhoodW} from "../WriteFolder/geographicMainComponents/neighborhoodMainComponent.jsx";
import { default as RegionW} from "../WriteFolder/geographicMainComponents/regionMainComponent.jsx";
export default function MenuWrapper({type,id,isEdit}){
let [edit,setEdit] = useState(isEdit);
let changer=()=>{console.log('you clicked me!');setEdit(!setEdit)}
if(type==='country'){
return(
<div key={"frommenulist"+id}>
<div className={edit ? 'd-block' :'d-none'}><CountryW id={id}/><button onClick={changer}>read</button></div>
<div className={edit ? 'd-none' : 'd-block'}><Country id={id} /><button onClick={changer}>edit</button></div>
</div>
);
}
}
It's difficult to work out what clicking those buttons is meant to do. It looks like you need only one div/button block, and clicking the edit button determines what happens (ie to make the country editable somehow).
At the moment it looks like you want to set the display to either block/none but you can't set an element's display to none and still expect to be able to click the button to reset the display because there will be no button to click on. Further: unless the type is "country" the component doesn't return anything so you need a condition in there to return something if type isn't "country" (or add a condition in the parent component to prevent the component rendering at all if that condition is met).
Here's a small example that uses local state to manage whether the div is a plain one or an editable one. Click the edit button, and then click in the div to be able to edit it. You can then click the read button to switch off contentEditable and keep the content.
const { useState } = React;
function MenuWrapper({ type, id }) {
const [ edit, setEdit ] = useState(false);
function handleClick() {
setEdit(!edit);
}
// Return a default div if type is not "country"
if (type !== 'country') return <div>Not country</div>
const divStyle = [
'country',
edit && 'edit'
].join(' ');
return (
<div>
<div>
<div
className={divStyle}
contentEditable={edit}
>Country Id: {id}
</div>
<button onClick={handleClick}>
{edit ? 'Read' : 'Edit'}
</button>
</div>
</div>
);
}
ReactDOM.render(
<MenuWrapper type="country" id="1" />,
document.getElementById('react')
);
.country { padding: 0.25em; }
.edit { border: 1px solid green; }
button { margin-top: 1em; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>
<div id="react"></div>

Fallback message for empty object meteor/react

I would like to show a message if there aren't objects to be returned. Something like: 'currently there are no customers available'.
I tried to tinker a bit with Object.getOwnPropertyNames() but could not get it working because the mapping function does not being called. I'm not sure where to put this check, inside the rendering function, in the with tracker or render call inside the template.
I use Meteor/react and my code looks like this:
import React, {Component} from 'react';
import {withTracker} from 'meteor/react-meteor-data';
import {Link} from 'react-router-dom';
class ArchiveCustomerOverview extends Component {
renderCustomerList() {
return this.props.users.map( user => {
return(
<div className="row" key={user._id}>
<Link to={}>
<span className="medium-1">{user.profile.name}</span>
<span className="medium-4">{user.profile.company}</span>
<span className="medium-3">{user.profile.phone}</span>
<span className="medium-3">{user.emails[0].address}</span>
</Link>
</div>
)
});
}
render() {
return (
<div>
<div className="list-overview">
<div className="list-wrapper">
<div className="list-box clear">
{this.renderCustomerList()}
</div>
</div>
</div>
</div>
);
}
}
export default withTracker( (props) => {
Meteor.subscribe('users');
return {
users: Meteor.users.find({
'profile.isArchived': 0,
'roles.customers' : 'customer'
}).fetch()
};
})(ArchiveCustomerOverview);
Just check on the number of users before you render them like this:
renderCustomerList() {
if (this.props.users.length === 0) {
return (<div>Currently there are no customers available</div>)
}
return this.props.users.map( user => {
But a word of warning: you may not get what you want from the users collection - for security reasons it is treated differently from other collections.

Call a function on element ID click with selectors [Meteor + React]

I have a small Blaze event handling as below;
Template.navigation.events({
// Collapse menu in mobile mode after click on element
'click #side-menu a:not([href$="\\#"])': function(){
if ($(window).width() < 769) {
$("body").toggleClass("show-sidebar");
}
}
});
UI looks like:
import React from 'react';
import {render} from 'react-dom';
export default class Navbar extends React.Component {
render() {
return (
<aside id="menu">
<div id="navigation">
<ul className="nav" id="side-menu">
</ul>
</div>
</aside>
)
}
}
I just to convert the Blaze event to React function, so that all works same in React as it is working in Blaze Event handling.
The answer might be simple, but I am a newbie to React (16.2) so I expect soft corner.

React.js implement menu [highlight active link]

The following React.js code renders a navbar with two links named 'about' and 'project'. On page load the 'about' link is active and colored red. When the other link is clicked the state of the navbar is set to 'project', 'about' link style is set back, and 'project' is colored red.
I achieve this by attaching a click handler to both link tags, and set the state of active to the name of the event.target.innerHTML.
I'm new to react, and I feel this is a really verbose way of going about this. I am aware that there is an activeClassName prop you can pass to a react-router link, but I want a way that does not use it.
import React, { Component } from 'react'
import { Link, Route } from 'react-router'
export default class Navbar extends Component {
constructor() {
super();
this.state = {
active: 'about'
}
this._handleClick = this._handleClick.bind(this);
}
_handleClick(e) {
this.setState({
active: e.target.innerHTML
});
}
render() {
let aboutStyle;
let projectStyle;
if (this.state.active === 'about') {
aboutStyle = { color: '#ff3333' };
projectStyle = {};
} else {
aboutStyle = {};
projectStyle = { color: '#ff3333' };
}
return (
<div className='navbar'>
<Link to='/'><h2>BK //</h2></Link>
<div className='menu'>
<Link style={aboutStyle} onClick={this._handleClick} to='about'>about</Link>
<Link style={projectStyle} onClick={this._handleClick} to='projects'>projects</Link>
</div>
</div>
)
}
}
At this day you can use NavLink from react-router-dom. This object supports attributes as activeClassName, activeStyle, or isActive (for functions).
import { NavLink } from 'react-router-dom';
<NavLink to='about' activeClassName="active">about</NavLink>
// Or specifing active style
<NavLink to='about' activeStyle={{color: "red"}}>about</NavLink>
// If you use deep routes and you need an exact match
<NavLink exact to='about/subpath' activeClassName="active">about</NavLink>
For more options read documentation: https://reacttraining.com/react-router/web/api/NavLink
maybe slightly less verbose... in Pseudocode
const menuItems = [
'projects',
'about',
];
class MenuExample extends React.Component {
_handleClick(menuItem) {
this.setState({ active: menuItem });
}
render () {
const activeStyle = { color: '#ff3333' };
return (
<div className='menu'>
{menuItems.map(menuItem =>
<Link
style={this.state.active === menuItem ? activeStyle : {}}
onClick={this._handleClick.bind(this, menuItem)}
>
{menuItem}
</Link>
)}
</div>
);
}
}
Using NavLink in place of Link gives you the opportunity to set your preferred style for the active page/link.
So you can go ahead and set the style in CSS like this.
.active {
color: 'red'
}
We can use NavLink to highlight the active by writing custom class handling based on de-structured isActive property
<NavLink
to='/'
className={
useCallback(({isActive}) => isActive ? classes.active : classes.link)}
>
Home
</NavLink>
Ref: https://stackoverflow.com/a/72520423/4652706
As of React Router v6, activeClassName prop will not work. Find the solution here, ReactJS - Unknown prop `activeClassName` on <a> tag. Remove this prop from the element

Set active Bootstrap nav dropdown when any item in the list is active in React-Router v4

I'm using React Router v4 and trying to write up a wrapper that allows the Bootstrap dropdown class to be active. The gist is that I need match multiple routes, and I'm unsure exactly how to do that in this wrapper.
Here is what I have:
import React, { PropTypes } from 'react';
import { Link } from 'react-router';
const DropDownLinkWrapper = ({links, label}) => {
return (
<Link to="/link1|/link2"> // <-- this is what I want to do
{({isActive}) =>
<li className={`dropdown ${isActive ? 'active' : ''}`}>
<a href="#" className="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
aria-expanded="false">{label}<span className="caret"/></a>
<ul className="dropdown-menu">
{// output menu links here}
</ul>
</li>
}
</Link>
);
};
DropDownLinkWrapper.propTypes = {
links: PropTypes.array.isRequired,
label: PropTypes.string.isRequired
};
export default DropDownLinkWrapper;
I would imagine that the first <Link/>'s to prop would need to match on two URLs. But of course, this doesn't work. Does anyone have a solution for this?

Categories