我有一个带有2列的antd表,我需要在第一列上进行过滤,并在第二列上搜索文本。
根据我的代码,该应用程序呈现良好。请注意,标签字段是一个json数组,而不是文本字段,因此我想这与错误有关。
更新了1个代码。
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;
但是,当我添加以下行时:
...this.getColumnSearchProps('Tags'),
然后我得到这个错误
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 | }
更新2
这是容器组件
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;
最佳答案
很难从您提供的错误中猜测出了什么问题。因此,我能做的最好的事情就是指出您应该注意的几件事。getColumnSearchProps()
的呈现方法是错误的。如果文本是null
(由于一行没有任何标签),它将尝试将其转换为字符串并崩溃。为了避免这种情况,请在渲染之前检查text
是否存在:
render: text =>
text ? (
<Highlighter
highlightStyle={{ backgroundColor: "#ffc069", padding: 0 }}
searchWords={[this.state.searchText]}
autoEscape
textToHighlight={text.toString()}
/>
) : null
onFilter
方法也是如此:onFilter: (value, record) =>
record[dataIndex]
? record[dataIndex]
.toString()
.toLowerCase()
.includes(value.toLowerCase())
: false,
您有两种
render
方法来呈现“标签”列。一个在getColumnSearchProps()
内部,另一个在...this.getColumnSearchProps('Tags')
调用之后。这应该没问题,因为后者会覆盖前一个。再说一次,如果您不需要它,为什么还要宣布它为珍贵?希望这可以帮助。