How to handle two api calls in react-typescript ant-design - antd

interface SingleCustomerShipmentData {
_id: string;
shipping_type: string;
origin_port_city: string;
destination_port_city: string;
shipment_pickup_date: string;
}
interface SingleCustomerData {
id: string;
first_name: string;
last_name: string;
email: string;
phone: string;
Avatar: string;
}
const columns: ColumnsType<SingleCustomerShipmentData> = [
{
title: 'Shipment Type',
dataIndex: 'shipping_type',
key: 'shipping_type',
render: (shipping_type, data) => {
return (
<div>
<img className='customers-avatar' src={data.Avatar} alt="" />
{shipping_type}
</div>
)
},
},
{
title: 'Origin',
dataIndex: 'origin_port_city',
key: 'origin_port_city',
},
{
title: 'Destination',
dataIndex: 'destination_port_city',
key: 'destination_port_city',
},
{
title: 'Shipment Date',
dataIndex: 'shipment_pickup_date',
key: 'shipment_pickup_date',
},
{
title: 'Shipping ID',
dataIndex: '_id',
key: '_id',
},
{
title: '',
key: 'action',
render: () => {
return (
<Space size="middle"
<Link to="/shipment-details" className='space-action-green'>View Details</Link>
</Space>
)
},
},
];
const Shipments: React.FC = () => {
const [shipmentData, setShipmentData] = useState(null);
const [customersData, setCustomersData] = useState(null);
const [loading, setLoading] = useState(false);
useEffect(() => {
getSingleCustomer()
}, [])
useEffect(() => {
getSingleCustomerShipment()
}, [])
const getSingleCustomer = () => {
setLoading(true);
return makeAPICall({
path: `get_single_customer/123456789`,
method: "GET",
})
.then((data) => {
setCustomersData(data);
setLoading(false);
console.log(data);
})
.catch((err) => {
setLoading(false);
console.log(err);
});
}
const getSingleCustomerShipment = () => {
setLoading(true);
return makeAPICall({
path: `get_single_customer_shipments/123456789`,
method: "GET"
}).then((data) => {
setShipmentData(data);
console.log(data);
}).catch((err) => {
setLoading(false);
console.log(err);
})
}
return (
<SiderLayout>
<div className="site-layout-background" style={{ padding: "40px 40px", minHeight: 710 }}>
<Link className='shipment-back' to="/">
<img src={ArrowLeft} alt="" />
</Link>
{loading ? "loading..." : (
<>
<div className='shipment__container'>
<div className='shipment__container--image'>
<img src={data.Avatar} alt="" style={{ marginRight: 10 }} />
<div>
<p className='bold'>{first_name}</p>
<p>{email}</p>
<p>{phone}</p>
</div>
</div>
<div>
<span className='shipment__container--edit'>Edit</span>
</div>
</div>
<div className='shipment__border'>
<div className='shipment-spacing'>
<button className='new-shipment'>Add New Shipment {" "} +</button>
<select className='shipment-select' name="" id="">
<option value="">Shipment Type</option>
</select>
<select className='shipment-select' name="" id="">
<option value="">Shipment Date</option>
</select>
</div>
<div className='shipment-search'>
<form className="nosubmit">
<input className="nosubmit" type="search" placeholder="Search by shipment ID, Destination" />
</form>
</div>
</div>
<Table columns={columns} dataSource={data} />
</>
)}
</div>
</SiderLayout>
So I'm having these two api calls to be made on the same page. However I created two interface because both would definitely be needed on the it. But I don't really know how I can achieve that, because it is given an error message cannot find name data. So I brought it here for any person with an idea of it to help me out.

const [shipmentData, setShipmentData] = useState(null);
const [customersData, setCustomersData] = useState(null);
these shouldn't start as a null value. Because AntD Table requires an array to render.
const [shipmentData, setShipmentData] = useState([]);
const [customersData, setCustomersData] = useState([]);
should solve the problem you are facing.

Related

React: Trying to set selection to drop down option

I setup a component that is basically a drop down and I am trying to figure out how to set it to where when I submit the form....its set on that one option. When I submit it now, it sends all the options to the backend instead of just the one I selected.
Here is my Category component
import React, { Component } from 'react'
class Categories extends Component{
handleCatChange = (event) => {
this.setState({category: event.target.value}) <------this should set the state to whatever is selected
}
render(){
let categories = this.props.category
let value = this.props.value
let optionItems = categories.map((cat,index) => {
return <option key={index} value={value}>{cat.category}</option>
})
return (
<div>
<select onchange={this.handleCatChange} value={this.props.category}>
{this.props.category ? optionItems : <p>Loading....</p>}
</select>
</div>
)
}
}
export default Categories
And here is RecipeInput Component with form
import React, { Component } from 'react'
import Categories from './Categories.js'
class RecipeInput extends Component{
constructor(props){
super(props)
this.state = {
category: [],
name:'',
ingredients: '',
chef_name: '',
origin: ''
}
}
componentDidMount(){
let initialCats = [];
const BASE_URL = `http://localhost:10524`
const CATEGORIES_URL =`${BASE_URL}/categories`
fetch(CATEGORIES_URL)
.then(resp => resp.json())
.then(data => {
initialCats = data.map((category) => {
return category
})
this.setState({
category: initialCats
})
});
}
handleSubmit = (event) =>{
event.preventDefault();
this.props.postRecipes(this.state)
this.setState({
name:'',
ingredients: '',
chef_name: '',
origin: ''
})
}
render(){
return(
<div>
<form onSubmit={this.handleSubmit}>
<Categories category={this.state.category} value={this.state.category}/>
<div>
<label for='name'>Recipe Name:</label>
<input type='text' value={this.state.name} onChange={this.handleNameChange} />
</div>
<div>
<label for='name'>Country Origin:</label>
<input type='text' value={this.state.origin} onChange={this.handleOriginChange} />
</div>
<div>
<label for='name'>Chef Name:</label>
<input type='text' value={this.state.chef_name} onChange={this.handleChefChange} />
</div>
<div>
<label for='name'>Ingredients:</label>
<textarea value={this.state.ingredients} onChange={this.handleIngChange} />
</div>
<input value='submit' type='submit'/>
</form>
</div>
)
}
}
export default RecipeInput
And here is the error that is produced on submission(Its Rails btw)
I tired a few ways but haven't quite wrapped my head around using a component as a dropdown. What do I need to do?
Here is my backend code that creates the record on the api
def create
recipe = Recipe.create(recipe_params)
if recipe.save
render json: recipe
else
render json: { error: "Couldn't save" }
end
end
private
def recipe_params
params.permit(:category_id,:name,:ingredients,:chef_name,:origin,category_attribute:[:category])
end
Also my postRecipe function
export const postRecipes = (recipe)=>{
const BASE_URL = `http://localhost:10524`
const RECIPES_URL =`${BASE_URL}/recipes`
const config = {
method: "POST",
body:JSON.stringify(recipe),
headers: {
"Accept": "application/json",
"Content-type": "application/json"
}
}
//category field
return(dispatch)=>{
fetch(RECIPES_URL,config)
.then(response => response.json())
.then(resp => {
dispatch({
type: 'Add_Recipe',
payload:{
// category:resp.category,
name: resp.name,
ingredients: resp.ingredients,
chef_name: resp.chef_name,
origin: resp.origin,
categoryId: resp.categoryId
}
})
})
//.then(response => <Recipe />)
.catch((error) => console.log.error(error))
}
}
Code Edit due to change in question:
Access selectedValue while sending to the server
class Categories extends Component {
render() {
...
let optionItems = categories.map((cat, index) => {
return (
<option key={index} value={index}>
{cat.category}
</option>
);
});
...
}
}
class RecipeInput extends Component{
constructor(props){
super(props)
this.state = {
category: [],
name:'',
ingredients: '',
chef_name: '',
origin: ''
selectedValue: {}
}
}
handleSubmit(id){
this.setState({
selectedValue: this.state.category[id]
)}
}
...
}
You're passing onChange and value from Input Component but you're not using them in Categories Component.
Add onChange and value property to tag.
here is reference
import "./styles.css";
import React, { Component } from "react";
class Categories extends Component {
render() {
let categories = this.props.category;
let onChange = this.props.onChange;
let optionItems = categories.map((cat, index) => {
return (
<option key={index} value={cat.category}>
{cat.category}
</option>
);
});
return (
<div>
<select onChange={(e) => onChange(e.target.value)}>
{this.props.category.length ? optionItems : null}
</select>
</div>
);
}
}
export default function App() {
const onChange = (value) => {
console.log(value);
};
return (
<Categories
onChange={onChange}
category={[{ category: "1st" }, { category: "2nd" }]}
/>
);
}
I've updated the code.
If you need to try it online you can refer my Sandbox
https://codesandbox.io/s/stackoverflow-qno-65730813-j32ce

How to use Radio groups inside Antd table?

I want to do this: each row is a Radio group, each cell is a Radio button, like the picture:
An example of Radio group is like:
<Radio.Group onChange={this.onChange} value={this.state.value}>
<Radio value={1}>A</Radio>
<Radio value={2}>B</Radio>
<Radio value={3}>C</Radio>
<Radio value={4}>D</Radio>
</Radio.Group>
But I don't know how to add a Radio group to wrap each Antd table row?
My current code is:
renderTable() {
let columns = [];
columns.push(
{
title: '',
dataIndex: 'name',
key: 'name',
width: '45vw',
},
);
this.props.task.options.forEach((option, i) => {
columns.push(
{
title: option,
dataIndex: option,
key: option,
className: 'choice-table-column',
render: x => {
return <Radio value={0} />
},
},
);
});
let rowHeaders = [];
this.props.task.extras.forEach((extra, i) => {
rowHeaders.push(
{"name": `${i + 1}. ${extra}`},
);
});
// How can I pass a className to the Header of a Table in antd / Ant Design?
// https://stackoverflow.com/questions/51794977/how-can-i-pass-a-classname-to-the-header-of-a-table-in-antd-ant-design
const tableStyle = css({
'& thead > tr > th': {
textAlign: 'center',
},
'& tbody > tr > td': {
textAlign: 'center',
},
'& tbody > tr > td:first-child': {
textAlign: 'left',
},
});
return (
<div>
<Table className={tableStyle} columns={columns} dataSource={rowHeaders} size="middle" bordered pagination={false} />
</div>
);
}
I don't think it is possible to use radio group for each row, however you can achieve it in a traditional way.
Here is code sample
https://codesandbox.io/s/goofy-benz-12kv5
class App extends React.Component {
state = {
task: { options: [1, 2, 3, 4, 5], extras: [6, 7, 8, 9, 10] },
selected: {}
};
onRadioChange = e => {
let name = e.currentTarget.name;
let value = e.currentTarget.value;
this.setState({
...this.state,
selected: { ...this.state.selected, [name]: value }
});
};
onSubmit = () => {
console.log(this.state.selected);
this.setState({
...this.state,
selected: {}
});
};
render() {
let columns = [];
columns.push({
title: "",
dataIndex: "name",
key: "name",
width: "45vw"
});
this.state.task.options.forEach((option, i) => {
columns.push({
title: option,
key: option,
render: row => {
return (
<input
type="radio"
checked={this.state.selected[row.name] == option}
onChange={this.onRadioChange}
name={row.name}
value={option}
/>
);
}
});
});
let rowHeaders = [];
this.state.task.extras.forEach((extra, i) => {
rowHeaders.push({ name: `${i + 1}.${extra}` });
});
return (
<div>
<Button onClick={this.onSubmit} type="primary">
{" "}
Submit
</Button>
<Table
columns={columns}
dataSource={rowHeaders}
size="middle"
bordered
pagination={false}
/>
<Tag color="red">Selected options</Tag>
<br />
{JSON.stringify(this.state.selected)}
</div>
);
}
}
hi there i had the same problem and base on new updates on antd this way of using is easier
<Table
rowSelection={{
type: "radio",
getCheckboxProps: (record) => {
console.log("record", record);
},
}}
pagination={{ hideOnSinglePage: true }}
columns={columns}
dataSource={data}
/>
example : https://ant.design/components/table/#components-table-demo-row-selection
for hiding table header : https://newbedev.com/javascript-antd-table-hide-table-header-code-example
hope its usefull

Paginator not works when i fetch data from API into a mat-table. Mat table is generated dynamically

I'm creating my mat-table dynamically where is pass columns through an array and data is also rendering dynamically.
Mat-paginator was working fine with the local array. But when i fetch data from an API it doesn't respond.
I've tried different things but didn't find any solution.
Here is my code from the Html file.
`
<div class="container">
<div class="tableSearchRow">
<div id="searchTitle">
<button (click)="toggle()" [hidden]="show" class="searchButton">{{name}}<i class="material-icons searchIconImg"> search </i></button>
<mat-form-field *ngIf="!isPrepositionChecked" >
<input id="textupercase" matInput (keyup)="applyFilter($event.target.value)" placeholder="Search">
</mat-form-field>
</div>
<div id="searchIcon">
<button mat-raised-button (click)="openDialog()">+Add</button>
</div>
</div>
<div class="row">
<mat-table #table [dataSource]="dataSource" >
<ng-container *ngFor="let column of columns" [cdkColumnDef]="column.columnDef">
<mat-header-cell *cdkHeaderCellDef>{{ column.header }}</mat-header-cell>
<mat-cell *matCellDef="let commonCode">{{column.cell(commonCode)}}</mat-cell>
</ng-container>
<ng-container cdkColumnDef="Actions">
<mat-header-cell *cdkHeaderCellDef> Actions </mat-header-cell>
<mat-cell *matCellDef="let commonCode; let i = index">
<button mat-button (click)="updateDataDialog(i,commonCode)"><i class="material-icons blue">border_color</i></button>enter code here
<button mat-button (click)="delete(commonCode.Code)"><i class="material-icons red">delete</i></button>
<button mat-button routerLink="commonCodeValues"><i class="material-icons" >blur_circular</i></button>
</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns" ></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns;" ></mat-row>
</mat-table>
<mat-paginator [pageSizeOptions]="[5,10, 20]"></mat-paginator>
</div>
</div>
`
Code of Js File
`
let fields: any[] = [
{
type: 'text',
name: 'Code',
label: 'Code',
value: '',
required: true,
},
{
type: 'text',
name: 'Name',
label: 'Name',
value: '',
required: true,
},
{
type: 'text',
name: 'Description',
label: 'Description',
value: '',
required: true,
},
];
#Component({
selector: 'app-common-codes',
templateUrl: './common-codes.component.html',
styleUrls: ['../setupStyle.css']
})
export class CommonCodesComponent implements OnInit {
#ViewChild(MatPaginator) paginator: MatPaginator;
dataSource: any;
name="commonCode";
Employee: any = [];
// Columns Of Table
columns = [
{ columnDef: 'Code', header: 'Code', cell: (element: any) => `${element.Code}`},
{ columnDef: 'Name', header: 'Name', cell: (element: any) => `${element.Name}`},
{ columnDef: 'Description', header: 'Description', cell: (element: any) => `${element.Description}`},
];
displayedColumns = this.columns.map(c => c.columnDef).concat(['Actions']);
constructor(private dialog: MatDialog, private fb: FormBuilder, private setupService: SetupService) {
this.dataSource = new MatTableDataSource(this.json.transfer)
// this.refresh()
}
ngOnInit() {
// console.log(this.displayData());
}
ngAfterViewInit() {
this.refresh();
this.dataSource.paginator = this.paginator;
}
// Filter For Table
applyFilter(filterValue: string) {
this.dataSource.filter = filterValue.trim().toLowerCase();
}
// Function to refresh data inside table
refresh(){
this.dataSource = new MatTableDataSource(JSON.parse(localStorage.getItem(this.name )));
}
// Function for search bar
toggle(){
this.show=true;
this.isPrepositionChecked=false;
}
// Function For Adding New Table
openDialog(){
let regiForm = this.fb.group({
'Code' : ['', Validators.required],
'Name' : ['', Validators.required],
'Description' : ['', Validators.required],
});
this.setupService.openDialog(regiForm, fields, this.name).afterClosed().subscribe(res => {
this.refresh()
})
}
// Function for update Data inside table
updateDataDialog(index, obj){
let regiForm = this.fb.group({
'Code' : [obj.Code, Validators.required],
'Name' : [obj.Name, Validators.required],
'Description' : [obj.Description, Validators.required],
});
this.setupService.updateDialog(regiForm, fields, this.name, index ).afterClosed().subscribe(res => {
this.refresh();
})
}
// Function to remove data from table
delete(id){
this.setupService.deleteData().afterClosed().subscribe(res => {
if(res){
let items = JSON.parse(localStorage.getItem(this.name));
for (var i =0; i<=items.length; i++) {
if (items[i].Code == id) {
console.log("id FOUND")
items.splice(i,1)
break;
}
else {
console.log("id doesn't match")
}
}
items = JSON.stringify(items);
localStorage.setItem(this.name, items);
this.refresh();
}
})
}
// displayData(){
// this.setupService.getData().subscribe((res : {}) => {
// this.Employee = res;
// });
// }
}
`

Gutenberg Block Development: Only one RichText content is saving

I added two RichText components in my block.
registerBlockType( 'hallmark/gray-content-container', {
title: __( 'Gray Content Container' ),
icon: 'grid-view',
category: 'hallmark-blocks',
keywords: [
__( 'Hallmark gray content' ),
__( 'Hallmark' ),
__( 'Gray content container' ),
],
attributes:{
contentHeading: {
type: 'string',
source: 'children',
selector: 'h1,h2,h3,h4,h5,h6'
},
textContent: {
type: 'string'
}
},
edit: function( props ) {
var textContent = props.attributes.textContent;
var contentHeading = props.attributes.contentHeading;
function onChangeTextContent( content ) {
props.setAttributes( { textContent: content } );
}
function onChangeHeading (heading) {
props.setAttributes( { contentHeading: heading} );
}
return (
<div className={ props.className }>
<label className="editor-content-section-label">Content for gray section</label>
<RichText
tagName="h1"
value={contentHeading}
onChange={onChangeHeading}
placeholder={ __( 'Add a heading' ) }
keepPlaceholderOnFocus
/>
<RichText
tagName="p"
className={props.className}
onChange={onChangeTextContent}
value={textContent}
placeholder={ __( 'Add content' ) }
keepPlaceholderOnFocus
/>
</div>
);
},
save: function( props ) {
//return null;
return(
<div className={props.className}>
<div className="gray-bg">
<div className="constrain content">
<RichText.Content tagName="h1" value={ attributes.contentHeading } />
<RichText.Content tagName="p" value={ attributes.textContent } />
</div>
</div>
</div>
);
},
} );
I tried two different approaches to save the data.
Using default save() function
save: function( props ) {
return(
<div className={props.className}>
<div className="gray-bg">
<div className="constrain content">
<RichText.Content tagName="h1" value={ attributes.contentHeading } />
<RichText.Content tagName="p" value={ attributes.textContent } />
</div>
</div>
</div>
);
},
Saving it in PHP:
Using render_callback method (Using return null; from block's default save() function.
register_block_type( 'hallmark/white-content-container', array(
'render_callback' => 'hall_render_white_content'
) );
function hall_render_white_content( $atts ) {
$heading = $atts['contentHeading'];
$raw_content = $atts['textContent'];
$full_content = $heading . $raw_content;
// var_dump($full_content);
$content = hall_clean_shortcode_block_content( $full_content );
return '<div class="gray-bg"><div class="constrain content">' . $content . '</div></div>';
}
atts['contentHeading'] element does not exist at all in $atts array. When I check var_dump( $attas ); it has textContentelement present.
The problem is both approaches are only saving the textContent. contentHeading is not at all saving.
What I am missing?
Try setting
attributes:{
contentHeading: {
type: 'string',
source: 'children',
selector: 'h1'
},
textContent: {
type: 'string'
selector: 'p'
}
},
I think the selectors have to exactly match what is set in the save method.
<div className="constrain content">
<RichText.Content tagName="h1" value={ attributes.contentHeading } />
<RichText.Content tagName="p" value={ attributes.textContent } />
</div>
I think you also need a unique selector, so if you had two RichText paragraphs, you could do
textContentA: {
type: 'string'
selector: 'p.content-a'
}
textContentB: {
type: 'string'
selector: 'p.content-b'
}
For debugging use console.log(props.attributes) inside your edit function and observe if the values of contentHeading is changing or not when you edit. edit() function will be called each time if the state or props of component changes. As per my lucky guess the source of contentHeading should be 'text' instead of children.

type is invalid: expected a string (for built-in components) or a class/function in custom react component

I have an antd table with 2 columns which I need to filter on the first, and search text on the second column.
If I remove the line: ...this.getColumnSearchProps('Tags'),
from my code, the application is rendered fine. Please note the tags field is a json array, not a text field, so I guess that has something to do with the error.
import React, { Component } from 'react';
import { Table, Tag, Button, Icon, Input} from 'antd';
import { adalApiFetch } from '../../adalConfig';
import Notification from '../../components/notification';
import Highlighter from 'react-highlight-words';
class ListPageTemplatesWithSelection extends Component {
constructor(props) {
super(props);
this.state = {
data: [],
filteredInfo: null,
sortedInfo: null,
searchText: ''
};
this.handleChange= this.handleChange.bind(this);
this.clearFilters= this.clearFilters.bind(this);
this.clearAll= this.clearAll.bind(this);
this.getColumnSearchProps= this.getColumnSearchProps.bind(this);
this.handleSearch= this.handleSearch.bind(this);
this.handleReset= this.handleReset.bind(this);
}
handleSearch (selectedKeys, confirm){
confirm();
this.setState({ searchText: selectedKeys[0] });
}
handleReset(clearFilters){
clearFilters();
this.setState({ searchText: '' });
}
getColumnSearchProps = (dataIndex) => ({
filterDropdown: ({
setSelectedKeys, selectedKeys, confirm, clearFilters,
}) => (
<div style={{ padding: 8 }}>
<Input
ref={node => { this.searchInput = node; }}
placeholder={`Search ${dataIndex}`}
value={selectedKeys[0]}
onChange={e => setSelectedKeys(e.target.value ? [e.target.value] : [])}
onPressEnter={() => this.handleSearch(selectedKeys, confirm)}
style={{ width: 188, marginBottom: 8, display: 'block' }}
/>
<Button
type="primary"
onClick={() => this.handleSearch(selectedKeys, confirm)}
icon="search"
size="small"
style={{ width: 90, marginRight: 8 }}
>
Search
</Button>
<Button
onClick={() => this.handleReset(clearFilters)}
size="small"
style={{ width: 90 }}
>
Reset
</Button>
</div>
),
filterIcon: filtered => <Icon type="search" style={{ color: filtered ? '#1890ff' : undefined }} />,
onFilter: (value, record) => record[dataIndex].toString().toLowerCase().includes(value.toLowerCase()),
onFilterDropdownVisibleChange: (visible) => {
if (visible) {
setTimeout(() => this.searchInput.select());
}
},
render: (text) => (
<Highlighter
highlightStyle={{ backgroundColor: '#ffc069', padding: 0 }}
searchWords={[this.state.searchText]}
autoEscape
textToHighlight={text.toString()}
/>
),
})
handleChange(pagination, filters, sorter){
console.log('Various parameters', pagination, filters, sorter);
this.setState({
filteredInfo: filters,
sortedInfo: sorter,
});
}
clearFilters(){
this.setState({ filteredInfo: null });
}
clearAll(){
this.setState({
filteredInfo: null,
sortedInfo: null,
});
}
fetchData = () => {
adalApiFetch(fetch, "/PageTemplates", {})
.then(response => response.json())
.then(responseJson => {
if (!this.isCancelled) {
const results= responseJson.map(row => ({
key: row.Id,
Name: row.Name,
SiteType: row.SiteType,
Tags: row.Tags
}))
this.setState({ data: results });
}
})
.catch(error => {
console.error(error);
});
};
componentDidMount(){
this.fetchData();
}
render(){
let { sortedInfo, filteredInfo } = this.state;
sortedInfo = sortedInfo || {};
filteredInfo = filteredInfo || {};
const columns = [
{
title: 'Id',
dataIndex: 'key',
key: 'key',
},
{
title: 'Name',
dataIndex: 'Name',
key: 'Name',
},
{
title: 'Site Type',
dataIndex: 'SiteType',
key: 'SiteType',
filters: [
{ text: 'Modern Team Site', value: 'Modern Team Site' },
{ text: 'CommunicationSite', value: 'CommunicationSite' },
],
filteredValue: filteredInfo.SiteType || null,
onFilter: (value, record) => record.SiteType.includes(value),
},{
title: 'Tags',
key: 'Tags',
dataIndex: 'Tags',
...this.getColumnSearchProps('Tags'),
render: Tags => (
<span>
{Tags && Tags.map(tag => {
let color = tag.length > 5 ? 'geekblue' : 'green';
if (tag === 'loser') {
color = 'volcano';
}
return <Tag color={color} key={tag}>{tag.toUpperCase()}</Tag>;
})}
</span>)
}
];
const rowSelection = {
selectedRowKeys: this.props.selectedRows,
onChange: (selectedRowKeys) => {
this.props.onRowSelect(selectedRowKeys);
}
};
return (
<div>
<Button onClick={this.clearFilters}>Clear filters</Button>
<Button onClick={this.clearAll}>Clear filters and sorters</Button>
<Table rowSelection={rowSelection} columns={columns} dataSource={this.state.data} onChange={this.handleChange} />
</div>
);
}
}
export default ListPageTemplatesWithSelection;
However with that line, the application stops rendering and I got multiple errors like this:
Error on interface:
Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.
▶ 23 stack frames were collapsed.
AsyncFunc._callee$
src/helpers/AsyncFunc.js:26
23 | const { default: Component } = await importComponent();
24 | Nprogress.done();
25 | if (this.mounted) {
> 26 | this.setState({
27 | component: <Component {...this.props} />
28 | });
29 | }
what can I do to fix it?
You need to send the current version to the front-end somehow. Is it metadata that can be retrieved from your azure pipeline? Do you perhaps have pre or postbuild scripts? These could update a variable (++) in a database that you could either retrieve from the front-end with an ajax call or send along when downloading the Js bundle from your server.
When you have retrieved the data somewhere somehow in your back-end, you may also consider passing the version number as a header in the http response.

Resources