Tuesday, May 21, 2024
 Popular · Latest · Hot · Upcoming
166
rated 0 times [  168] [ 2]  / answers: 1 / hits: 19443  / 5 Years ago, fri, march 8, 2019, 12:00:00

I have an antd table with 2 columns which I need to filter on the first, and search text on the second column.



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.



Updated 1 Code.



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]
? record[dataIndex]
.toString()
.toLowerCase()
.includes(value.toLowerCase())
: false,
onFilterDropdownVisibleChange: (visible) => {
if (visible) {
setTimeout(() => this.searchInput.select());
}
}
})

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 when I add this line:
...this.getColumnSearchProps('Tags'),



Then I get this error



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 | }


Update 2



This is the container component



import React, { Component } from 'react';
import { Input} from 'antd';
import Form from '../../components/uielements/form';
import Button from '../../components/uielements/button';
import Notification from '../../components/notification';
import { adalApiFetch } from '../../adalConfig';
import ListPageTemplatesWithSelection from './ListPageTemplatesWithSelection';

const FormItem = Form.Item;

class CreateCommunicationSiteCollectionForm extends Component {
constructor(props) {
super(props);
this.state = {Title:'',Url:'', SiteDesign:'', Description:'',Owner:'',Lcid:'', PageTemplateIds : []};
this.handleChangeTitle = this.handleChangeTitle.bind(this);
this.handleValidationCommunicationSiteUrl = this.handleValidationCommunicationSiteUrl.bind(this);
this.handleChangeCommunicationSiteUrl = this.handleChangeCommunicationSiteUrl.bind(this);
this.handleChangeSiteDesign = this.handleChangeSiteDesign.bind(this);
this.handleChangeDescription = this.handleChangeDescription.bind(this);
this.handleChangeOwner = this.handleChangeOwner.bind(this);
this.handleChangelcid = this.handleChangelcid.bind(this);

this.handleSubmit = this.handleSubmit.bind(this);
this.handleRowSelect = this.handleRowSelect.bind(this);
}

handleRowSelect(ids) {
this.setState({ PageTemplateIds: ids });
}

handleChangeTitle(event){
this.setState({Title: event.target.value});
}

handleValidationCommunicationSiteUrl(rule, value, callback){
const form = this.props.form;
const str = form.getFieldValue('communicationsiteurl');
var re = /^(?:http(s)?://)?[w.-]+(?:.[w.-]+)+[w-._~:/?#[]@!$&'()*+,;=.]+$/i;
if (str && !str.match(re)) {
callback('Communication site url is not correctly formated.');
}
else {
callback();
}
}

handleChangeCommunicationSiteUrl(event){
this.setState({Url: event.target.value});
}

handleChangeSiteDesign(event){
this.setState({SiteDesign: event.target.value});
}

handleChangeDescription(event){
this.setState({Description: event.target.value});
}

handleChangeOwner(event){
this.setState({Owner: event.target.value});
}

handleChangelcid(event){
this.setState({Lcid: event.target.value});
}

handleSubmit(e){
e.preventDefault();
this.props.form.validateFieldsAndScroll((err, values) => {
if (!err) {
let data = new FormData();
//Append files to form data
//data.append(

const options = {
method: 'post',
body: JSON.stringify(
{
Title: this.state.Title,
Url: this.state.Url,
SiteDesign: this.state.SiteDesign,
Description: this.state.Description,
Owner: this.state.Owner,
Lcid: this.state.Lcid,
PageTemplateIds: this.state.PageTemplateIds
}),
headers: {
'Content-Type': 'application/json; charset=utf-8'
}
};

adalApiFetch(fetch, /SiteCollection/CreateCommunicationSite, options)
.then(response =>{
if(response.status === 201){
Notification(
'success',
'Communication Site created',
''
);
}else{
throw error;
}
})
.catch(error => {
Notification(
'error',
'Site collection not created',
error
);
console.error(error);
});
}
});
}

render() {
const { getFieldDecorator } = this.props.form;
const formItemLayout = {
labelCol: {
xs: { span: 24 },
sm: { span: 6 },
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 14 },
},
};
const tailFormItemLayout = {
wrapperCol: {
xs: {
span: 24,
offset: 0,
},
sm: {
span: 14,
offset: 6,
},
},
};
return (
<Form onSubmit={this.handleSubmit}>
<FormItem {...formItemLayout} label=Title hasFeedback>
{getFieldDecorator('Title', {
rules: [
{
required: true,
message: 'Please input your communication site title',
}
]
})(<Input name=title id=title onChange={this.handleChangeTitle} />)}
</FormItem>
<FormItem {...formItemLayout} label=Communication Site Url hasFeedback>
{getFieldDecorator('communicationSiteUrl', {
rules: [
{
required: true,
message: 'CommunicationSite site collection url',
},
{
validator: this.handleValidationCommunicationSiteUrl
}
]
})(<Input name=communicationsSiteUrl id=communicationsSiteUrl onChange={this.handleChangeCommunicationSiteUrl} />)}
</FormItem>
<FormItem {...formItemLayout} label=Site Design hasFeedback>
{getFieldDecorator('sitedesign', {
rules: [
{
required: true,
message: 'Please input your site design',
}
]
})(<Input name=sitedesign id=sitedesign onChange={this.handleChangeSiteDesign} />)}
</FormItem>
<FormItem {...formItemLayout} label=Description hasFeedback>
{getFieldDecorator('description', {
rules: [
{
required: true,
message: 'Please input your description',
}
],
})(<Input name=description id=description onChange={this.handleChangeDescription} />)}
</FormItem>
<FormItem {...formItemLayout} label=Owner hasFeedback>
{getFieldDecorator('owner', {
rules: [
{
required: true,
message: 'Please input your owner',
}
],
})(<Input name=owner id=owner onChange={this.handleChangeOwner} />)}
</FormItem>
<FormItem {...formItemLayout} label=Lcid hasFeedback>
{getFieldDecorator('lcid', {
rules: [
{
required: true,
message: 'Please input your lcid',
}
],
})(<Input name=lcid id=lcid onChange={this.handleChangelcid} />)}
</FormItem>

<ListPageTemplatesWithSelection onRowSelect={this.handleRowSelect} selectedRows={this.state.PageTemplateIds}/>


<FormItem {...tailFormItemLayout}>
<Button type=primary htmlType=submit>
Create communication site
</Button>
</FormItem>


</Form>



);
}
}

const WrappedCreateCommunicationSiteCollectionForm = Form.create()(CreateCommunicationSiteCollectionForm);
export default WrappedCreateCommunicationSiteCollectionForm;

More From » reactjs

 Answers
14

It is very difficult to guess what went wrong from the error you provided. So the best I can do is to point out a few things that you should take care of.



The render method of getColumnSearchProps() is erroneous. If the text is null (due to a row not having any Tags) it will try to convert it to a string and crash. To avoid that, check text exists before rendering:



render: text =>
text ? (
<Highlighter
highlightStyle={{ backgroundColor: #ffc069, padding: 0 }}
searchWords={[this.state.searchText]}
autoEscape
textToHighlight={text.toString()}
/>
) : null


The same applies for onFilter method:



onFilter: (value, record) =>
record[dataIndex]
? record[dataIndex]
.toString()
.toLowerCase()
.includes(value.toLowerCase())
: false,


You have two render methods for rendering Tags column. One inside getColumnSearchProps() and one after ...this.getColumnSearchProps('Tags') call. This should be fine because the later will override the previous. Then again, why would you declare the precious if you don't need it?



Hope this helps.


[#52458] Monday, March 4, 2019, 5 Years  [reply] [flag answer]
Only authorized users can answer the question. Please sign in first, or register a free account.
keric

Total Points: 572
Total Questions: 93
Total Answers: 97

Location: Cyprus
Member since Mon, Oct 24, 2022
2 Years ago
;