如何正确使用打字稿中的工厂方法
好吧,这是一个很难写的问题,让我看看我能否正确解释自己。如何正确使用打字稿中的工厂方法
在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}`);
}
}
很抱歉,但我可能误解了你的问题;但是如果你想在另一个中注入一个obj,你为什么要扩展这个列表?我会用代码来解释:
import {ListItem} from './ListItem';
export class DirectoryListItem {
constructor(
public listIt: ListItem;
// instead of repeating code, you inject your base-obj listItem
public firstName: string,
public lastName: string,
public mobileNumber: string,
public internalNumber: string,
) { }
}
也许这不是你问什么,但如果我理解你的类的问题可能是有用的。 希望这有助于。
你有没有考虑过使用策略设计模式?这将是更灵活的解决方案,海事组织 –