好吧,這是一個很難寫的問題,讓我看看我能否正確解釋自己。如何正確使用打字稿中的工廠方法
在Sharepoint中,ListItem具有默認屬性,id,title,createdby,createddate,modifiedby,modifieddate。
但是,您可以創建包含更多列的自定義列表,但它們從基本列表繼承,因此任何新列都將添加到以前的列中。
我的想法是在SharePoint中創建框架與打字稿一個通用的解決方案並作出反應,以便能夠從任何列表讀取和渲染使用Office UI面料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只有一個方法,你可以看到返回列表項
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方法以及我的問題集中在哪裏的渲染方法。
在呈現的方法,該組件接收的項目陣列也是一個列陣列。
在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}`);
}
}
你有沒有考慮過使用策略設計模式?這將是更靈活的解決方案,海事組織 –