当列是 JSON 数组而不是字符串时如何过滤 ANTD 表
Posted
技术标签:
【中文标题】当列是 JSON 数组而不是字符串时如何过滤 ANTD 表【英文标题】:How to filter on ANTD table when the column is a JSON array instead of a string 【发布时间】:2019-07-30 10:29:11 【问题描述】:我有一个包含 2 列的 antd 表,我需要在第一列进行过滤,并在第二列搜索文本。
从我的代码中,应用程序渲染得很好。请注意 tags 字段是 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;
【问题讨论】:
能否给个codepen项目? 我看不到任何状态:任何;在你的代码中。这是在驱动类中实现的吗?您必须查找定义“状态”的位置,然后才能找到问题。 我不知道什么是 codepend,它可能不会运行,因为它有带身份验证的服务器端 api insrc/helpers/AsyncFunc.js:26 23 | const default: Component = await importComponent();
这实际上是未定义的吗?一些错误的递归导入?
【参考方案1】:
正如另一个帖子中所说,如果您尝试导入不存在的组件,则可能会出现此错误。确保您没有拼写错误,并且该组件确实以这种方式命名。如果是库,请确保使用正确的版本,因为组件在不同版本中可能有不同的名称。
有类似问题的链接:Uncaught Error: Invariant Violation: Element type is invalid: expected a string (for built-in components) or a class/function but got: objectReact.createElement: type is invalid -- expected a string or a class/function but got: undefined
【讨论】:
【参考方案2】:很难从您提供的错误中猜测出了什么问题。所以我能做的最好的就是指出一些你应该注意的事情。
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')
调用之后。这应该没问题,因为后者将覆盖前者。话说回来,贵重的东西不需要的话,为什么要申报呢?
希望这会有所帮助。
【讨论】:
highlighter 它的另一个组件,它突出显示您搜索的文本,就像我认为的 antd 文档中的那样 我明白了。您可以尝试删除getColumnSearchProps()
的渲染方法,因为您稍后会提供自己的渲染方法并看到它有效。
我把第二个地方的render去掉了,修改了onfilter如上图,还是报同样的错误screencast.com/t/UZkm6bRBq
我复制了您的代码here,它工作正常。看起来问题可能出在其他地方。如果您可以添加与错误相关的其他部分的MCVE(例如AsyncFunc.js
),这可能会有所帮助。
我稍后会在这里更新问题,基本上该组件嵌入在我编写的另一个组件中,上层组件链的其余部分来自模板,所以我希望我不必更改模板组件上的任何内容,我相信 AsyncFunc.cs 不是我的代码,但我会稍后检查并在此处更新以上是关于当列是 JSON 数组而不是字符串时如何过滤 ANTD 表的主要内容,如果未能解决你的问题,请参考以下文章
当列是NTEXT时,SQL Server:IN('asd')不工作
PySpark:当列是列表时,将列添加到 DataFrame
当列是现有列的布尔测试时,为啥向 Pandas DataFrame 添加列会返回 SettingWithCopy 警告?