Issue: With the current code, when i click an item, it correctly adds the "selected" class to the clicked item, but when i click another option, the "selected" class gets removed from it and gets added to the newly clicked item.
Wanted: I want to have the selected class added to all items which have been selected, my code is below, would appreciate any help:
My Html:
<form (ngSubmit)="onSubmit()">
<div *ngFor="let event of groupSelections; let i = index;" class="row">
<div class="col-12">
<div class="row">
<div *ngFor="let team of event?.Actors; first as isFirst" class="col-6">
<div class="row">
<div *ngIf="isFirst" class="col-6">
<div>
{{ team?.ActorName }}
</div>
</div>
<div class="col-6">
<div [className]="selectedValue == team?.Players ?'selected':''">
<select (change)="getSelections(team, event, $event, team?.Players)">
<option value="none" selected disabled hidden>SELECT</option>
<option value="" *ngFor="let player of team?.Players; let j = index">
{{ player?.Name }}
</option>
</select>
</div>
</div>
<div *ngIf="!isFirst" class="col-6">
<div>
{{ team?.ActorName }}
</div>
</div>
</div>
</div>
</div>
</div>
My function:
getSelections(actors, event, selectedOption, player): any {
const selections = [];
this.selectedTeam = actors;
this.selectedTeamPlayers = actors.Players;
this.gameEvent = event;
this.selectedValue = player;
selections.push({
EventId: this.gameEvent.EventId,
ActorId: this.selectedTeam.ActorId,
EventActorId: this.selectedTeam.EventActorId,
Score: 1,
Position: 1,
PlayerPosition: this.player.Position,
PlayerPoint: this.player.Point,
});
this.playerSelections = selections;
}
My Data:
groupSelections = [
{
"PromotionId": 5,
"Events": [
{
"Actors": [
{
"ActorId": 33,
"ActorName": "Italy",
"Players": [
{
"Name": " Mattia De Sciglio (D)",
"Position": "DEFENDER",
"Point": 5
},
{
"Name": "Bryan Cristante (M)",
"Position": "MIDFIELDER",
"Point": 3
}
]
},
{
"ActorId": 34,
"ActorName": "Turkey",
"Players": [
{
"Name": " Zeki Çelik (D)",
"Position": "DEFENDER",
"Point": 5
},
{
"Name": "Ozan Tufan (M)",
"Position": "MIDFIELDER",
"Point": 3
}
]
}
]
},
{
"Actors": [
{
"ActorId": 77,
"ActorName": "Slovakia",
"Players": [
{
"Name": "Mattia Perin (G)",
"Position": "GOALKEEPER",
"Point": 10
},
{
"Name": "Bryan Cristante (M)",
"Position": "MIDFIELDER",
"Point": 3
}
]
},
{
"ActorId": 78,
"ActorName": "Sweden",
"Players": [
{
"Name": " Zeki Çelik (D)",
"Position": "DEFENDER",
"Point": 5
},
{
"Name": "Ozan Tufan (M)",
"Position": "MIDFIELDER",
"Point": 3
}
]
}
]
}
]
}
Usually you should add a selected field to your Players object. Then you can set it to true and consider it when adding the additional class.
But let's do it with a simple array first.
TS file
selectedPlayers: Array<string> = [];
// check whether the players object is in the list
isSelectedPlayer(players: any): boolean {
return this.selectedPlayers.findIndex(element => element === players) > -1;
}
getSelections(actors, event, selectedOption, player): any {
const selections = [];
this.selectedTeam = actors;
this.selectedTeamPlayers = actors.Players;
this.gameEvent = event;
// add the selection to your list, if is not in it
if (this.selectedPlayers.findIndex(element => element === player) === -1) {
this.selectedPlayers.push(player);
}
selections.push({
EventId: this.gameEvent.EventId,
ActorId: this.selectedTeam.ActorId,
EventActorId: this.selectedTeam.EventActorId,
Score: 1,
Position: 1,
PlayerPosition: this.player.Position,
PlayerPoint: this.player.Point,
});
this.playerSelections = selections;
}
HTML
<div [className]="gameEvent == event && isSelectedPlayer(team?.Players) ? 'selected':''">
Related
I was dynamically adding nested categories and subacatogories in react. I want to hide and show the sub-categories on clicking or hovering main-category. I wanted to show/hide subcatogories(mobiles, tv, laptops) on clicking Accessories and wanna show/hide Noodles on clicking groceries. Please help
My Code:
import React from "react";
function App(props) {
const categoriesList = [
{
id: "1",
name: "Accessories",
slug: "accessories",
children: [
{
id: "2",
name: "Mobiles",
slug: "mobiles",
},
{
id: "3",
name: "TV",
slug: "tv",
},
{
id: "4",
name: "Laptops",
slug: "laptops",
children: [
{
id: 5,
name: "Dell",
slug: "dell",
},
],
},
],
},
{
id: "6",
name: "Books",
slug: "books",
// children: undefined,
},
{
id: "7",
name: "Groceries",
slug: "groceries",
children: [
{
id: "8",
name: "Noodles",
slug: "noodles",
},
],
},
];
const renderCategories = (categories) => {
let myCategories = [];
for (const category of categories) {
myCategories.push(
<li className="category-list" key={category.name}>
{category.name}
{category?.children?.length > 0 ? (
<ul className="nested-category">
{renderCategories(category.children)}
</ul>
) : null}
</li>
);
}
return myCategories;
};
return (
<div className="app">
<ul className="main">{renderCategories(categoriesList)}</ul>
</div>
);
}
You need a state like categoryToBeDisplayed and then just have an onClick on the category li tag
for (const category of categories) {
myCategories.push(
<li className="category-list" key={category.name} onClick={() => setCategory(category.name)}>
{category.name}
{category?.children?.length > 0 && categoryToBeDisplayed === category.name ? (
<ul className="nested-category">
{renderCategories(category.children)}
</ul>
) : null}
</li>
);
}
And if you want multiple to be open at once just have the state accept an array and check if categoryToBeDisplayed.includes(category.name)
I am developing headless WordPress with NExtjs.
menuItems is props that contain an object. when I console.log(menuItems ) it shows output in the console similar to "const menu" but when I map "menu" it maps perfectly but when I map menuItems, the site gives me the error that it is not defined.
code under className "navi-2" is not working
<pre>
import Link from "next/link";
function NavBar({ menuItems }) {
console.log(menuItems )
const menu = {
"menuItemse": {
"edges": [
{
"node": {
"uri": "/",
"title": "home link",
"target": null,
"label": "Home"
}
},
{
"node": {
"uri": "/about-us/",
"title": null,
"target": null,
"label": "About Us"
}
},
{
"node": {
"uri": "/portfolio/",
"title": null,
"target": null,
"label": "Portfolio"
}
},
{
"node": {
"uri": "/services/",
"title": null,
"target": null,
"label": "Services"
}
},
{
"node": {
"uri": "/contact-us/",
"title": null,
"target": null,
"label": "Contact Us"
}
}
]
}
}
return(
<>
<nav className="navi">
{menu.menuItemse.edges.map(it => (
<Link href={it.node.uri}><a>{it.node.label}</a></Link>
) )}
</nav>
<nav className="navi-2">
{menuItems.menuItems.edges.map(item => (
<Link href={item.node.uri}><a>{item.node.label}</a></Link>
) )}
</nav>
</>
)
}
export default NavBar
</pre>
I am trying to retrieve data from strapi using the NextJs as the front-end. The problem is that I can't display them on the UI, but I can see them in the console.
I used Graphql for querying the data using this commend:
query {
menus(filters: {language: {code: {eq: "en"}}}) {
data {
attributes {
Entry {
title
link
}
}
}
}
}
, I got this:
{
"data": {
"menus": {
"data": [
{
"attributes": {
"Entry": [
{
"title": "home",
"link": "/home.html"
},
{
"title": "classes",
"link": "./calss.html"
},
{
"title": "events",
"link": "/events.html"
},
{
"title": "news",
"link": "/news.html"
},
{
"title": "reosurces",
"link": "./resources.html"
},
{
"title": "links",
"link": "./links.html"
}
]
}
}
]
}
}
}
and this is how the UI handled:
const mainMenuAdapter = (menuData) => {
return menuData.map(md => {
const entry = md['attributes']['Entry']
console.log('title', entry)
return {
link: entry.link,
title: entry.title,
}
})
}
I use useContext;
const { menuData } = useContext(GlobalContext)
const menus = mainMenuAdapter(menuData)
here is how the mapping is handled.
<div className="bg-green-400 relative filosofia_regular bg-grayDark flex-wrap md:flex flex-row items-end md:justify-around p-2 lg:justify-evenly text-center mx-auto w-full">
{!!menus && menus.map((menu, i) => {
return (
<div key={i}>
<Link href="/">
<a className="text-gray-100 px-2 text-sm lg:text-2xl xl:text-4xl whitespace-nowrap">
{t(menu.title)}
</a>
</Link>
{i < menus.length - 1 && (
<a className="text-white">|</a>
)}
</div>
);
})}
</div>
and here is the console.
(6) [{…}, {…}, {…}, {…}, {…}, {…}]
0:
link: "/home.html"
title: "home"
__typename: "ComponentEntryComEntry"
[[Prototype]]: Object
1: {title: 'classes', link: './calss.html', __typename: 'ComponentEntryComEntry'}
2: {title: 'events', link: '/events.html', __typename: 'ComponentEntryComEntry'}
3: {title: 'news', link: '/news.html', __typename: 'ComponentEntryComEntry'}
4: {title: 'reosurces', link: './resources.html', __typename: 'ComponentEntryComEntry'}
5: {title: 'links', link: './links.html', __typename: 'ComponentEntryComEntry'}
length: 6
[[Prototype]]: Array(0)
Can anyone please tell me what I am missing?
Thanks
TypeError: Cannot read properties of undefined (reading 'forEach')
This is an error message I get when I am trying to render OrderTable component. I struggled fixing it for a good few hours and I don't have idea what is wrong.
Other almost similar tables works fine.
const orderProducts = useSelector((state) => state.orders.order.products)
I use this structure instead of state.orders.order because from serializer I got nested data that does not works. Tried to take products from order after selector and it does not also work. Data seems to be fine, but I attach JSON anyway.
import React, { useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { getOrder } from "../../features/orders/orderSlice";
import {
useTable,
useRowSelect,
useSortBy,
useFilters,
useGlobalFilter,
} from "react-table";
import {
Table,
TableBody,
TableCell,
TableHead,
TableRow,
} from "#mui/material";
import Paper from "#mui/material/Paper";
import KeyboardArrowUpIcon from "#mui/icons-material/KeyboardArrowUp";
import KeyboardArrowDownIcon from "#mui/icons-material/KeyboardArrowDown";
import TableContainer from "#mui/material/TableContainer";
import IndeterminateCheckbox from "../Checkbox";
import ColumnFilter from "../ColumnFilter";
// import GlobalFilter from "../GlobalFilter";
const OrderTable = () => {
const dispatch = useDispatch();
useEffect(() => {
const id = window.location.pathname.split("/orders/order/").pop();
dispatch(getOrder(id));
}, []);
const loading = useSelector((state) => state.orders.loading);
const orderProducts = useSelector((state) => state.orders.order.products);
const data = React.useMemo(() => orderProducts, [orderProducts]);
const columns = React.useMemo(
() => [
{ Header: "ID", accessor: "id", Filter: ColumnFilter },
{ Header: "Nazwa", accessor: "product.title", Filter: ColumnFilter },
{ Header: "Ilość", accessor: "quantity", Filter: ColumnFilter },
{ Header: "Cena", accessor: "product.price", Filter: ColumnFilter },
{ Header: "Wartość", accessor: "total_price", Filter: ColumnFilter },
{
Header: "Zamówiony",
accessor: (d) => (d.ordered ? "Tak" : "Nie"),
Filter: ColumnFilter,
},
],
[]
);
const {
getTableProps,
getTableBodyProps,
headerGroups,
rows,
state,
setGlobalFilter,
prepareRow,
selectedFlatRows,
} = useTable(
{ columns, data },
useGlobalFilter,
useFilters,
useSortBy,
useRowSelect,
(hooks) => {
hooks.visibleColumns.push((columns) => [
// Let's make a column for selection
{
id: "selection",
// The header can use the table's getToggleAllRowsSelectedProps method
// to render a checkbox
Header: ({ getToggleAllRowsSelectedProps }) => (
<div>
<IndeterminateCheckbox {...getToggleAllRowsSelectedProps()} />
</div>
),
// The cell can use the individual row's getToggleRowSelectedProps method
// to the render a checkbox
Cell: ({ row }) => (
<div>
<IndeterminateCheckbox {...row.getToggleRowSelectedProps()} />
</div>
),
},
...columns,
]);
}
);
const { globalFilter } = state;
return (
<>
{loading ? (
"loading"
) : (
<TableContainer component={Paper} sx={{ ml: 3, mt: 2 }}>
<Table {...getTableProps()} size="small">
<TableHead>
{headerGroups.map((headerGroup) => (
<TableRow {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map((column) => (
<TableCell {...column.getHeaderProps()}>
<div {...column.getSortByToggleProps()}>
{column.render("Header")}
{column.isSorted ? (
column.isSortedDesc ? (
<KeyboardArrowUpIcon fontSize="small" />
) : (
<KeyboardArrowDownIcon fontSize="small" />
)
) : (
""
)}
</div>
<div>
{column.canFilter ? column.render("Filter") : null}
</div>
</TableCell>
))}
</TableRow>
))}
</TableHead>
<TableBody {...getTableBodyProps()}>
{rows.map((row) => {
prepareRow(row);
return (
<TableRow {...row.getRowProps()}>
{row.cells.map((cell) => {
return (
<TableCell {...cell.getCellProps()}>
{cell.render("Cell")}
</TableCell>
);
})}
</TableRow>
);
})}
</TableBody>
</Table>
</TableContainer>
)}
</>
);
};
export default OrderTable;
JSON
{
"id": 37,
"products": [
{
"id": 68,
"product": {
"id": 1,
"created": "2021-11-11T02:01:15.897446Z",
"active": true,
"title": "Kapustka",
"description": "biała",
"quantity": -143,
"price": "3.24",
"category": 1
},
"quantity": 8,
"total_price": "25.92",
"ordered": true,
"user": 1
},
{
"id": 69,
"product": {
"id": 2,
"created": "2021-11-12T17:16:43.422467Z",
"active": true,
"title": "Marchew",
"description": null,
"quantity": 10,
"price": "2.00",
"category": null
},
"quantity": 11,
"total_price": "22.00",
"ordered": true,
"user": 1
},
{
"id": 70,
"product": {
"id": 5,
"created": "2021-11-13T20:03:01.336712Z",
"active": true,
"title": "Makaron",
"description": null,
"quantity": 0,
"price": "0.00",
"category": null
},
"quantity": 1,
"total_price": "0.00",
"ordered": true,
"user": 1
},
{
"id": 71,
"product": {
"id": 6,
"created": "2021-11-13T20:03:12.384605Z",
"active": true,
"title": "Pomidor",
"description": null,
"quantity": 0,
"price": "0.00",
"category": null
},
"quantity": 1,
"total_price": "0.00",
"ordered": true,
"user": 1
}
],
"title": "Zamowienie",
"created": "2021-11-13T19:26:59.545602Z",
"value": "49.92",
"is_paid": false,
"ordered": true,
"user": 1
}
My JSON Data
{"menu": {
"id": "file",
"value": "File",
"popup": {
"menuitem": [
{"value": "New", "onclick": "CreateNewDoc()"},
{"value": "Open", "onclick": "OpenDoc()"},
{"value": "Close", "onclick": "CloseDoc()"}
]
}
}}
jQuery code:
$(document).ready(function() {
$("#Button1").click(function() {
var asd = "test";
$.get("CallBack.Aspx", { asd: asd }, function(data) {
$.each(data, function() {
})
})
})
})
I need menuitem in values how to make ?
"menuitem": [
{ "value": "New", "onclick": "CreateNewDoc()" } ]
$.getJSON() fits probably better.
After that,
$.each(data.menu.popup.menuitem, function(i, v) {
//Your code here
});