Convert React class component to React Hook - reactjs

Im trying to convert the following code to react hook component, but I don't understand how to convert the onOrderChange and the consts in the render parts to react hooks, how do I go about this? My goal is to have a drag and drop-able react checkbox tree component but I'm unable to convert the drag and drop part to react hooks, the other parts are in react hooks.
import React from 'react';
import CheckboxTree from 'react-checkbox-tree-reorderable';
const nodesData = './data.json'
class BasicExample extends React.Component {
state = {
nodes: nodesData,
checked:[],
expanded: [],
};
constructor(props) {
super(props);
this.onCheck = this.onCheck.bind(this);
this.onExpand = this.onExpand.bind(this);
}
onCheck(checked) {
this.setState({ checked });
}
onExpand(expanded) {
this.setState({ expanded });
}
onOrderChange = (orderedNodes) => {
this.setState({
nodes: orderedNodes,
});
}
render() {
const { onOrderChange, state } = this;
const { checked, expanded, nodes } = state;
return (
<CheckboxTree
checked={checked}
expanded={expanded}
iconsClass="fa5"
nodes={nodes}
onCheck={this.onCheck}
onExpand={this.onExpand}
orderable
onOrderChange={onOrderChange}
/>
);
}
}
export default BasicExample;
This is my data.json file
[
{
"value": "polygon",
"label": "Polygon",
"type": "parent",
"children": [
{
"value": "ward",
"label": "Ward",
"type": "fill",
"source": {
"type": "geojson",
"data": "/Ward.json"
},
"id": "ward",
"paint": {
"fill-color": "red",
"fill-opacity": 0.2
},
"layout": {
"visibility": "none"
},
"filter": [
"all"
]
},
{
"value": "zone",
"label": "Zone",
"type": "fill",
"source": {
"type": "geojson",
"data": "/Zone.json"
},
"id": "zone",
"paint": {
"fill-color": "blue",
"fill-opacity": 0.2
},
"layout": {
"visibility": "none"
},
"filter": [
"all"
]
}
]
},
{
"value": "line",
"label": "Line",
"type": "parent",
"children": [
{
"value": "path",
"label": "Path",
"type": "parent",
"children": [
{
"value": "roads",
"label": "Roads",
"type": "line",
"source": {
"type": "geojson",
"data": "/Roads.json"
},
"id": "roads",
"paint": {
"line-color": "orange"
},
"layout": {
"visibility": "none"
},
"filter": [
"all"
]
},
{
"value": "footpaths",
"label": "Footpaths",
"type": "line",
"source": {
"type": "geojson",
"data": "/Footpaths.json"
},
"id": "footpaths",
"paint": {
"line-color": "pink"
},
"layout": {
"visibility": "none"
},
"filter": [
"all"
]
}
]
},
{
"value": "drainage",
"label": "Drainage",
"type": "parent",
"children": [
{
"value": "waste",
"label": "Waste",
"type": "line",
"source": {
"type": "geojson",
"data": "/Waste.json"
},
"id": "waste",
"paint": {
"line-color": "brown"
},
"layout": {
"visibility": "none"
},
"filter": [
"all"
]
},
{
"value": "storm",
"label": "Storm",
"type": "line",
"source": {
"type": "geojson",
"data": "/Storm.json"
},
"id": "storm",
"paint": {
"line-color": "green"
},
"layout": {
"visibility": "none"
},
"filter": [
"all"
]
}
]
}
]
}
]

Refer this and go through the code below..
https://olinations.medium.com/10-steps-to-convert-a-react-class-component-to-a-functional-component-with-hooks-ab198e0fa139
import React, { useState } from "react";
import CheckboxTree from "react-checkbox-tree-reorderable";
const nodesData = "./data.json";
const BasicExample = () => {
const [checked, setChecked] = useState("");
const [expanded, setExpand] = useState("");
const [nodes, setOrderNodes] = useState(nodesData);
const onCheck = (checked) => setChecked(checked);
const onExpand = (expanded) => setExpand(expanded);
const onOrderChange = (orderedNodes) => setOrderNodes(orderedNodes);
return (
<CheckboxTree
checked={checked}
expanded={expanded}
iconsClass="fa5"
nodes={nodes}
onCheck={onCheck}
onExpand={onExpand}
orderable
onOrderChange={onOrderChange}
/>
);
};
export default BasicExample;

Related

Angular: Get parent and specific child from JSON

I have this object:
elements120: {
"data": {
"name": "120",
"type": "120"
},
"children": [
{
"data": {
"name": "120A",
"type": "120A"
},
"children": []
},
{
"data": {
"name": "120B",
"type": "120B"
},
"children": []
},
{
"data": {
"name": "120C",
"type": "120C"
},
"children": []
}
]
}
I need to make some new Json as these below:
Json 1:
filtered120A{
"data": {
"name": "120",
"type": "120"
},
"children": [
{
"data": {
"name": "120A",
"type": "120A"
},
"children": []
}
]
}
Json 2:
filtered120B{
"data": {
"name": "120",
"type": "120"
},
"children": [
{
"data": {
"name": "120B",
"type": "120B"
},
"children": []
}
]
}
Json 3:
filtered120C{
"data": {
"name": "120",
"type": "120"
},
"children": [
{
"data": {
"name": "120C",
"type": "120C"
},
"children": []
}
]
}
I tried to do this in order to get only the first children node and delete the others (it's the only way it works me). For 120B and 120C i put as first child the value of the node that I needed for each case
this.filtered120A = utils.deepClone(this.elements120);
this.filtered120B = utils.deepClone(this.elements120);
this.filtered120C = utils.deepClone(this.elements120);
this.filtered120A = this.filtered120A.filter((element) => {
delete element.children[1];
delete element.children[2];
return true;
});
this.filtered120B = this.filtered120B.filter((element) => {
element.children[0] = element.children[1];
delete element.children[1];
delete element.children[2];
return true;
});
this.filtered120C = this.filtered120C.filter((element) => {
element.children[0] = element.children[2];
delete element.children[1];
delete element.children[2];
return true;
});
It works, but the code is not very elegant. I would like to know if there is any other better alternative.
Here you go:
function getOutputs(input) {
const outputs = [];
for (const child of input.children) {
outputs.push({
"data": {
"name": input.data.name,
"type": input.data.type
},
"children": [child]
});
}
return outputs;
}
const inputs = {
"data": {
"name": "120",
"type": "120"
},
"children": [
{
"data": {
"name": "120A",
"type": "120A"
},
"children": []
},
{
"data": {
"name": "120B",
"type": "120B"
},
"children": []
},
{
"data": {
"name": "120C",
"type": "120C"
},
"children": []
}
]
};
const outputs = getOutputs(inputs);
console.log(outputs[0]); // output1
console.log(outputs[1]); // output2
console.log(outputs[2]); // output3

How to prevent fields in react-json-schema-form from appearing row by row

I am creating forms using React-json-schema-form. I don't understand how am I suppose to change the layout of the forms I create. They appear in rows by default and adding classes to each field in the uiSchema does not reflect the desired change. I tried adding col-3 etc and they neither change size nor stop appearing in rows.
Its so complex to figure out. My understand would be to change the default behaviour of the fields. But, I'm sure it should be able to be designed out of the box right?
This is what I want to do but its outdated and I still don't know how to use it. https://github.com/audibene-labs/react-jsonschema-form-layout.
How do I change the layout?
import React, { Component, Fragment } from "react";
import axios, { existing_api, new_api, public_path } from "../../../Api/api";
import 'bootstrap/dist/css/bootstrap.css';
//import Form from "#rjsf/core";
import Form from "#rjsf/bootstrap-4";
class POSView extends Component {
constructor(props) {
super(props);
this.state = {
hotelId: 1,
isActive: 1,
formData: { 'recordIn': 10096 },
schema: props.schema || {
"title": "POS",
"description": "Add POS Invoice - Rooms",
"type": "object",
"properties": {
"customer": { "title": "Customer", "type": 'string', "default": '' },
"room": { "title": "Room", "type": 'integer', "default": '' },
"address": { "title": "Address", "type": 'string' },
"company": { "title": "Company", "type": 'string' },
"dueAmount": { "title": "Due Amount", "type": 'string' },
"roomRate": { "title": "Room Rate", "type": 'string' },
"recordIn": { "title": "Record In", "type": 'number', enum: [10096, 10097], enumNames: ["Guest Ledger Control A/c", "Accounts Receivable"] },
"department": { "title": "Department", "type": 'number', enum: [1, 2], enumNames: ["Head Office", "Accounts"] },
"id": { "title": "ID", "type": 'string' },
"invoiceNumber": { "title": "Invoice Number", "type": 'string' },
"invoiceDate": { "title": "Invoice Date", "type": 'string', "format": "date-time" },
"btcCompany": { "title": "BTC Company", "type": 'number', enum: [1, 2], enumNames: ["Limited Standard", "Standard Limited"] },
"itemsAndServices":
{
"title": "Item And Service",
"description": "Add items and Services",
"type": "array",
"items": {
"type": "object",
//"required": [''],
"properties":
{
"Number": { "type": "number" },
"Item Name": {
"title": "Item Name",
"type": "string"
},
"Item Notes": {
"title": "Item Notes",
"type": "string"
},
"Qty": {
"title": "Qty",
"type": "number"
},
"Unit": {
"title": "Unit",
"type": "string"
},
"Price": {
"title": "Price",
"type": "number"
},
"%": {
"title": "%",
"type": "number"
},
"Extended": {
"title": "Extended",
"type": "number"
}
}
}
},
"payment":
{
"title": "Payment",
"description": "",
"type": "array",
"items": {
"type": "object",
//"required": [''],
"properties":
{
"date": { "title": "Date", "type": "string", format: "date-time" },
"amount": { "title": "Amount", "type": "number" },
"cheque": { "title": "Cheque #", "type": "integer" },
"memo": { "title": "Memo", "type": "string" },
"recordIn": { "title": "Record In", "type": 'number', enum: [10096, 10097], enumNames: ["Guest Ledger Control A/c", "Accounts Receivable"] },
// dynamically populate
}
}
}
}
},
uiSchema: props.uiSchema || {
// customer:{'className':""},
// room:{'className':"", },
// address: {'className':"", "ui:disabled": true, },
// company: {'className':"", "ui:disabled": true, },
// dueAmount: {'className':"", "ui:disabled": true, },
// roomRate: {'className':"", "ui:disabled": true, },
// recordIn:{'className':"", },
// department:{'className':"", },
// id:{'className':"", },
// invoiceNumber: {'className':"", "ui:disabled": true, },
// invoiceDate:{'className':"", },
// btcCompany:{'className':"", },
// itemsAndServices:{'className':""},
//items: { className: "container col-offset-6 col-md-3" }
// 'ui:field': 'layout', HOW I expected the default library to work
// 'ui:layout': [
// {
// customer: { md: 6 },
// room: { md: 6 }
// }, {
// address: { md: 12 }
// }, {
// company: { md: 6 },
// dueAmount: { md: 6 }
// }
// ]
// },
// fields:
// {
// layout: LayoutField
}
};
this.onChange = this.onChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
};
onChange({ formData }) {
formData.address = "";
console.log(formData);
this.state.schema.description = "this is beta plus plus";
this.setState({
formData: formData,
});
}
handleSubmit({ formData }) {
// Submit to an api
console.log(formData);
}
render() {
return (
<div className="container">
<div className="col-4">
{/* <div class="row">
<h1 class="col">First Form</h1>
</div><br /> */}
<div>
<Form
schema={this.state.schema}
formData={this.state.formData}
uiSchema={this.state.uiSchema}
//fields={this.state.fields}
onChange={this.onChange}
onSubmit={this.handleSubmit} />
</div>
</div>
</div>
);
}
}
export default POSView;

TypeScript: add a new object into an array of objects

I have the following data structure:
uiBundles:
[
{
"id": "tasks widget UI",
"uiUnits": [
{
"type": "widget",
"id": "tasks-widget",
"roles": "MB"
}
]
},
{
"id": "berater widget UI",
"uiUnits": [
{
"type": "widget",
"id": "berater-widget",
"roles": "MB"
}
]
}
]
What I would like to do is add a new uiUnit into this embedded array of objects. Here is my code:
add-new.component.ts:
uiBundles: UIBUndle[];
ngOnInit(): void {
this.getBundlesService.getUiBundles().subscribe((value: UIBundle[]) => this.uiBundles = value);
}
addWidget(id: string): void {
this.selectedUiUnits = this.uiBundles.filter((data) => data.id === id);
let newWidget = { id: 'new', uiUnits: [{ id: 'new-widget', type: 'widget', roles:'MB' }] };
}
add-new.component.html:
<div *ngFor="let bundle of uiBundles">
<button (click)="addWidget(bundle.id)"></button>
</div>
When I run this code, the result is this:
[
{
"id": "tasks widget UI",
"uiUnits": [
{
"type": "widget",
"id": "tasks-widget",
"roles": "MB"
}
]
},
{
"id": "berater widget UI",
"uiUnits": [
{
"type": "widget",
"id": "berater-widget",
"roles": "MB"
}
]
},
{
"id": "new",
"uiUnits": [
{
"type": "widget",
"id": "new-widget",
"roles": "MB"
}
]
}
]
But what I am trying to do would be:
[
{
"id": "tasks widget UI",
"uiUnits": [
{
"type": "widget",
"id": "tasks-widget",
"roles": "MB"
},
{
"type": "widget",
"id": "new widget",
"roles": "MB"
}
]
},
{
"id": "berater widget UI",
"uiUnits": [
{
"type": "widget",
"id": "berater-widget",
"roles": "MB"
}
]
}
]
Can someone please help me, what did I do wrong here?
You aren't adding the new widget to the uiUnits array of the widget with the specified id but instead are creating an entirely new widget.
What you want is rather
addWidgetToBundleUnits(id: string) {
const selectedBundle = this.uiBundles.find(bundle => bundle.id === id);
const widgetToAdd = {id: 'new-widget', type: 'widget', roles: 'MB'};
selectedBundle.uiUnits.push(widgetToAdd);
}
Try this:
addWidget(id: string): void {
const index: number = this.uiBundles.findIndex((data) => data.id === id);
const newUnits = [{ id: 'new-widget', type: 'widget', roles:'MB' }];
this.uiBundles[index].uiUnits.push(newUnits);
}

how to map and array inside of an object

So here I have an object that I am trying to map:
var bakery = {
"items":
{
"item":[
{
"id": "0001",
"type": "donut",
"name": "Cake",
"ppu": 0.55,
"batters": {
"batter":[
{ "id": "1001", "type": "Regular" },
{ "id": "1002", "type": "Chocolate" },
{ "id": "1003", "type": "Blueberry" },
{ "id": "1004", "type": "Devil's Food" }
]
},
"topping":[
{ "id": "5001", "type": "None" },
{ "id": "5002", "type": "Glazed" },
{ "id": "5005", "type": "Sugar" },
{ "id": "5007", "type": "Powdered Sugar" },
{ "id": "5006", "type": "Chocolate with Sprinkles" },
{ "id": "5003", "type": "Chocolate" },
{ "id": "5004", "type": "Maple" }
]
},
...
...
...
]
}
}
This is the target outcome
var target = [{
"id": 1, //as an int
"type": "donut",
"name": "Cake",
"ppu": 0.55,
"batters": "all of the batter types as a string",
"ingredients": [],//a copy of all the toppings
"countOfFillings": 0
}];
And here is my mapping function
// creates variable bakeryArray that contains the actual Array inside of Baker var
var bakeryArray = bakery.items.item
// newCakes var invoked map function with the bakeryArray
var newCakes = bakeryArray.map(mapCakes)
function mapCakes(oldCakes) {
let batter = oldCakes.batters.batter
console.log(batter, "batter Logged")
var newCakesObject = {
type: oldCakes.type,
name: oldCakes.name,
ppu: oldCakes.ppu,
batters: batter.type,
ingredients: "ingridients",
countOfFillings: "total number of ingrediensts"
};
return newCakesObject;
};
I am running into problems in getting the Batter, Ingredients, and countOfFillings from the old object into the new one.
The only thing I can think of doing in order to get the batters in the newCakesObject is that I have to create another mapping function for the batter (I put my attempt at that below)? and then invoke that in the mapCakes function under batters? but every time I create another function for that I get an error saying that it's undefined once I call newBatterArray in the console
var newBatterArray = bakeryArray.map(mapBatters)
function mapBatters(oldarray) {
let theBatters = oldarray.batters.batter
console.log(theBatters.type, "we ran")
var newBatters = {
type: theBatters.type
}
return newBatters;
}
To have a much more clear interpretation of your bakery object I have tweaked it a bit
var bakery = {
"items":[
{
"id": "0001",
"type": "donut",
"name": "Cake",
"ppu": 0.55,
"batters":[
{ "id": "1001", "type": "Regular" },
{ "id": "1002", "type": "Chocolate" },
{ "id": "1003", "type": "Blueberry" },
{ "id": "1004", "type": "Devil's Food" }
],
"toppings":[
{ "id": "5001", "type": "None" },
{ "id": "5002", "type": "Glazed" },
{ "id": "5005", "type": "Sugar" },
{ "id": "5007", "type": "Powdered Sugar" },
{ "id": "5006", "type": "Chocolate with Sprinkles" },
{ "id": "5003", "type": "Chocolate" },
{ "id": "5004", "type": "Maple" }
]
},
{
"id": "0002",
"type": "donut",
"name": "Cake",
"ppu": 0.65,
"batters":[
{ "id": "1001", "type": "Regular1" },
{ "id": "1002", "type": "Chocolate1" },
{ "id": "1003", "type": "Blueberry1" },
{ "id": "1004", "type": "Devil's Food1" }
],
"toppings":[
{ "id": "5001", "type": "None1" },
{ "id": "5002", "type": "Glazed1" },
{ "id": "5005", "type": "Sugar1" },
{ "id": "5007", "type": "Powdered Sugar1" },
{ "id": "5006", "type": "Chocolate with Sprinkles1" },
{ "id": "5003", "type": "Chocolate1" },
{ "id": "5004", "type": "Maple1" }
]
},
...
...
...
...
]
}
Now You can iterate through each item and build your target array as follows
var target = [];
// define reducer function for each item in bakery.items
const reduceToTarget = item => {
var obj = {};
obj.id = item.id;
obj.type = item.type;
obj.name = item.name;
obj.ppu = item.ppu;
obj.batters = '';
item.batters.forEach(b => obj.batters+=b.type+'|');
obj.ingredients = item.toppings;
target.push(obj);
}
// Now you can call the reduceToTarget function to get the desired target list/array
bakery.items.forEach(reduceToTarget);
The output for this looks something like this
target = [
{
id: "0001"
type: "donut"
name: "Cake"
ppu: 0.55
batters: "Regular|Chocolate|Blueberry|Devil's Food|",
ingredients : [/* list of ingredients*/]
},
{
id: "0002"
type: "donut"
name: "Cake"
ppu: 0.65
batters: "Regular|Chocolate|Blueberry|Devil's Food|",
ingredients : [/* list of ingredients*/]
}
]
NOTE:
For getting the countOfFillings you can simply call length() function on your ingredients list for any element in target

Displaying list dynamically in react when user click on input filed

I am trying to display list dynamically when user click on input box. for that I took onChange event handle on input box and setting state to new data when user click on input box. but it is not giving me desired result. can anyone help me to solve the issue ? When user click on input box then only list should be displayed but in my case it's displaying already.
SearchBox.js
import React, { Component } from "react";
import SourceData from "../assets/continents.json";
class SearchBox extends Component {
state = {
value: ""
};
handleChange = e => {
this.setState({
sourceData: SourceData
});
};
render() {
const searhBox = (
<input type="text" value={this.state.value} onClick={this.handleChange} />
);
const selectBox2 = SourceData.map(option => <li>{option.continent}</li>);
return (
<React.Fragment>
<h2>Step 1</h2>
<h3>Select a continent.</h3>
{searhBox}
<ul>{selectBox2}</ul>
</React.Fragment>
);
}
}
export default SearchBox
continents.json
[
{
"continent": "Africa",
"countries": [
{
"name": "Nigeria",
"flag": "ð³ð¬"
},
{
"name": "Ethiopia",
"flag": "ðªð¹"
},
{
"name": "Egypt",
"flag": "ðªð¬"
},
{
"name": "DR Congo",
"flag": "ð¨ð©"
},
{
"name": "South Africa",
"flag": "ð¿ð¦"
}
]
},
{
"continent": "America",
"countries": [
{
"name": "USA",
"flag": "ðºð¸"
},
{
"name": "Brazil",
"flag": "ð§ð·"
},
{
"name": "Mexico",
"flag": "ð²ð½"
},
{
"name": "Colombia",
"flag": "ð¨ð´"
},
{
"name": "Argentina",
"flag": "ð¦ð·"
}
]
},
{
"continent": "Asia",
"countries": [
{
"name": "China",
"flag": "ð¨ð³"
},
{
"name": "India",
"flag": "ð®ð³"
},
{
"name": "Indonesia",
"flag": "ð®ð©"
},
{
"name": "Pakistan",
"flag": "ðµð°"
},
{
"name": "Bangladesh",
"flag": "ð§ð©"
}
]
}
]
output ::
In SearchBox.render, build up the list of countries from this.state.sourceData
const selectBox2 = this.state.sourceData.map(option => <li>{option.continent}</li>);
return (
<React.Fragment>
<h2>Step 1</h2>
<h3>Select a continent.</h3>
{searhBox}
{selectBox2 && <ul>{selectBox2}</ul>}
</React.Fragment>
);
Also, remember to set an initial value for sourceData in SearchBox.state.
state = {
value: '',
sourceData: []
};

Resources