React onClick not changing color of item - css

I am trying to make it so that when i click a note, the item should become selected and then it will change background color.
I have a console log statement inside the handleNoteClick function, but it is not logging, meaning that the function is not being called
import React, { useState } from "react";
import { NoteItems } from "../noteDisplay/noteDisplay";
import NavItems from "./navItems";
const NoteNav = () => {
const [notes, setNotes] = useState(NoteItems);
const handleNoteClick = (id) => {
const newNoteItems = notes.map((item) => {
if (item.id === id) return { ...item, selected: !item.selected };
else {
return item;
}
});
console.log("yekaj;lksndf");
setNotes(newNoteItems);
};
return (
<nav className="nav-bar">
<div className="nav-content">
{NoteItems.map((items) => (
<NavItems key={items.id} items={items} onClick={handleNoteClick} />
))}
</div>
</nav>
);
};
export default NoteNav;
Array of notes:
const NoteItems = [
{
id: uuidv4(),
message: "asdfasdfffffffffffffffffffffffffffffffffffffff",
title: "New Note",
selected: false
},
{
id: uuidv4(),
message: "asdfffffffffffffffffffffffffffffffffffffff",
title: "e"
},
{
id: uuidv4(),
message: "asdfasdfffffffffffffffffffffffffffffffffffffff",
title: "New Note",
selected: false
},
{
id: uuidv4(),
message: "asdfasdfffffffffffffffffffffffffffffffffffffff",
title: "New Note",
selected: false
},
{
id: uuidv4(),
message: "asdfasdfffffffffffffffffffffffffffffffffffffff",
title: "New Note",
selected: false
},
{
id: uuidv4(),
message: "asdfasdfffffffffffffffffffffffffffffffffffffff",
title: "New Note",
selected: false
},
{
id: uuidv4(),
message: "asdfasdfffffffffffffffffffffffffffffffffffffff",
title: "New Note",
selected: false
},
{
id: uuidv4(),
message: "asdfasdfffffffffffffffffffffffffffffffffffffff",
title: "New Note",
selected: false
},
{
id: uuidv4(),
message: "asdfasdfffffffffffffffffffffffffffffffffffffff",
title: "New Note",
selected: true
}
];
The object that I pass each item of the array into
import React, { useState } from "react";
const NavItems = ({ items }) => {
return (
<div
className={
items.selected ? "second-note-box-selected" : "second-note-box"
}
>
<h1 className="note-title">{items.title}</h1>
<p className="note-content">{items.message}</p>
</div>
);
};
export default NavItems;

There are a couple of problems with your code.
The first and most important is that onClick only works on native DOM elements. What you are doing here <NavItems key={items.id} items={items} onClick={handleNoteClick}/> is passing a prop named onClick to NavItems.
That will not trigger an on click, you need to use that in the component and attach it to a div for instance.
The second is regarding the fact that you are updating notes, but you don't use it during the render.
The third could be that you are iterating over the entire array, just to update one value. You could easily do something like this:
const handleNoteClick =(item) => {
item.selected = !item.selected
console.log('yekaj;lksndf')
setNotes([...notes])
}
And pass item as the argument to handleNoteClick like this:
<NavItems onClick={() => handleNoteClick(item) />

in this line that you mapped your items into NavItem
{NoteItems.map((items)=><NavItems key={items.id} items={items} onClick={handleNoteClick}/>)}
the onClick just point to the function and you cant pass pointer like handleNoteClick(id) because its excuted not pointed and your not passing the id to the function though
do this i think it should work
{NoteItems.map((items)=><NavItems key={items.id} items={items} onClick={()=>handleNoteClick(items.id)}/>)}
and of course you should pass custom prop onClick to your custom component native onclick

Related

Adding controls for nested proptypes in storybook

I am trying to add a multi-select control using argTypes in storybook for a button component which takes propTypes in below format :
type ButtonProps = {
params: { FirstParam: string; SecondParam: string };
fields: Fields;
};
And the below is the code where I am trying to specify the control type for firstParam :
export default {
title: 'components/Button',
component: Default,
argTypes: {
params: {
FirstParam: {
name: 'FirstParam',
description: 'grid styling',
control: { type: 'multi-select', disable: false },
options: ['b', 'c', 'd'],
defaultValue: 'b c d',
},
SecondParam: {
name: 'SecondParam',
description: 'button styling',
control: 'multi-select',
options: ['none', 'secondary-button'],
},
},
},
decorators: [(story) => <div className="grid grid-cols-12">{story()}</div>],
} as ComponentMeta<typeof Default>;
const Template: ComponentStory<typeof Default> = (args) => <Default {...args} />;
export const Primary = Template.bind({});
Primary.args = {
fields: {
Link: {
value: {
href: 'https://www.google.com/',
target: '_blank',
text: 'Find Installer',
},
},
},
};
But it doesn't bind the control and breaks the storybook component.
Is it possible to have controls like multi-select working for the above kind of buttonProps?

how can I make the data no longer pass in the adjacent column when there is no space in react table bootstrap?

I would like when there is no space to lower the letters that do not fit with a lower level.Can i resolve this using css ?
I tried in various ways I read the documentation but nothing worked just changing the color :(
I really need to know if there is a solution as soon as possible, thanks in advance :)
There is my table when there is no space
There is my code
import "react-bootstrap-table-next/dist/react-bootstrap-table2.min.css";
import "bootstrap/dist/css/bootstrap.min.css";
import BootstrapTable from "react-bootstrap-table-next";
import paginationFactory from "react-bootstrap-table2-paginator";
import Sidebar from "./sidebar/Sidebar";
import 'bootstrap/dist/css/bootstrap.css';
import React, { useEffect, useState } from "react";
import axiosInstance from "./axios";
import cellEditFactory from 'react-bootstrap-table2-editor';
import { Button } from "react-bootstrap";*
const UsersList = () => {
const [users,setUsers] = useState([]);
useEffect( () => {
axiosInstance.get("users")
.then(res => {
const val = res.data;
setUsers( val);
})
.catch(error => {
console.log(error);
});
}, []);
let isFollow = true;
const onFollowChanged =() => {
isFollow = !isFollow;
console.log(isFollow);
}
const linkFollow = (cell, row, rowIndex, formatExtraData) => {
return (
<Button
onClick={() => {
onFollowChanged();
}}
>
Follow
</Button>
);
};
onFollowChanged.bind();
const columns = [
{
dataField: 'index',
text: 'ID',
formatter: (cell, row, rowIndex, formatExtraData) => {
return rowIndex + 1;
},
sort: true,
},
{
dataField: "username",
text: "Username",
},
{
dataField: "email",
text: "Email",
},
{
dataField: "fullName",
text: "Full Name"
},
{
dataField: "address",
text: "Address"
},
{
dataField: "status",
text: "Status"
},
{
dataField: "follow",
text: "EDIT",
editable: false,
formatter: linkFollow
}
];
const rowEvents = {
onClick: (e, row, rowIndex) => {
window.location.assign("/home");
}
};
return (
<div>
<Sidebar />
<div className="container" style={{ padding: "20px" }}>
<BootstrapTable
striped hover condensed
trClassName='tr-string-example'
keyField="id"
data={users}
columns={columns}
pagination={paginationFactory({ sizePerPage: 5 })}
cellEdit={ cellEditFactory({ mode: 'click' }) }
/>
</div>
</div>
);
}
export default UsersList;

vue3 setup emit with function click

i want to run a method when emitting how can i get it?
When handleShow(depth is clicked), I want to run collapsed in the medhod in the setup.
or
I want to trigger the function I will write in setup
<MenuLink
:link="items"
:key="items.title"
#click.stop="handleShow(depth)"
/>
<script>
import {ref} from "vue"
import MenuLink from "./MenuLink";
export default {
name: 'MenuItems',
components: {MenuLink},
props: {
items: {type: Object, required: true},
depth: {Number},
selected: {Number},
},
data() {
return {
opensCollapsed: false
};
},
methods: {
collapsed(dep) {
console.log(dep)
}
},
setup(props, {emit}) {
const showDropdown = ref(false);
const handleShow = (depth) => {
emit('clicked', depth)
}
return {
showDropdown,
handleShow,
}
},
};
</script>
emit should only be used if you want to get an event out of your component to its parent (for example, if your component is a custom button and you want its parent to specify what would happen when clicking on it). Otherwise, you can write the code you want inside of handleShow instead of calling emit. You can also change the function name to whatever you want, just make sure it's the same inside the setup method and in the #click.stop property.
In your case (since you just console.log the result):
<MenuLink
:link="items"
:key="items.title"
#click.stop="handleShow(depth)"
/>
<script>
import {ref} from "vue"
import MenuLink from "./MenuLink";
export default {
name: 'MenuItems',
components: {MenuLink},
props: {
items: {type: Object, required: true},
depth: {Number},
selected: {Number},
},
data() {
return {
opensCollapsed: false
};
},
setup(props, {emit}) {
const showDropdown = ref(false);
const handleShow = (depth) => {
console.log(depth)
// do whatever you want here
}
return {
showDropdown,
handleShow,
}
},
};
</script>

Rendered fewer hooks than expected error in the return statement

I am trying to build a simple navbar but when I define a setResponsivness function inside my useEffect
I am getting the error Rendered fewer hooks than expected. This may be caused by an accidental early return statement. I looked at similar answers for the same but till wasn't able to fix
Here s my code
import React,{useEffect,useState} from 'react'
import {AppBar ,Toolbar, Container ,makeStyles,Button, IconButton} from '#material-ui/core'
import MenuIcon from '#material-ui/icons/Menu'
const usestyles = makeStyles({
root:{
display:'flex',
justifyContent:'space-between' ,
maxWidth:'700px'
},
menubtn:{
fontFamily: "Work Sans, sans-serif",
fontWeight: 500,
paddingRight:'79px',
color: "white",
textAlign: "left",
},
menuicon:{
edge: "start",color: "inherit",paddingLeft:'0'
}
})
const menudata = [
{
label: "home",
href: "/",
},
{
label: "About",
href: "/about",
},
{
label: "Skill",
href: "/skills",
},
{
label: "Projects",
href: "/projects",
},
{
label: "Contact",
href: "/contact",
},
];
//yet to target link for the smooth scroll
function getmenubuttons(){
const {menubtn} = usestyles();
return menudata.map(({label,href})=>{
return <Button className={menubtn}>{label}</Button>
})
}
//to display navbar on desktop screen
function displaydesktop(){
const { root } = usestyles() //destructuring our custom defined css classes
return <Toolbar ><Container maxWidth={false} className={root}>{getmenubuttons()}</Container> </Toolbar>
}
//to display navbar on mobile screen
function displaymobile(){
const {menuicon} =usestyles() ;
return <Toolbar><IconButton className={menuicon}><MenuIcon /> </IconButton></Toolbar>
}
function Navbar() {
const [state, setState] = useState({mobileview:false});
const {mobileview} = state;
useEffect(() => {
const setResponsiveness = () => {
return window.innerWidth < 900
? setState((prevState) => ({ ...prevState, mobileview: true }))
: setState((prevState) => ({ ...prevState, mobileview: false }));
};
setResponsiveness();
window.addEventListener("resize", () => setResponsiveness());
}, []);
return (
<div>
<AppBar> {mobileview?displaymobile():displaydesktop()} </AppBar>
</div>
)
}
export default Navbar;
Your problem seems to be here
{mobileview?displaymobile():displaydesktop()}
For example the displaymobile function inside uses hooks right (usestyles)? Then it means you are rendering hooks inside conditions (mobileview being condition) which is not allowed by rules of hooks.
You can fix it like this:
<div>
<AppBar> {mobileview ? <Displaymobile /> : <Displaydesktop />} </AppBar>
</div>
Also change definition of component using capital letters as that is how react refers to components. e.g.
function Displaydesktop() {
const { root } = usestyles(); //destructuring our custom defined css classes
return (
<Toolbar>
<Container maxWidth={false} className={root}>
{getmenubuttons()}
</Container>{" "}
</Toolbar>
);
}
Now we consume them as components. Probably when you used lower case letters and called those as functions in your render, react interpreted them as custom hooks, hence the warnings.

Data not showing on Firebase, Using V-data-table Vue.js

The data is not showing, I do not know how to push the value from the firebase to the v-data-table values. Here is my code.
<template>
<div class="dashboard">
<h2 class="subheading mx-5">Subject</h2>
<v-btn block color="primary mt-5" #click="enrollSubjects()">Enroll Subjects</v-btn>
<v-container class="my-5">
<template>
<v-card>
<v-card-title>
Courses
<v-spacer></v-spacer>
<v-text-field v-model="search" append-icon="search" label="Search" single-line hide-details></v-text-field>
</v-card-title>
<v-data-table v-model="selected" :headers="headers" :items="courses" show-select :single-select="singleSelect" item-key="descrip_title" :search="search">
</v-data-table>
</v-card>
</template>
</v-container>
</div>
</template>
<script>
// # is an alias to /src
import db from '#/firebase/init'
export default {
name: 'dashboard',
data(){
return{
search: '',
singleSelect: false,
subjects: [],
selected: [],
headers: [
{text: 'Control No.', value: 'controlno'},
{text: 'Course No.', value: 'courseno'},
{text: 'Descriptive Title', value: 'descrip_title'},
{text: 'Schedule(In)', value: 'schedin'},
{text: 'Schedule(Out)', value: 'schedout'},
{text: 'Room No.', value: 'roomno'},
{text: 'Days', value: 'days'},
{text: 'Units', value: 'units'}
],
courses: []
}
},
methods:{
enrollSubjects(){
if(this.selected === this.selected){
this.$swal({
title: 'No Course Selected',
text: 'Please select course/s',
type: 'error'
})
}
},
created(){
db.collection('masterlist_courses').get()
.then(snapshot => {
snapshot.forEach(doc => {
let course = doc.data()
course.id = doc.id
this.courses.push(course)
})
})
}
}
}
</script>
I am practicing in firebase and vuetify, I do not know how to push this to the value of the v-data-table. I am having hard time and its not showing anything to the datatable and also there is no error. It's not saying anything after I code the data in the firebase not displaying
You need to use one of the vue.js life cycle hook to trigger the fetch before the component is mounted.
For example the created hook can be used to "run code after an instance is created", as follows:
<script>
// # is an alias to /src
import db from '#/firebase/init'
export default {
name: 'dashboard',
data(){
return{
search: '',
singleSelect: false,
subjects: [],
selected: [],
headers: [
{text: 'Control No.', value: 'controlno'},
{text: 'Course No.', value: 'courseno'},
{text: 'Descriptive Title', value: 'descrip_title'},
{text: 'Schedule(In)', value: 'schedin'},
{text: 'Schedule(Out)', value: 'schedout'},
{text: 'Room No.', value: 'roomno'},
{text: 'Days', value: 'days'},
{text: 'Units', value: 'units'}
],
courses: []
}
},
methods:{
enrollSubjects(){
if(this.selected === this.selected){
this.$swal({
title: 'No Course Selected',
text: 'Please select course/s',
type: 'error'
})
}
}
},
created: function() {
db.collection('masterlist_courses').get()
.then(snapshot => {
snapshot.forEach(doc => {
let course = doc.data()
course.id = doc.id
this.courses.push(course)
})
})
}
}
</script>
Note that if the query to Firestore is going to take some time, you could display a spinner and hide it when the query is done, i.e. in the callback passed to then(), after snapshot.forEach().
You need to define what items should be shown. You have only defined your headers so far. Try it like this for every header you have.
<template v-slot:item.controlno="{ item }">
{{ item.controlno }}
</template>
Hope this helps =)

Resources