Nativescript RadDataForm convert property not working with json array - javascript

I have json array with id and name property after submiting the form I am getting NaN I want to convert converter code from typescript to Javascript
I created a Playground example
file : Data.js
{ id: 123, name: 'Zootopia' },
{ id: 217, name: 'Captain America' },
{ id: 324, name: 'The Jungle Book' }
];
export class MovieConverter {
constructor(_movies) {
this._movies = _movies;
}
convertFrom(id) {
return this._movies.filter((movie) => movie.id === id)[0].name;
}
convertTo(name) {
return this._movies.filter((movie) => movie.name === name)[0].id;
}
}
Test.vue
<template>
<Page>
<ActionBar :title="Simple">
<NavigationButton text="Back" android.systemIcon="ic_menu_back"
#tap="onNavigationButtonTap"></NavigationButton>
</ActionBar>
<StackLayout>
<Button text="Button" #tap="onSubmit" />
<RadDataForm :source="ticket" :metadata="ticketMetadata" />
</StackLayout>
</Page>
</template>
<script>
import Home from "./Home";
import {
Movies,
MovieConverter
} from "../Data";
//const movies = getMovies();
export default {
methods: {
onNavigationButtonTap() {
this.$navigateTo(Home);
}
},
mounted() {
console.log("movies", Movies);
Movies.map(Movie => {
console.log(Movie.name);
});
},
data() {
return {
ticket: {
movie: 123,
date: "2016-04-06",
time: "20:00",
type: "2D",
price: 9.5,
numberOfTickets: 2,
contactName: null,
contactPhone: null,
contactEmail: null,
agreeTerms: false
},
ticketMetadata: {
isReadOnly: false,
commitMode: "Immediate",
validationMode: "Immediate",
propertyAnnotations: [{
name: "movie",
displayName: "Movie Name",
index: 0,
editor: "Picker",
valuesProvider: Movies.map(Movie => Movie.name),
converter: new MovieConverter(Movies)
},
{
name: "date",
displayName: "Date",
index: 1,
editor: "DatePicker",
hintText: "This is a hint for you"
},
{
name: "time",
displayName: "Time",
index: 2,
editor: "TimePicker"
},
{
name: "type",
displayName: "Type",
index: 3,
editor: "SegmentedEditor",
valuesProvider: ["2D", "3D"]
},
{
name: "price",
displayName: "Price",
index: 4,
editor: "Decimal",
readOnly: true
},
{
name: "numberOfTickets",
displayName: "Number Of Tickets",
index: 5,
editor: "Stepper",
editorParams: {
minimum: 0,
maximum: 20,
step: 2
}
},
{
name: "contactName",
displayName: "Contact Name",
index: 6,
editor: "Text"
},
{
name: "contactPhone",
displayName: "Contact Phone",
index: 7,
editor: "Phone"
},
{
name: "contactEmail",
displayName: "Contact Email",
index: 8,
editor: "Email"
},
{
name: "agreeTerms",
displayName: "I Agree with Terms",
index: 9,
editor: "Switch"
}
]
}
};
},
methods: {
onSubmit() {
console.log("submit", this.ticket.movie);
}
}
};
</script>
<style>
</style>
after onSubmit() of the form I should get 'submit' 123
but getting 'submit' NaN.
I check out the documentation of converter it showing a class with 2 methods convertFrom() & convertTo() which I think is proper not understand as all the documentation is in typescript and I am using javascript.

Related

How to generate excel file using write-excel-file library when I need to map through elemenents of data

I need to generate excel report using write-excel-file library.
On simple mock data it works to me but in reality I need to provide data mapping through array of objects.
This is how array of objects looks like:
export const benefits = [
{
comment: "brak",
companyCost: 90,
luxmedType: {
package: "Indywidualny",
type: "Opieka standardowa",
cost: 0
},
persons: [
{
name: "Jan",
lastName: "Kowalski",
cooperationForm: "b2b",
type: "b2b"
}
]
},
{
comment: "nic do skomentowania",
companyCost: 50,
luxmedType: {
package: "Rodzinny",
type: "Opieka rozszerzona",
cost: 100
},
persons: [
{
name: "Tomasz",
lastName: "Michalski",
cooperationForm: "umowa o pracę",
type: "pracownik"
},
{
name: "Ewa",
lastName: "Michalska",
cooperationForm: "null",
type: "partner"
}
]
}
];
Data should be mapped through benefits array and inside persons array. I have tried firstly to map through benefits array but it does not return any values in excel. Can You please suggest how to solve it ?
import "./styles.css";
import writeXlsxFile from "write-excel-file";
import { benefits } from "./benefits";
const HEADER_ROW = [
{
value: "Name and Last Name",
fontWeight: "bold"
},
{
value: "Contract Type",
fontWeight: "bold"
},
{
value: "Employee/Partner/Kid",
fontWeight: "bold"
},
{
value: "Package Type",
fontWeight: "bold"
},
{
value: "Employee Cost",
fontWeight: "bold"
},
{
value: "300B Cost",
fontWeight: "bold"
},
{
value: "Comments",
fontWeight: "bold"
}
];
const DATA_ROW_BENEFITS = benefits.map((element) => {
return [
{
type: String,
value: "józek"
},
{
type: String,
value: "Contract Type"
},
{
type: String,
value: "Employee/Partner/Kid"
},
{
type: String,
value: "Package Type"
},
{
type: Number,
value: 50
},
{
type: Number,
value: 100
},
{
value: "Comment"
}
];
});
const data = [HEADER_ROW, DATA_ROW];
export default function App() {
const createExcelReport = async () => {
console.log("click");
await writeXlsxFile(data, {
fileName: "benefits.xlsx"
});
};
I have also prepared codesandbox so it will be easier to look and check:
https://codesandbox.io/s/thirsty-mccarthy-5b40tj?file=/src/App.js:1359-1573
If You have also other working libraries to export excel files I'm open, I tried few others but they didn't work.
thanks

How to add images in MaterialDatatable?

I'm using MaterialDatatable in react-app this is working fine but now I want to add country icons with country names so how can I add images with table value?
My Code:-
<MaterialDatatable
columns={headers}
data={items}
options={options}
/>
items is coming from below list:-
export function getHeaders() { return [
{
name: 'Username',
field: 'username',
type: 'string'
},
{
name: 'Country',
field: 'countryName',
type: 'string',
className: 'lftAlign',
},
{
name: 'Name',
field: 'fullName',
type: 'string'
}] }
Package Link:-
https://www.npmjs.com/package/material-datatable
Countries flag images will be come from below array:-
const countries = [
{
value: '1',
title: 'Afghanistan',
icon: '/flags/afghanistan.png'
},
{
value: '2',
title: 'Albania',
icon: '/flags/albania.png'
}
]
You can use customValue for that purpose:
See: https://github.com/Diaver/material-datatable
There is a sandbox example at https://codesandbox.io/s/lp8pvk1zk9?file=/index.js:0-1728:
import React from "react";
import ReactDOM from "react-dom";
import MaterialDatatable from "material-datatable";
class App extends React.Component {
render() {
const columns = [
{ name: "Name", field: "name" },
{ name: "Title", field: "title" },
{ name: "Location", field: "location" },
{ name: "Age", field: "age" },
{ name: "Salary", field: "salary" },
{
name: "Name and Title Custom Column",
field: "salary",
options: {
noHeaderWrap: true,
width: 200,
customBodyRender: (value, tableMeta, updateValue) => {
return `${value.name} (${value.title})`;
}
}
},
{
name: "Custom Render",
field: "salary2",
options: {
noHeaderWrap: true,
width: 200,
customBodyRender: (value, tableMeta, updateValue) => {
return <h4>{value.name}</h4>;
},
customValue: (value, tableMeta, updateValue) => value.name,
customSortValue: (value, tableMeta, updateValue) => value.name
}
}
];
const data = [
{
name: "Name 1",
title: "Title 1",
location: "Location 1",
age: 30,
salary: 10
},
{
name: "Name 2",
title: "Title 2",
location: "Location 2",
age: 31,
salary: 11
}
];
const options = {
filterType: "dropdown",
responsive: "scroll"
};
return (
<MaterialDatatable
title={"ACME Employee list"}
data={data}
columns={columns}
options={options}
/>
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));
Note that the relevant part is
{
name: "Custom Render",
field: "salary2",
options: {
noHeaderWrap: true,
width: 200,
customBodyRender: (value, tableMeta, updateValue) => {
return <h4>{value.name}</h4>;
},
customValue: (value, tableMeta, updateValue) => value.name,
customSortValue: (value, tableMeta, updateValue) => value.name
}
}
Note that we have a customValue as
customValue: (value, tableMeta, updateValue) => value.name,
You could have something like
customValue: (value, tableMeta, updateValue) => value.icon,
Yes, I know, this only displays the relative path. But, instead of that, you can change this to return something like
`<img src="${value.icon}">`
the above is just a dummy example. You can replace it with a more React-like code and you can even put there some components.

How to update nested object array in js?

I need to modify component state which has inner array objects. There is no problem with modifying object array but I'd like to update inner object array value which has action format. It doesn't update the action value as "No Action Needed".
What's the wrong with that map() functions?
Thanks in advance.
let example_response = {
data: [
{
details: [
{
format: "date",
value: "2020-04-29T15:03:44.871Z",
title: "Date"
},
{
format: "action",
value: "-",
title: "Action"
}
],
id: 13409,
isSelected:true
}, {
details: [
{
format: "date",
value: "2019-04-29T15:03:44.871Z",
title: "Date"
},
{
format: "action",
value: "-",
title: "Action"
}
],
id: 13409,
isSelected:false
}
]
};
const newList = example_response.data.map((item) => {
if (item.isSelected) {
item.details.map((elem) => {
if (elem.format === "action") {
const updatedElem = {
...elem,
value: "No Action Needed"
};
return updatedElem;
}
});
}
return item;
});
console.log(newList);
I found 2 problems:
You are not modifying item.details (you are just mapping it).
You only return updatedElem when elem.format === "action" but you're returning anything otherwise
Try
let example_response = {
data: [{
details: [{
format: "date",
value: "2020-04-29T15:03:44.871Z",
title: "Date"
},
{
format: "action",
value: "-",
title: "Action"
}
],
id: 13409,
isSelected: true
}, {
details: [{
format: "date",
value: "2019-04-29T15:03:44.871Z",
title: "Date"
},
{
format: "action",
value: "-",
title: "Action"
}
],
id: 13409,
isSelected: false
}]
};
const newList = example_response.data.map((item) => {
if (item.isSelected) {
item.details = item.details.map((elem) => {
if (elem.format === "action") {
elem.value = "No Action Needed";
}
return elem;
});
}
return item;
});
console.log(newList);
Since you're already creating a new array with the top level map method, you can use forEach and assign the value.
let example_response = {
data: [
{
details: [
{
format: "date",
value: "2020-04-29T15:03:44.871Z",
title: "Date"
},
{
format: "action",
value: "-",
title: "Action"
}
],
id: 13409,
isSelected:true
}, {
details: [
{
format: "date",
value: "2019-04-29T15:03:44.871Z",
title: "Date"
},
{
format: "action",
value: "-",
title: "Action"
}
],
id: 13409,
isSelected:false
}
]
};
const newList = example_response.data.map((item) => {
if (item.isSelected) {
item.details.forEach((elem) => {
if (elem.format === "action") {
elem.value = "No Action Needed";
}
});
}
return item;
});
console.log(newList);
let example_response = {
data: [{
details: [{
format: "date",
value: "2020-04-29T15:03:44.871Z",
title: "Date"
},
{
format: "action",
value: "-",
title: "Action"
}
],
id: 13409,
isSelected: true
},
{
details: [{
format: "date",
value: "2019-04-29T15:03:44.871Z",
title: "Date"
},
{
format: "action",
value: "-",
title: "Action"
}
],
id: 13409,
isSelected: false
}
]
};
const newList = example_response.data.map(item => item.isSelected
? item.details.map(elem => elem.format === "action"
? ({ ...elem, value: "No Action Needed" })
: elem)
: item.details);
console.log(newList);
Your code does not return a modified item, it just maps over the details when the item is selected. Make sure you are returning something in else clauses too. Here's an example using shorthand notation:
const elementUpdater = (element) => element.format === 'action' ? {...element, value: 'No action needed'} : element
const itemDetailsUpdater = (item) => item.isSelected ? item.details.map(elementUpdater) : item
example_response.data.map(itemDetailsUpdater)
Which yields:
[
[
{
"format": "date",
"value": "2020-04-29T15:03:44.871Z",
"title": "Date"
},
{
"format": "action",
"value": "No action needed",
"title": "Action"
}
],
{
"details": [
{
"format": "date",
"value": "2019-04-29T15:03:44.871Z",
"title": "Date"
},
{
"format": "action",
"value": "-",
"title": "Action"
}
],
"id": 13409,
"isSelected": false
}
]

How to get and link nested value to field passing columns to Material Table

I'm trying to create a table and I have nested data like this:
[{
id: 24,
name: "DANIEL TSUTOMU OBARA",
number: "134",
phone: "11111111111",
rg: "4034092666",
EmployeeStatus: {
createdAt: "2019-08-07T14:38:52.576Z"
description: "Documentos rejeitados"
id: 3
updatedAt: "2019-08-07T14:38:52.576Z"
},
Sector: {
id: 2,
name: "Controladoria"
}
}]
And have this structure columns table:
columns: [
{ title: "Nome", field: "name" },
{ title: "CPF", field: "cpf" },
{ title: "Função", field: "FunctionId", lookup: {} },
{
title: "Setor",
field: "SectorId",
lookup: {}
},
{
title: "Status",
field: "EmployeeStatus", <------- I want to get description here
editable: "never"
}
],
Then, I need to pass these columns into my Material-table like this:
<MaterialTable
columns={state.columns}
data={state.data}
title=""
icons={tableIcons}
editable={{
onRowAdd: newData => createInstructor(newData),
onRowUpdate: async (newData, oldData) =>
updateInstructor(newData, oldData),
onRowDelete: oldData => deleteInstructor(oldData)
}}
/>
So, how I can do that access nested data into column field?
Thanks!
Please find the below solution.
I am expecting the data to have other objects too, so finding the first object with the key available.
let data = [{
id: 24,
name: "DANIEL TSUTOMU OBARA",
number: "134",
phone: "11111111111",
rg: "4034092666",
EmployeeStatus: {
createdAt: "2019-08-07T14:38:52.576Z",
description: "Documentos rejeitados",
id: 3,
updatedAt: "2019-08-07T14:38:52.576Z"
},
Sector: {
id: 2,
name: "Controladoria"
}
}]
let columns = [
{ title: "Nome", field: "name" },
{ title: "CPF", field: "cpf" },
{ title: "Função", field: "FunctionId", lookup: {} },
{
title: "Setor",
field: "SectorId",
lookup: {}
},
{
title: "Status",
field: "EmployeeStatus",
editable: "never"
}
];
let columnToUpdate = columns.find(obj => obj.title==="Status"); //find the column in columns array
let desc = data.find(obj => Object.keys(obj).includes('EmployeeStatus')).EmployeeStatus.description; // get description
columnToUpdate.field = desc; // mutate the object
console.log(columns);
I just decided to use lookup functionality and solve in this way for now.
const [state, setState] = useState({
columns: [
{ title: "ID", field: "id", editable: "never" },
{ title: "Nome", field: "name" },
{ title: "CPF", field: "cpf" },
{ title: "Função", field: "FunctionId", lookup: {} }, // 3
{
title: "Setor",
field: "SectorId",
lookup: {}
}, // 4
{
title: "Status",
field: "EmployeeStatusId",
lookup: {},
editable: "never"
}, // 5
]});
....
await api
.get(`/employee-status`)
.then(result => {
status = formatSectors(state, result, 5);
})
.....
const formatSectors = (state, result, position) => {
let columns = state.columns;
const indexColumnSector = 4;
columns[position].lookup = result.data.rows.reduce(
(accumulator, currentValue) => {
accumulator[currentValue.id] =
position === indexColumnSector
? currentValue.name
: currentValue.description;
return accumulator;
},
{}
);
return columns;
};

add and remove item in array on click reactjs

I'm working on a simple table using reactjs and ant design.
My plan is to add and remove a new item on the list on button click.
My problem is I don't know how to do that.
I tried to follow this thread but no luck.
Hope you understand me.
Thanks.
sample code
function remove() {
console.log("remove");
}
function add() {
console.log("add");
}
const columns = [
{
title: "Num",
dataIndex: "num"
},
{
title: "Name",
dataIndex: "name"
},
{
title: "Age",
dataIndex: "age"
},
{
title: "Address",
dataIndex: "address"
}
];
const data = [
{
key: "1",
num: 1,
name: "John Brown",
age: 32,
address: "New York No. 1 Lake Park"
},
{
key: "2",
num: 2,
name: "Jim Green",
age: 42,
address: "London No. 1 Lake Park"
},
{
key: "3",
num: 3,
name: "Joe Black",
age: 32,
address: "Sidney No. 1 Lake Park"
}
];
<Table pagination={false} columns={columns} dataSource={data} />
<Button type="primary" onClick={add}>
add
</Button>
<Button type="danger" onClick={remove}>
remove
</Button>
You need to use react state. State holds the data, when you want to add or remove, update this state and react with re-render the table.
I have updated your code. On click of add a new random row is added. On click of remove last row is removed.
CodeSandbox
import React from "react";
import ReactDOM from "react-dom";
import "antd/dist/antd.css";
import "./index.css";
import { Table, Button } from "antd";
function remove() {
console.log("remove");
}
const columns = [
{
title: "Num",
dataIndex: "num"
},
{
title: "Name",
dataIndex: "name"
},
{
title: "Age",
dataIndex: "age"
},
{
title: "Address",
dataIndex: "address"
}
];
let data = [
{
key: "1",
num: 1,
name: "John Brown",
age: 32,
address: "New York No. 1 Lake Park"
},
{
key: "2",
num: 2,
name: "Jim Green",
age: 42,
address: "London No. 1 Lake Park"
},
{
key: "3",
num: 3,
name: "Joe Black",
age: 32,
address: "Sidney No. 1 Lake Park"
}
];
export default class MyTable extends React.Component {
constructor(props) {
super(props);
this.state = {
data: data
};
}
add = () => {
var row = {
key: "99",
num: 99,
name: "I am New",
age: 32,
address: "New Address"
};
var newStateArray = [...this.state.data];
newStateArray.push(row);
this.setState(() => {
return {
data: newStateArray
};
});
}
remove = () => {
var newStateArray = [...this.state.data];
if(newStateArray.length > 1) {
newStateArray.pop();
}
this.setState(() => {
return {
data: newStateArray
};
});
}
render() {
return (
<div>
<Table
pagination={false}
columns={columns}
dataSource={this.state.data}
/>
<Button type="primary" onClick={this.add}>
add
</Button>
<Button type="danger" onClick={this.remove}>
remove
</Button>
</div>
);
}
}
ReactDOM.render(<MyTable />, document.getElementById("container"));

Categories

Resources