React Dynamic Table not showing in Knowckout project - reactjs

i have been able to successfully integrate react components in my durandal/knockout application. I have managed to show data in a graph but i cant seem to show the data in my react table. I get the following JSON dynamic data :
{
"Level": 1,
"Label": "Level 1",
"Qualification": "≥ 100 points",
"BBBEERecognitionLevel": "135%",
"LevelMet": false,
"Color": "whitesmoke"
},
Now the data shows in my console so i know i am getting the Json data, here is my Knockout code:
index.html
<bee-data-Table data-bind="attr: { data: ReactBeeLevelTable }" />
index.js
self.ReactBeeLevelTable = ko.observable();
var length = levels.length;
for (var i = 0; i < length; i++) {
var levelItem = levels[i];
levelItem.LevelMet = levelItem.Level === recognisedLevel;
levelItem.Color = levelItem.LevelMet ? reveresedColours[i].color : defaultTableRowColor;
var levelCompare = getCompareValueFromLevel(levelItem.Level);
var recognisedLevelCompare = getCompareValueFromLevel(recognisedLevel);
if (levelCompare <= recognisedLevelCompare) {
var chartIndex = ConvertLevelToIndex(levelItem.Level);
dataset.backgroundColor[chartIndex] = defaultChartBackgroundColor;
}
}
self.ReactBeeLevelTable(JSON.stringify(levels));
And this is my react datatable.js
import React, { Component } from 'react';
import { Table } from '#react-pakistan/react-commons-collection/table';
const RenderRow = (props) =>{
return props.keys.map((key, index)=>{
return <td key={props.data[key]}>{props.data[key]}</td>
})
}
export class Example extends Component {
constructor(props) {
super(props)
this.getHeader = this.getHeader.bind(this);
this.getRow= this.getRow.bind(this);
this.getKeys=this.getKeys.bind(this);
}
getKeys = function() {
return Object.keys(this.props.data[0]);
}
getHeader = function() {
var keys = this.getKeys();
return keys.map((key,index)=> {
return <th key={key}>{key.toUpperCase()}</th>
})
}
getRow = function () {
var items = this.props.data;
var keys = this.getKeys();
return items.map((row,index) => {
return <tr key={index}><RenderRow key={index} data={row} keys={keys}/></tr>
})
}
render () {
return (
<div>
<Table>
<thead>
<tr>
<th>B-BBEE Recognition Level</th>
</tr>
<tr>
<th>{this.getHeader()}</th>
</tr>
</thead>
<tbody>
<tr> {this.getRow()} </tr>
</tbody>
</Table>
</div>
);
}
}
and here is my Datatable.Story.js
import React from 'react';
import { storiesOf } from '#storybook/react';
import { Example } from './DataTable';
const TableElements = [{
"Level": 1,
"Label": "Level 1",
"Qualification": "≥ 100 points",
"BBBEERecognitionLevel": "135%",
"LevelMet": false,
"Color": "whitesmoke"
}]
storiesOf('Table Examples', module)
.add('Priority Element', () => (
<Example data={TableElements} title={"Points Available/Earned"}/>)
);
and here is my index,js
import { register } from 'web-react-components';
register(Example,'bee-data-Table',['data'],{}, { useShadowDOM: false });
So the Table shows with hard coded data in my react project but when i try to switch out the data with dynamic data in my durandal/knockout project, it doesnt seem to show

After some investigation i found that when you register a component, it is case sensitive, so if you look in my index.jsfile i have this line of code:
register(Example,'bee-data-Table',['data'],{}, { useShadowDOM: false });
Which is incorrect, the correct way to register a component is like this:
register(Example,'bee-data-table',['data'],{}, { useShadowDOM: false });

Related

React convert timestamp to date time inside ".map" function

I am building a table that fetches data from a json API. The API gives measurments on electricity power flow between diffrent countries, example:
GetFlow.json
[
{
"OutAreaElspotId": "DE",
"InAreaElspotId": "SE4",
"Value": -615,
"MeasureDate": 1646123700000
},
{
"OutAreaElspotId": "DK1",
"InAreaElspotId": "DE",
"Value": 1211.7925,
"MeasureDate": 1646123700000
},
{
"OutAreaElspotId": "DK1",
"InAreaElspotId": "NL",
"Value": 699.8785,
"MeasureDate": 1646123700000
}
]
I have managed to display the data in a HTML table:
My problem is that the Measure Date field is in seconds and not a real date and time. It is impossible for the usewr of the table to know what it means..
My code is as following:
PhysicalFlow.js
import React from 'react';
import axios from 'axios';
export default class PhysicalFlow extends React.Component {
state = {
flows: []
}
componentDidMount() {
let config = {
headers: {
Accept: 'application/json',
'Access-Control-Allow-Origin': '*',
}
}
let data = {
'HTTP_CONTENT_LANGUAGE': 'no',
}
axios.get('http://localhost:8010/proxy/restapi/PhysicalFlowMap/GetFlow', data, config)
.then(res => {
const flows = res.data;
this.setState({ flows });
})
};
render() {
return (
<table className="hor-zebra">
<thead>
<tr>
<th>
<span>Area</span>
</th>
<th>
<span>To</span>
</th>
<th>
<span>Measure Date</span>
</th>
<th>
<span>Value</span>
</th>
</tr>
</thead>
<tbody>
{
this.state.flows
.map(flow =>
<tr key={flow.InAreaElspotId}>
<td><span>{flow.InAreaElspotId}</span></td>
<td><span>{flow.OutAreaElspotId}</span></td>
<td><span>{flow.MeasureDate}</span></td>
<td><span>{flow.Value}</span></td>
</tr>
)
}
</tbody>
</table>
)
};
};
Now I have found the following code for converting data:
var t = new Date();
t.setSeconds( 1370001284 );
var formatted = moment(t).format("dd.mm.yyyy hh:MM:ss");
But I am unsure where I can place that code. I tried to put it into the .map function like this but it failed:
{
this.state.flows
.map(flow =>
var t = new Date();
t.setSeconds( flow.MeasureDate );
var measureDateSaying = moment(t).format("dd.mm.yyyy hh:MM:ss");
<tr key={flow.InAreaElspotId}>
<td><span>{flow.InAreaElspotId}</span></td>
<td><span>{flow.OutAreaElspotId}</span></td>
<td><span>{measureDateSaying}</span></td>
<td><span>{flow.Value}</span></td>
</tr>
)
}
That's correct. You just missed the brackets and the return statement.
this.state.flows
.map(flow => {
var t = new Date();
t.setSeconds( flow.MeasureDate );
var measureDateSaying = moment(t).format("dd.mm.yyyy hh:MM:ss");
return (
<tr key={flow.InAreaElspotId}>
<td><span>{flow.InAreaElspotId}</span></td>
<td><span>{flow.OutAreaElspotId}</span></td>
<td><span>{measureDateSaying}</span></td>
<td><span>{flow.Value}</span></td>
</tr>
);
}
)
Refer: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions#comparing_traditional_functions_to_arrow_functions
I suppose you forgot to add a block inside map, so you can do more stuff in it:
this.state.flows.map((flow) => {
var t = new Date();
t.setSeconds( flow.MeasureDate );
var measureDateSaying = moment(t).format("dd.mm.yyyy hh:MM:ss");
return (
<tr key={flow.InAreaElspotId}>
<td><span>{flow.InAreaElspotId}</span></td>
<td><span>{flow.OutAreaElspotId}</span></td>
<td><span>{measureDateSaying}</span></td>
<td><span>{flow.Value}</span></td>
</tr>
)
}

Why when i try run this code in reactjs, its always output wrong total number

i still newbie in reactjs, and i try to build a some project. this project its to display any product price and stock, but here this problem.
i try to sum this number to get a total price in my product in reactjs, but the output always like this. how to fix that...
import React from "react";
import { nanoid } from "nanoid";
import calc from "./calc";
export default class TableData extends React.Component {
constructor(props) {
super(props);
}
render() {
let arr = []
const {
data,
} = this.props;
const {
location, proformaItem,
} = data;
proformaItem.forEach((item) => {
const parseStock = JSON.parse(item.product_stock);
parseStock.forEach((stock) => {
let total = 0
if (stock[1] !== undefined) {
total += Number(stock[1]);
}
if (stock[5] !== undefined) {
total += Number(stock[5])
}
arr.push(total);
})
})
console.log(arr);
return (
<>
{
proformaItem.map((item, index) => {
const parseStock = JSON.parse(item.product_stock);
const parseItem = JSON.parse(item.items);
return (
<tr key={nanoid(12)}>
<td key={nanoid(12)}>{parseStock.map((key) => key[1])}</td>
<td key={nanoid(12)}>{parseStock.map((key) => key[3])}</td>
<td key={nanoid(12)}>{parseStock.map((key) => key[5])}</td>
<td key={nanoid(12)}>{item.categoryDescription}</td>
<td key={nanoid(12)}>{item.productDescription}</td>
<td key={nanoid(12)}>{
parseStock.map((item) => {
if (item[1] !== undefined && item[5] !== undefined) {
console.log(calc(item[1], item[5]));
}
})
}
</td>
<td key={nanoid(12)}>1</td>
<td key={nanoid(12)}>{parseItem.map((key) => key['qty'])}</td>
</tr>
)
})
}
</>
)
}
}
here's my data in json
{
"proformaItem": [
{
"product_id": "1852",
"productDescription": "Charcoal Size M",
"categoryDescription": "7200 Premium Tee",
"product_stock": "[{\"1\": 272}, {\"3\": 5328}, {\"5\": 177}]",
"items": "[{\"qty\": 1, \"productId\": 1852, \"proformaInfoId\": 556745, \"proformaItemId\": 2679283}]"
},
{
"product_id": "1801",
"productDescription": "Black Size S",
"categoryDescription": "7200 Premium Tee",
"product_stock": "[{\"1\": 745}, {\"3\": 30744}, {\"5\": 273}]",
"items": "[{\"qty\": 1, \"productId\": 1801, \"proformaInfoId\": 556745, \"proformaItemId\": 2679284}]"
},
]
}
enter image description here
The problem is you changing arr array in the render method, it means it pushes every time the component renders, that's why you are getting unstable results. To avoid this, you could move this logic
proformaItem.forEach((item) => {
const parseStock = JSON.parse(item.product_stock);
parseStock.forEach((stock) => {
let total = 0
if (stock[1] !== undefined) {
total += Number(stock[1]);
}
if (stock[5] !== undefined) {
total += Number(stock[5])
}
arr.push(total);
})
})
to componentDidMount() callback, for example.
Also you shouldn't use key={nanoid(12)}, because it creates the new keys every time it renders, but key should be strong and stable. It's better to use your product it: key={item.product_id}
UPD: if you want just to sum up your total, you don't need to use arr at all, you could use just total:
let total = 0
proformaItem.forEach((item) => {
const parseStock = JSON.parse(item.product_stock);
parseStock.forEach((stock) => {
if (stock[1] !== undefined) {
total += Number(stock[1]);
}
if (stock[5] !== undefined) {
total += Number(stock[5])
}
})
})
console.log(total)

How do I match IDs in ReactJS

Hello i'm building React web application that has CRUD for "Fleet car manager". I'm using axios libraries to get/post requests to and from my api controller written in Spring Boot. I've builded Table where i want to render data i got from 2 axios get methods /car Data from /car and /company Data from /company.
This is how i render data from /car
{this.state.cars.map(car =>
<tr key={car.idCar}>
<td>{car.carBrand}</td>
<td>{car.carModel}</td>
<td>{car.carManufactureYear}</td>
<td>{car.carType}</td>
<td>{car.engineCapacity}</td>
<td>{car.enginePower}</td>
<td>{car.plateNumber}</td>
<td>{car.id_company}</td>
<td styles="text-align: center, display: inline-block">
Works just fine Result
Now i want to replace this car.id_company with name of company which i got from axios.get(localhost:8080/company)
Any tips how to do this?
After you have get the info from /company, just make an object by using reduce to store the mapping info.
const mapping = res.reduce((idNameMapping, elem) => {
idNameMapping[id] = elem.name
return idNameMapping
} , {})
{this.state.cars.map(car =>
//more on top
<td>{mapping[car.id_company]}</td>
// more down below
Yes you can achieve it by creating a function, you need to pass a value and return filtered first data to get the name.
import React, { useState } from 'react';
const MyComponent = () => {
const [company, setCompany] = useState([
{
idCompany: 1,
name: "xyz",
},
{
idCompany: 2,
name: "Abc",
}
]);
const [car, setCar] = useState([
{
idCar: 1,
id_company: 2,
name: "A"
},
{
idCar: 2,
id_company: 1,
name: "B"
}
])
// filter company name and get data from frist data
const companyName = (id) => {
let tempCompany = company.filter((c) => {
return c.idCompany === id
})
console.log(tempCompany[0]);
return tempCompany[0].name;
}
return (
<table>
<tr>
<th>Car name</th>
<th>Company</th>
</tr>
{car.map((item, index) => {
return (
<tr key={index}>
<td>{item.name}</td>
<td>{companyName(item.id_company)}</td>
</tr>
)
})}
</table>
)
}
export default MyComponent

React.js: Unable to access object attribute within state object

I am working on a finance tracker. Eventually, the finance tracker will be able to access an account in the user's bank account, pull every transaction, and the user will be able to add transactions as future projections. The idea is to give the user the ability to run financial projections/scenarios using the most recent checking/saving account information in the user's bank account(s).
I am working on a "running total" column which takes the amount found in transactionData.amount and will add transactionData.amount to startBal if this is the "zero" index. Otherwise, it will use the numbers found in the previous index for transactionData.runningTotal and add to the value found in the current index for transactionData.amount.
In either case, the new calculation should be added to the current index for transactionData.runningTotal. I am essentially mimicking what an online transaction detail would, in the event that the bank does not provide this data already.
Here is the parent component.
import React, { Component } from "react";
import TransactionSearch from "./transactionSearch.js";
import PendingTransactions from "./pendingTransactions.js";
import Transactions from "./transactions.js";
class CheckingAccount extends Component {
state = {
startBal: 1000,
pendingTransData: [
{ id: 0, date: "1/1/2020", transaction: "gas", amount: -25.45 },
{ id: 1, date: "1/2/2020", transaction: "cell phone", amount: -127.35 },
{ id: 2, date: "1/3/2020", transaction: "car payment", amount: -303.97 }
],
transactionData: [
{
id: 0,
date: "1/1/2020",
transaction: "gas",
amount: -35.45,
runningTotal: null
},
{
id: 1,
date: "1/2/2020",
transaction: "cell phone",
amount: -227.35,
runningTotal: null
},
{
id: 2,
date: "1/3/2020",
transaction: "car payment",
amount: -403.97,
runningTotal: null
}
]
};
addRunningTotal() {
let { transactionData, startBal } = this.state;
console.log(transactionData);
transactionData.map((el, i) => {
console.log("in map function");
if (el[i] === 0) {
return (el[i].runningTotal = el[i].amount + startBal);
} else if (el[i] > 0) {
return (el[i].runningTotal = el[i - 1].amount + el[i].amount);
}
});
console.log("out of map function");
console.log("start Balance: ", startBal);
console.log("amount: ", transactionData[0].amount);
console.log("running total: ", transactionData[0].runningTotal);
this.setState({ transactionData: transactionData, startBal: startBal });
}
componentDidMount() {
this.addRunningTotal();
}
render() {
let pendTransData = (
<div>
<h1>PendingTransactions</h1>
<table>
<tr>
<th>Date</th>
<th>Transaction</th>
<th>Amount</th>
</tr>
</table>
{this.state.pendingTransData.map((pendingTransData, index) => {
return (
<PendingTransactions
key={pendingTransData.id}
date={pendingTransData.date}
transaction={pendingTransData.transaction}
amount={pendingTransData.amount}
/>
);
})}
</div>
);
let transData = (
<div>
<h1>Transaction Component</h1>
<table>
<tr>
<th>Date</th>
<th>Transaction</th>
<th>Amount</th>
<th>Running Total</th>
</tr>
</table>
{this.state.transactionData.map((transactionData, index) => {
return (
<Transactions
key={transactionData.id}
date={transactionData.date}
transaction={transactionData.transaction}
amount={transactionData.amount}
runningTotal={transactionData.runningTotal}
/>
);
})}
</div>
);
return (
<div className="App">
<h1> Checking Account</h1>
<TransactionSearch />
{pendTransData}
{transData}
</div>
);
}
}
export default CheckingAccount;
Here is the child component where the data should appear.
import React from "react";
function Transactions(props) {
return (
<tr>
<td>{props.date} </td>
<td>{props.transaction}</td>
<td>{props.amount}</td>
<td>{props.runningTotal}</td>
</tr>
);
}
export default Transactions;
First, runningTotal attribute does not render in the component. I expected to see a column with the new data in the runningTotal attribute.
In addRunningTotal, It looks like it's how you've used map. In map((el, i) => {}), el is a reference to the current iteration's value so where you've used el[i] (undefined), you wanted to use just el.
You also only need to use i (index) in your if statement.
This should do the trick (keeping reference to the previous value):
let prevAmount, running;
transactionData.map((el, i) => {
if (i === 0) {
running = el.runningTotal = el.amount + startBal;
prevAmount = el.amount;
return running;
} else if (i > 0) {
running = el.runningTotal = prevAmount + el.amount;
prevAmount = el.amount;
return running;
}
});

How to pass down checkbox values from an iterating table row to an Array in Vue?

I am getting some data from Database and pass it to the <tbody> by looping through it's rows. The rows are within a child component while the <tbody> imports them:
<template>
<tr>
<td>{{id}}</td>
<td>{{indId}}</td>
<td><input type="checkbox" :value="id" v-model="values">...</td>
</tr>
</template>
<script>
import { mapActions } from 'vuex'
export default {
data() {
return {
values: []
}
},
props: {
id: {
type: String,
reuired: true
},
indId: {
type: String,
reuired: true
},
methods: {
...mapActions([
'selectValues'
])
},
beforeUpdate(){
this.selectValues(this.values)
}
}
</script>
The "id" is unique and should be therefore representation of checked rows (checkboxes) in the "values" Array. Then am saving "values" in Vuex through mutating the action in the beforeUpdate() Lifecycle Hook and define a getter for it to be able to use this state everywhere in my app. On the other hand I am importing this child component and passing Data to it from the Array "tableBody". Just like this:
<template>
<table class="data-table">
<tbody>
<tableBody
v-for="body in tableBody" :key="body.id"
:id="body.id"
:indId="body.ind_id"
/>
</tbody>
</table>
</template>
<script>
import tableBody from './TableParts/TableBody'
export default {
components: {
tableBody
},
props: {
tableBody: {
type: Array,
required: true
}
}
}
</script>
And here my State, mutation, action, and getter from my store.js file:
import Vuex from "vuex";
import axios from "axios";
const createStore = () => {
return new Vuex.Store({
state: {
selectedValues: []
},
mutations: {
selectValues(state, payload){
state.selectedValues = payload;
}
},
actions: {
selectValues({commit}, payload){
commit('selectValues',payload)
}
},
getters: {
selectedValues(state){
return state.selectedValues;
}
}
});
};
export default createStore;
The problem is, all this things just save the value of "id" at the actual row in the "values" Array. If I've checked five rows then is the "values" an Array of length 1 with a value of last checked row. But what I need is to fill this Array with the values of all checked rows.
I have seen a few examples where it works perfect through iterating <li> in <ul>. Maybe it depends on html Tags I am using?
It would be great to know what I am doing wrong and how I can fix it.
values in your tableBody component is local data, it will not be share between row.
I saw you want to save data to vuex, you might want to implement as below:
<template>
<tr>
<td>{{id}}</td>
<td>{{indId}}</td>
<td><input type="checkbox" :value="id" :checked="isSelected" #click="toggleValue">...</td>
</tr>
</template>
<script>
import { mapActions, mapState } from 'vuex'
export default {
props: {
id: {
type: String,
reuired: true
},
indId: {
type: String,
reuired: true
},
methods: {
...mapActions([
'selectValues',
'deselectValues'
]),
toggleValue() {
if (!this.isSelected) {
this.selectValues(this.id)
} else {
this.deselectValues(this.id)
}
}
},
computed: {
...mapState(['selectedValues']),
isSelected () {
return this.selectedValues && this.selectedValues.includes(this.id)
}
}
</script>
To store all checked row, in your mutations, you need to concat array, instead of reassigned it:
selectValues(state, payload){
state.selectedValues = state.selectedValues.concat([payload])
}
deselectValues (state, payload) {
state.selectedValues = state.selectedValues.filter(item => item !== payload)
}

Resources