嗯,这是一个很难写的问题,让我们看看能不能正确解释自己。
在Sharepoint中,ListItem默认具有属性,id,title,createdby,createddate,modifiedby,modifieddate。
但您可以创建包含更多列的自定义列表,但它们会从基本列表继承,因此任何新列都将添加到以前的列中。
我的想法是使用typescript在Sharepoint Framework中创建一个通用解决方案,并做出反应,以便能够从任何列表中读取并使用Office UI Fabric DetailsList组件进行渲染:https://developer.microsoft.com/en-us/fabric#/components/detailslist
所以我开始使用模型:
ListIitem.ts
export class ListItem {
constructor(
public id: string,
public title: string,
public modified: Date,
public created: Date,
public modifiedby: string,
public createdby: string,
) { }
}
DirectoryListItem.ts
import {ListItem} from './ListItem';
export class DirectoryListItem extends ListItem {
constructor(
public id: string,
public title: string,
public modified: Date,
public created: Date,
public modifiedby: string,
public createdby: string,
public firstName: string,
public lastName: string,
public mobileNumber: string,
public internalNumber: string,
) {
super(id, title, modified, created, modifiedby, createdby);
}
}
AnnoucementLIstItem.ts
import {ListItem} from './ListItem';
export class AnnouncementListItem extends ListItem {
constructor(
public id: string,
public title: string,
public modified: Date,
public created: Date,
public modifiedby: string,
public createdby: string,
public announcementBody: string,
public expiryDate: Date
) {
super(id, title, modified, created, modifiedby, createdby);
}
}
等等。
然后我创建了一个只有一个方法的ListItemFactory,你可以看到它返回一个ListItem数组
import { SPHttpClient, SPHttpClientResponse } from '@microsoft/sp-http';
import { IWebPartContext } from '@microsoft/sp-webpart-base';
import {ListItem} from './models/ListItem';
export class ListItemFactory{
public _getItems(requester: SPHttpClient, siteUrl: string, listName: string): ListItem[] {
let items: ListItem[];
requester.get(`${siteUrl}/_api/web/lists/getbytitle('${listName}')/items?$select=Title,Id`,
SPHttpClient.configurations.v1,
{
headers: {
'Accept': 'application/json;odata=nometadata',
'odata-version': ''
}
})
.then((response: SPHttpClientResponse): Promise<{ value: ListItem[] }> => {
return response.json();
})
.then((response: { value: ListItem[] }): void => {
items= response.value;
});
return items;
}
}
其他工厂看起来也很相似:
import { SPHttpClient, SPHttpClientResponse } from '@microsoft/sp-http';
import {ListItemFactory} from './ListItemFactory';
import {ListItem} from './models/ListItem';
import {DirectoryListItem} from './models/DirectoryListItem';
export class DirectoryListItemFactory extends ListItemFactory {
public _getItems(requester: SPHttpClient, siteUrl: string, listName: string): DirectoryListItem[] {
let items: DirectoryListItem[];
requester.get(`${siteUrl}/_api/web/lists/getbytitle('${listName}')/items?$select=Title,Id`,
SPHttpClient.configurations.v1,
{
headers: {
'Accept': 'application/json;odata=nometadata',
'odata-version': ''
}
})
.then((response: SPHttpClientResponse): Promise<{ value: DirectoryListItem[] }> => {
return response.json();
})
.then((response: { value: DirectoryListItem[] }): void => {
items= response.value;
});
return items;
}
}
唯一的区别是,它不是返回ListItem,而是返回DirectoryListItem数组。
直到那里,一切都很清楚,然后我的组件将作为参数之一接收列表名称。
密切关注readItems方法,以及我的问题所关注的渲染方法。
在render方法中,组件接收一个item数组,但也接收一个列数组。
在readItems上我有一个switch语句,根据所选列表名称,我使用不同的工厂并返回适当数组类型的项目。
但是我不确定,如何正确地将项目和列参数传递给DetailList组件,以使此解决方案尽可能通用。
import * as React from 'react';
import styles from './FactoryMethod.module.scss';
import { IFactoryMethodProps } from './IFactoryMethodProps';
import { IFactoryMethodCrudState } from './IFactoryMethodCrudState';
import { ListItem } from './models/ListItem';
import { escape } from '@microsoft/sp-lodash-subset';
import { SPHttpClient, SPHttpClientResponse } from '@microsoft/sp-http';
import { ListItemFactory} from './ListItemFactory';
import { AnnouncementListItemFactory} from './AnnouncementListItemFactory';
import { DirectoryListItemFactory} from './DirectoryListItemFactory';
import { NewsListItemFactory} from './NewsListItemFactory';
import { TextField } from 'office-ui-fabric-react/lib/TextField';
import {
DetailsList,
DetailsListLayoutMode,
Selection
} from 'office-ui-fabric-react/lib/DetailsList';
import { MarqueeSelection } from 'office-ui-fabric-react/lib/MarqueeSelection';
import { autobind } from 'office-ui-fabric-react/lib/Utilities';
let _items: any[];
let _columns = [
{
key: 'column1',
name: 'Name',
fieldName: 'name',
minWidth: 100,
maxWidth: 200,
isResizable: true
},
{
key: 'column2',
name: 'Value',
fieldName: 'value',
minWidth: 100,
maxWidth: 200,
isResizable: true
},
];
export default class FactoryMethod extends React.Component<any, any> {
private listItemEntityTypeName: string = undefined;
private _selection: Selection;
constructor(props: IFactoryMethodProps, state: IFactoryMethodCrudState) {
super(props);
/* this.state = {
status: this.listNotConfigured(this.props) ? 'Please configure list in Web Part properties' : 'Ready',
items: []
}; */
this._selection = new Selection({
onSelectionChanged: () => this.setState({ selectionDetails: this._getSelectionDetails() })
});
this.state = {
status: this.listNotConfigured(this.props) ? 'Please configure list in Web Part properties' : 'Ready',
items: _items,
selectionDetails: this._getSelectionDetails()
};
}
public componentWillReceiveProps(nextProps: IFactoryMethodProps): void {
this.listItemEntityTypeName = undefined;
this.setState({
status: this.listNotConfigured(nextProps) ? 'Please configure list in Web Part properties' : 'Ready',
items: []
});
}
public render(): React.ReactElement<IFactoryMethodProps> {
let { items, selectionDetails } = this.state;
return (
<div>
<div>{ selectionDetails }</div>
<TextField
label='Filter by name:'
onChanged={ this._onChanged }
/>
<MarqueeSelection selection={ this._selection }>
<DetailsList
items={ items }
columns={ _columns }
setKey='set'
layoutMode={ DetailsListLayoutMode.fixedColumns }
selection={ this._selection }
selectionPreservedOnEmptyClick={ true }
onItemInvoked={ this._onItemInvoked }
compact={ true }
/>
</MarqueeSelection>
</div>
);
}
private readItems(): void {
this.setState({
status: 'Loading all items...',
items: []
});
//Here its where we actually use the pattern to make our coding easier.
switch(this.props.listName)
{
case "List":
let factory = new ListItemFactory();
let listItems = factory._getItems(this.props.spHttpClient, this.props.siteUrl, this.props.listName);
this.setState({
status: `Successfully loaded ${listItems.length} items`,
items: listItems
});
break;
case "Announcements":
let announcementFactory = new AnnouncementListItemFactory();
let announcementlistItems = announcementFactory._getItems(this.props.spHttpClient, this.props.siteUrl, this.props.listName);
this.setState({
status: `Successfully loaded ${listItems.length} items`,
items: announcementlistItems
});
break;
case "News":
let newsFactory = new NewsListItemFactory();
let newsListItems = newsFactory._getItems(this.props.spHttpClient, this.props.siteUrl, this.props.listName);
this.setState({
status: `Successfully loaded ${listItems.length} items`,
items: newsListItems
});
break;
case "Directory":
let directoryFactory = new DirectoryListItemFactory();
let directoryListItems = directoryFactory._getItems(this.props.spHttpClient, this.props.siteUrl, this.props.listName);
this.setState({
status: `Successfully loaded ${listItems.length} items`,
items: directoryListItems
});
break;
default :
break;
}
}
private _getSelectionDetails(): string {
let selectionCount = this._selection.getSelectedCount();
switch (selectionCount) {
case 0:
return 'No items selected';
case 1:
return '1 item selected: ' + (this._selection.getSelection()[0] as any).name;
default:
return `${selectionCount} items selected`;
}
}
private listNotConfigured(props: IFactoryMethodProps): boolean {
return props.listName === undefined ||
props.listName === null ||
props.listName.length === 0;
}
@autobind
private _onChanged(text: any): void {
this.setState({ items: text ? _items.filter(i => i.name.toLowerCase().indexOf(text) > -1) : _items });
}
private _onItemInvoked(item: any): void {
alert(`Item invoked: ${item.name}`);
}
}
答案 0 :(得分:1)
很抱歉,但我可能误解了你的问题;但是,如果你想在另一个中注入obj,为什么要扩展列表?我将用代码解释:
TableColumn
&#13;
可能这不是你要求的,但如果我理解你的课程问题可能会有用。 希望这有帮助。