Here is the code:
state: {
button: "notclicked"
}
changeclass = () => {
this.setState({ button: "clicked" })
}
<ul>
<li className="linkactive">
<a class="vote-up-off" onClick={ this.changeclass } href="/">
<Icon className={ this.state.button } className=" fa fa-area-chart"/>
</a>
</li>
<li>
<a class="vote-up-off"href="/">
<Icon className="fa fa-bar-chart fa-2x"/>
</a>
</li>
<li>
<a class="vote-up-off" href="/>
<Icon className="fa fa-line-chart"/>
</a>
</li>
</ul>
I am able to change the class on clicking <li>, But on clicking another <li>, how to make prev class back to notclicked?
I want to show the user which tab he is currently on
What happen now with your changeClass() function is that every time you click on the link, the state.button is set to "clicked".
What you could do in this method is start by checking the value of button and set it to the other value.
eg:
changeclass=()=>{
if(this.state.button === "notclicked"){
this.setState({button:"clicked"})
}
else {
this.setState({button:"notclicked"})
}
}
Then, if you want each <li> to trigger your changeclass function, onClick must be set for each one of them.
Also, there are a few typos in your code:
onClicke must be onClick
in the last <a> tag, the string besides href is not closed (there is a missing ")
To summarize, this code should work as expected:
state:{
button:"notclicked"
}
changeclass = () => {
if(this.state.button === "notclicked"){
this.setState({button:"clicked"})
}
else {
this.setState({button:"notclicked"})
}
}
<ul>
<li className="linkactive"><a class="vote-up-off" onClick={this.changeclass} href="/"><Icon className={this.state.button} className=" fa fa-area-chart"/></a></li>
<li><a class="vote-up-off"href="/" onClick={this.changeclass}><Icon className="fa fa-bar-chart fa-2x"/></a></li>
<li><a class="vote-up-off" href="/" onClick={this.changeclass}><Icon className="fa fa-line-chart"/></a></li>
</ul>
you can try it like this
// lets assume initial state is false
state = {clicked : false}
later on your component, you make ternary if by doing it like this
changeClicked = ()=>{
// this setState will take what you have previously, and
// will change it to opposite value
this.setState(prev=>({clicked: !prev.clicked}))
}
//...
<a onClick={this.changeClicked}>
<Icon className={clicked ? "clicked":"notclicked"} />
</a>
my suggestion is if you have something opposite like clicked-notclicked, on-off, up-down, etc that inherently one will always be true when the opposite is false, use boolean.
it will help you down the road.
Related
I'm trying to get to work a delete btn which is inside a div which is wrapped in react-router-dom tag. I want to be able to navigate to the established path when that div is clicked. But if the target is that delete btn, then it shouldn't navigate just execute the onClick inside the delete btn. Is this possible? I couldn't figure out on my own. Thanks for reading.
<ul className="m-entries">
{
letters.map(letter => {
return (
<li className="o-entry" key={ letter.id }>
<Link to={`/Letters/letter/${ letter.id }`}>
<div className="l-entry-container">
<div className="l-entry__header">
<h2 className="c-text__h2 c-letter-title">{ letter.title }</h2>
// This is the delete btn
<button
className="c-entry__btn c-entry__dlt-btn"
onClick={(e) => {
displayConfirmDeleteWdw(e, letter.id)
}}
type="button"
>
<XDeleteBtn />
</button>
</div>
<p className="c-text__p c-letter__preview">{ letter.synopsis }</p>
</div>
</Link>
</li>
)})
}
</ul>
It's generally considered bad UI/UX to place interactive DOM elements within other interactive DOM elements (in fact some elements are sometimes illegal when used like this), but there is a way to accomplish this.
The button's onClick event should not propagate up to the Link component. Call stopPropagation on the event to prevent it from bubbling up further.
<ul className="m-entries">
{letters.map(letter => {
return (
<li className="o-entry" key={letter.id}>
<Link to={`/Letters/letter/${letter.id}`}>
<div className="l-entry-container">
<div className="l-entry__header">
<h2 className="c-text__h2 c-letter-title">{letter.title}</h2>
<button
className="c-entry__btn c-entry__dlt-btn"
onClick={(e) => {
e.stopPropagation(); // <-- prevent event from bubbling up
displayConfirmDeleteWdw(e, letter.id);
}}
type="button"
>
<XDeleteBtn />
</button>
</div>
<p className="c-text__p c-letter__preview">{letter.synopsis}</p>
</div>
</Link>
</li>
)})
}
</ul>
I have been stuck for hours to figure out how to add classActive on the parent html tag of the provided reactrouter tag. Here is the code,
Using React-Router "version": "3.2.6"
<li className="sidebar-item">
<div className="sidebar-link" activeClassName="active">
<span>Track Page</span>
<div className="collapse first-level">
<Link className="first-level__link" to="/track-page" activeClassName="active">
Track Page 1
</Link>
<Link className="first-level__link" to="/track-page-2" activeClassName="active">
Track Page 2
</Link>
</div>
</div>
</li>
Currently the active class can only be kept on <link> tag but I need it to be on the <li> the parent of the <link>. How can I achieve this ? Please help.
I am not very familiar with react so, any help here would be much appreciated. Thank you in advance.
Use <NavLink> instead of <Link> and add exact as a property
Include exact as a property to ensure activeClassName only triggers on url paths that match your location exactly
if you want add active class to li tag also which is the parent
you can use a function to get the NavLinkClass
you can use the useLocation to get the exact location
import { useLocation,NavLink } from "react-router-dom";
const location = useLocation();
const getNavLinkClass = path => {
return location.pathname === path
? "sidebar-item active"
: "sidebar-item";
};
<li className={getNavLinkClass("/track-page")>
<div className="sidebar-link">
<span>Track Page</span>
<div className="collapse first-level">
<NavLink
className="first-level__link"
to="/track-page"
activeClassName="active"
>
Track Page 1
</NavLink>
<NavLink
className="first-level__link"
to="/track-page-2"
activeClassName="active"
>
Track Page 2
</NavLink>
</div>
</div>
</li>
Try by adding style to anchor element like below.
<Link to="/track-page" >
<a className="first-level__link_active"> Track Page 1 </a>
</Link>
<Link to="/track-page-2" activeClassName="active">
<a className="first-level__link_active">Track Page 2 </a>
</Link>
Using this.props.location.pathname you get the current page url. so you can set the condition when page url match you give the active class anywhere you want.
Try this code may be it's help you
render() {
const url = this.props.location.pathname + this.props.location.search;
<li className="sidebar-item">
<div className="sidebar-link">
<span>Track Page</span>
<div className="collapse first-level">
<div className={url == '/track-page' ? 'active' : ''}>
<Link className="first-level__link" to="/track-page" activeClassName="active">
Track Page 1
</Link>
</div>
<div className={url == '/track-page-2' ? 'active' : ''}>
<Link className="first-level__link" to="/track-page-2" activeClassName="active">
Track Page 2
</Link>
</div>
</div>
</div>
</li>
}
here is the demo code sandbox : https://codesandbox.io/s/black-platform-gz5qx?file=/src/App.js
you can use window.location.pathname to get the current route. you might want to use something like the following sample code.
export default function App() {
const location = window.location.pathname;
return (
<div className="outer">
<h1>Hello CodeSandbox</h1>
<a
href="/track-page"
className={`link ${location === "/track-page" ? "active" : ""}`}
>
/track-page
</a>
<a
href="/track-page-2"
className={`link ${location === "/track-page-2" ? "active" : ""}`}
>
/track-page-2
</a>
<a
href="/track-page-3"
className={`link ${location === "/track-page-3" ? "active" : ""}`}
>
/track-page-3
</a>
</div>
);
}
I am trying to refactor from class based to functional. While doing so I will need to use hooks instead of setting this.state etc.. I am trying to get a FORM to open when i click a button. The button will also change from "add reply" to "submit comment" once the form opens. I am stumped. This is the best thing I could come up with... Doesnt work. in fact, it makes my "add reply" button completely disappear. Any thoughts on this? Here is the code that I have written. inside of the comment I am trying to return a component using ternary....
image of component as-is
import React, {useState} from 'react';
import FormOpen from './FormOpen';
const CommentCreated = (props) => {
const [resource, setResource] = useState([{visible: false, addReply: 'Add Reply'}]);
return (
<div className="ui threaded comments">
<h3 className="ui dividing header">Comments</h3>
<div className="comment">
<a href="/" className="avatar">
<img alt="avatar" src= {props.avatar} />
</a>
<div className="content">
<a href="/" className="author">{props.author}
</a>
<div className="metadata">
<span className="date">Today at 5:42PM</span>
</div>
<div className="text">{props.content}
</div>
<div className="actions">
{resource.visible ? <FormOpen /> : null}
<a className="reply" onClick={() => {setResource([{visible: true, addReply: 'Submit Comment'}]);}}>{resource.addReply}
</a>
<a className="save">Save</a>
<a className="hide">Hide</a>
</div>
</div>
</div>
</div>
);
};
export default CommentCreated;
You should replace the setResource(['Submit Comment', true]) with :
setResource([{
visible: true,
addReply: 'Submit Comment'
}])
To match the shape of your state.
EDIT:
Here is a working example based on your code.
As I can see from your example, your resource state doesn't need to be an array but simply an object.
Furthermore, as you are using hyperlinks <a />, you must use preventDefault() on your event being triggered if you don't want the page to refresh.
Hi,
I have a notification menu list in which i am binding the data which is coming from the REST API. My notification menu will look like this. See below image for clarity.
In the notifications, when ever i click on any of the list item then it should be removed from the list and on the above also there is notification bubble in red color with some count that how many notifications i have received. What i want to achieve is when i click on the notification menu list then the clicked list item should be removed from it also the count should decrease in red color bubble above the bell icon. For example, when i click on notification list item of first item the it should be removed as well as the count should be decreased.
notification.component.ts
try {
this.currentUser = JSON.parse(this.cookieService.get('user-is-logged-in-details'));
console.log(this.currentUser.uid);
this._userService.getBellNotification(this.currentUser.uid)
.subscribe(data => this.cookieData = data);
} catch (e) {
console.log("Catch Block Error from Notification.Component.ts");
//console.log("currentUser", this.currentUser.uid);
}
apiservice.service.ts
getBellNotification(uid: any){
const urlBell = this.config.apiUrl+'api/supplier-notification/'+uid+'?_format=json';
let headers = new Headers();
headers.append("Content-Type", 'application/json');
headers.append('Authorization', 'Basic ' + btoa('apiuser:#piUser#2017Supplier'));
let requestoptions = new RequestOptions({headers: headers});
return this.http.get(urlBell, requestoptions)
.map(response => response.json())
.catch(this.handleErrorObservable);
}
notification.component.html
<span
class="notification"
dropdown (onShown)="onShown()"
(onHidden)="onHidden()"
(isOpenChange)="isOpenChange()">
<a
href dropdownToggle
(click)="false">
<i
class="glyphicon glyphicon-bell"
[ngClass]="cookieData?.search_unread_count != 0 ? 'notification-icon': ' '">
<span *ngIf="cookieData?.search_unread_count != 0">{{cookieData.search_unread_count}}</span>
</i>
</a>
<ul
*dropdownMenu
class="dropdown-menu notify-drop">
<div
class="notify-drop-title">Notifications</div>
<div
class="drop-content"
*ngFor="let item of cookieData.search_result">
<li
data-id="{{item.id}}"
class="notification-items unread">
<i
class="fa fa-dot-circle-o"
aria-hidden="true">
</i>
<a
data-link="admin-invoice-list"
href="javascript:;">{{item.message}}
</a>
</li>
</div>
</ul>
</span>
Can anyone please suggest me how it can be achieved?
#federico scamuzzi ise explained what you missed exactly. but him answer is need some correction for your objects and requirements. I have update that in here, try it and let me know if you have any clarification.
<div
class="drop-content"
*ngFor="let item of cookieData.search_result">
<li (click)="remove(item)"
data-id="{{item.id}}"
class="notification-items unread">
<i
class="fa fa-dot-circle-o"
aria-hidden="true">
</i>
<a
data-link="admin-invoice-list"
href="javascript:;">{{item.message}}
</a>
</li>
and your remove function should be
remove(item:any){
//ALSO CALL A BACKEND API... TO REMOVE THEM .. THIS IS ONLY FRONT END
this.cookieData.search_result = this.cookieData.search_result.filter(xx=>xx.id != item.id);
this.cookieData.search_unread_count=this.cookieData.search_result.length;
}
have youtried to attach a (click) function on each so to remove (or do the action you want) on the click of item?...something like:
<div
class="drop-content"
*ngFor="let item of cookieData.search_result">
<li (click)="remove(item)"
data-id="{{item.id}}"
class="notification-items unread">
<i
class="fa fa-dot-circle-o"
aria-hidden="true">
</i>
<a
data-link="admin-invoice-list"
href="javascript:;">{{item.message}}
</a>
</li>
then in your ts file:
remove(item:any){
//ALSO CALL A BACKEND API... TO REMOVE THEM .. THIS IS ONLY FRONT END
this.cookieData = this.cookieData.filter(xx=>xx.id != item.id);
this.cookieData.search_unread_count=this.cookieData.search_result.length;
}
Hope it helps you!!
I want to add isActive class to an item menu when user click on this item, and remove isActive class from all others items.
I am trying to compare the id, this is the angularJS code:
$rootScope.isActive = function(idVal, event){
return idVal === event.target.id;
}
This is a part from Menu Html code:
<ul class="sidebar-nav">
<li>
<a ui-sref="" id='101' ng-class="{active: isActive($event, 101)}">
<span class='glyphicon glyphicon-ban-circle glyph-sidebar'></span>
Rules
</a>
<ul class='dropdown sidebar-nav-dropdown' >
<li>
Transaction Mapping
</li>
<li>
File Setup
</li>
<li>
Code Setup
</li>
</ul>
</li>
<li>
<a href="#" id='102' ng-class="{active: isActive($event, 102)}">
<span class='glyphicon glyphicon-ban-circle glyph-sidebar'></span>
Administrative Rules
</a>
<ul class='dropdown sidebar-nav-dropdown'>
<li>
<a ui-sref="admin.mapping-rules">Transaction Mapping</a>
</li>
<li>
<a ui-sref="admin.mapping-rules">File Setup</a>
</li>
<li>
<a ui-sref="admin.mapping-rules">Code Setup</a>
</li>
</ul>
</li>
</ul>
Thanks,
First of all, you shouldn't use the root scope. You should use the scope of the controller associated to that view.
Second, your code doesn't make much sense. $event can be used as a parameter of a function called... to react to an event:
ng-click="doSomething($event)"
But with ng-class, there is no $event.
All you need to have in your scope is the ID (or name, or whatever identifies a menu item) of the selected menu item:
$scope.selectedMenuItem = null;
When an item is clicked, you need to change the selected menu item:
ng-click="selectMenuItem(101)"
$scope.selectMenuItem(item) {
$scope.selectedMenuItem = item;
}
Then to associated a css class with the selected menu item, you simply need
ng-class="{active: selectedMenuItem === 101}"
That said, if all your links navigate to a given router state, you don't even need that selectedMenuItem. All you need is to add the active class if the current router state is the one the that the link allows navigating to (assuming $state is on your scope):
ng-class="{active: $state.includes('admin.mapping-rules')}