S H A R E P O I N T C E N T E R

این webpart، آیتم‌های لیست شیرپوینت را فراتر از حد آستانه بازیابی می کند و نتایج را با استفاده از DetailsList Office UI fabric component نمایش می دهد. با توجه به محدودیت آستانه مشاهده لیست شیرپوینت، کاربران بدون admin rights نمی توانند آیتم‌های لیست شیرپوینت را بررسی کنند. افزودن و پیکربندی این webpart به کاربرانی که حداقل مجوزهای خواندن سایت را دارند این امکان را می دهد تا همه موارد را از لیست مشاهده کنند.


 webpart فریم ورک شیرپوینت برای بازیابی آیتم‌های لیست شیرپوینت با استفاده از React & Rest API و نمایش نتایج با استفاده از جزییات DetailsList Office UI fabric component

پیش نیازها

  • پروژه ViewAllItemsWebPart را با اجرای Yeoman SharePoint Generator ایجاد کنید
  • react Paging component را نصب کنید
  • jQuery را نصب کنید

استفاده از کد

در ادامه کامپوننت‌هایی که به عنوان بخشی از این webpart ایجاد شده‌اند، فهرست شده است:

  • Custom property pane - یک کنترل صفحه ویژگی سفارشی برای نشان دادن یک منوی کشویی چند انتخابی برای پر کردن ستون ها هنگام انتخاب ویژگی لیست.
  • Config - اگر ویژگی‌های webpart پیکربندی نشده باشند، مؤلفه پیکربندی ارائه می‌شود.
  • Paging - این react paging component است که برای افزودن صفحه بندی به نمای لیست استفاده می شود.
  • ViewAllItems – کامپوننتی که DetailsList Office UI fabric component را رندر می‌کند و آیتم های لیست را به آن متصل می‌کند.
  • services - شامل روش‌هایی برای دریافت لیست‌ها و ستون‌ها از شیرپوینت با استفاده از Rest API است.

بیایید با modifying the scaffolding که توسط Yeoman Generator تولید شده است شروع کنیم.

 

WebPart.manifest.json

بخش webpart manifest json file properties section را ویرایش کنید تا شامل سه ویژگی نام لیست (listName)، نام ستون (selectedIds) و اندازه صفحه (pageSize) باشد و مقادیر پیش فرض را مطابق شکل تنظیم کنید.

"properties": {
"listName": "",
"selectedIds":[],
"pageSize": 100
}

 

تعریف Webpart Property Constants  و  Property Types

در پوشه loc، en-us.js و mystrings.js را به‌روزرسانی کنید تا اسکریپت زیر را شامل شود. این‌ها برای تعریف ثابت‌های ویژگی و انواع ویژگی‌هایی است که در پیکربندی webpart property pane مورد نیاز هستند.

en-us.js

define([], function() {
return {
"PropertyPaneDescription": "Description",
"BasicGroupName": "Group Name",
"ListNameFieldLabel": "Select List",
"ColumnFieldLabel": "Select Columns",
"PageSizeFieldLabel": "Select Page Size"
}
});

 

mystrings.d.ts

declare interface IViewAllItemsWebPartStrings {
PropertyPaneDescription: string;
BasicGroupName: string;
ListNameFieldLabel: string;
ColumnFieldLabel: string;
PageSizeFieldLabel: string;
}

declare module 'ViewAllItemsWebPartStrings' {
const strings: IViewAllItemsWebPartStrings;
export = strings;
}

 

Webpart.ts

imports های زیر را به فایل webpart.ts اضافه کنید:

import * as React from 'react';
import * as ReactDom from 'react-dom';
import { Version } from '@microsoft/sp-core-library';
import {
BaseClientSideWebPart,
IPropertyPaneConfiguration,
PropertyPaneDropdown,
IPropertyPaneDropdownOption
} from '@microsoft/sp-webpart-base';

import * as strings from 'ViewAllItemsWebPartStrings';
import ViewAllItems from './components/ViewAllItems';
import { IViewAllItemsProps } from './components/IViewAllItemsProps';
import { IList } from './services/IList';
import { IListColumn } from './services/IListColumn';
import { ListService } from './services/ListService';
import { MultiSelectBuilder, IItemProp, PropertyPaneMultiSelect }
from './CustomPropertyPane/PropertyPaneMultiSelect';
import { IDropdownOption } from 'office-ui-fabric-react/lib/components/Dropdown';

خطوط کد موجود در متد getPropertyPaneConfiguration را حذف کرده و خطوط کد زیر را اضافه کنید:

protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
return {
pages: [
{
header: {
description: strings.PropertyPaneDescription
},
groups: [
{
groupName: strings.BasicGroupName,
groupFields: [
PropertyPaneDropdown('listName', {
label: strings.ListNameFieldLabel,
options: this.lists,
disabled: this.listsDropdownDisabled,

}),
PropertyPaneMultiSelect("selectedIds", {
label: "Select Columns",
selectedItemIds: this.properties.selectedIds, //Ids of Selected Items
onload: () => this.loadColumns(), //On load function to items for drop down
onPropChange: this.onPropertyPaneFieldChanged, // On Property Change function
properties: this.properties, //Web Part properties
key: "targetkey", //unique key
disabled: !this.properties.listName
}),
PropertyPaneDropdown('pageSize',{
label: strings.PageSizeFieldLabel,
options:[
{key: '10', text: '10'},
{key: '25', text: '25'},
{key: '50', text: '50'},
{key: '100', text: '100'}
]
})
]
}
]
}
]
};
}

PropertyPaneMultiselect در واقع  custom property pane component است.

روش‌هایی را در PropertyPaneConfigurationStart و onPropertyPaneFieldChanged به کلاس webpart اضافه کنید تا فهرست کشویی آبشاری یا همان cascading dropdown ایجاد کنید و property pane controls را با داده‌ها بارگیری کنید.

protected onPropertyPaneConfigurationStart(): void {
this.listsDropdownDisabled = !this.lists;

if (this.lists) {
return;
}

this.context.statusRenderer.displayLoadingIndicator(this.domElement, 'lists');

this.loadLists()
.then((listOptions: IPropertyPaneDropdownOption[]): void => {
this.lists = listOptions;
this.listsDropdownDisabled = false;
this.context.propertyPane.refresh();
this.context.statusRenderer.clearLoadingIndicator(this.domElement);
this.render();
});
}

protected onPropertyPaneFieldChanged(propertyPath: string, oldValue: any, newValue: any): void {
if (propertyPath === 'listName' && newValue) {
// push new list value
super.onPropertyPaneFieldChanged(propertyPath, oldValue, newValue);
// get previously selected column
const previousItem: string[] = this.properties.selectedIds;
// reset selected item
this.properties.selectedIds = [];
// push new item value
this.onPropertyPaneFieldChanged('selectedIds', previousItem, this.properties.selectedIds);

//this.columnsDropdown.render(this.domElement);

this.render();
// refresh the item selector control by repainting the property pane
this.context.propertyPane.refresh();

}
else {
super.onPropertyPaneFieldChanged(propertyPath, oldValue, newValue);
}
}

اگر متوجه شدید که متدهای بالا متدهای loadLists و loadColumns را برای دریافت داده فراخوانی می کنند، متدهای زیر را به کلاس webpart اضافه کنید.

private loadLists(): Promise<IPropertyPaneDropdownOption[]> {
const dataService = new ListService(this.context);

return new Promise<IPropertyPaneDropdownOption[]>(resolve => {
dataService.getLists()
.then((response: IList[]) => {
var options : IPropertyPaneDropdownOption[] = [];

response.forEach((item: IList) => {
options.push({"key": item.Title, "text": item.Title});
});

resolve(options);
});
});
}

private loadColumns(): Promise<IItemProp[]> {
if (!this.properties.listName) {
// resolve to empty options since no list has been selected
return Promise.resolve();
}
const dataService = new ListService(this.context);

return new Promise<IItemProp[]>(resolve => {
dataService.getColumns(this.properties.listName)
.then((response) => {
var options : IItemProp[] = [];
this.properties.selectedColumnsAndType = [];
response.forEach((column: IListColumn) => {
options.push({"key": column.StaticName, "text": column.Title});
this.properties.selectedColumnsAndType.push
({"key": column.StaticName, "text": column.TypeDisplayName});
});

resolve(options);
});
});
}

به نوبه خود، این روش ها برای دریافت داده ها به کلاس ListService مراجعه می کنند. خدمات پوشه جدید را به راه حل ها اضافه کنید و فایل های ILists.ts، IListColumn.ts، ListService.ts را اضافه کنید.

ILists.ts

Interface IList.ts درواقع metadata لیستی را تعریف می کند که از بقیه درخواست های API درخواست می شود. این رابط شناسه(id) و عنوان لیست(title) را دریافت می کند.

export interface IList {
Id: string;
Title: string;
}

 

IListColumns.ts

Interface IListColumns فراداده ستونی را که از درخواست API درخواست می‌شود، تعریف می‌کند، که عنوان ستون(title )، نام داخلی(Internal name) و نوع ستون(column type) را دریافت می کند.

export interface IListColumn {
Title: string;
StaticName: string;
TypeDisplayName: string;
}

ListService.ts

اسکریپت زیر را به فایل ListService.ts اضافه کنید. این فایل متدهای getLists و GetColumns را تشکیل می‌دهد که اطلاعات لیست‌ها و ستون‌ها را از شیرپوینت با ارسال محتوای فعلی سایت که به SharePoint REST API به عنوان پارامتر url به درخواست HTTP اضافه شده است، دریافت می‌کند.

export class ListService {

constructor(private context: IWebPartContext) {
}

public getLists(): Promise<IList[]> {
var httpClientOptions : ISPHttpClientOptions = {};

httpClientOptions.headers = {
'Accept': 'application/json;odata=nometadata',
'odata-version': ''
};

return new Promise<IList[]>((resolve: (results: IList[]) => void,
reject: (error: any) => void): void => {
this.context.spHttpClient.get(this.context.pageContext.web.serverRelativeUrl +
`/_api/web/lists?$select=id,title&$filter=Hidden eq false`,
SPHttpClient.configurations.v1,
httpClientOptions
)
.then((response: SPHttpClientResponse): Promise<{ value: IList[] }> => {
return response.json();
})
.then((lists: { value: IList[] }): void => {
resolve(lists.value);
}, (error: any): void => {
reject(error);
});
});
}

public getColumns(listName: string): Promise<IListColumn[]> {
var httpClientOptions : ISPHttpClientOptions = {};

httpClientOptions.headers = {
'Accept': 'application/json;odata=nometadata',
'odata-version': ''
};

return new Promise<IListColumn[]>((resolve: (results: IListColumn[]) => void,
reject: (error: any) => void): void => {
this.context.spHttpClient.get(this.context.pageContext.web.serverRelativeUrl +
`/_api/web/lists/GetByTitle('${listName}')/fields?$filter=TypeDisplayName ne
'Attachments' and Hidden eq false and ReadOnlyField eq false`,
SPHttpClient.configurations.v1,
httpClientOptions
)
.then((response: SPHttpClientResponse): Promise<{ value: IListColumn[] }> => {
return response.json();
})
.then((listColumns: { value: IListColumn[] }): void => {
resolve(listColumns.value);
}, (error: any): void => {
reject(error);
});
});
}
}

متدهای زیر را به کلاس webpart اضافه کنید. هنگامی که متد webpart render فراخوانی می شود، این متدها به عنوان ویژگی به عنصر ReactDOM ارسال می شوند.

  • needsCofiguration - مشخص می‌کند که آیا ویژگی‌های webpart که برای ارائه نمای مورد نیاز است پیکربندی شده است یا خیر.
  • selectedColumns - ستون‌هایی را که از custom property pane control انتخاب شده‌اند را برمی‌گرداند.
  • configureWebPart - این متد وقتی فراخوانی می‌شود، صفحه ویژگی webpart را باز می‌کند.

private needsConfiguration(): boolean {
return this.properties.listName === null ||
this.properties.listName === undefined ||
this.properties.listName.trim().length === 0 ||
this.properties.selectedIds === null ||
this.properties.selectedIds === undefined ||
this.properties.selectedIds.length === 0;
}

private selectedColumns(): IItemProp[] {
if(this.properties.selectedColumnsAndType === null ||
this.properties.selectedColumnsAndType===undefined ||
this.properties.selectedColumnsAndType.length === 0){
return [];
}
else{
return this.properties.selectedColumnsAndType.filter
(obj => this.properties.selectedIds.indexOf(obj.key) !== -1);
}
}
private configureWebPart(): void {
this.context.propertyPane.open();
}

کد موجود در متد webpart renderرا حذف کنید، کد زیر را copy و paste کنید:

public render(): void {
const element: React.ReactElement<IViewAllItemsProps> = React.createElement(
ViewAllItems,
{
spHttpClient: this.context.spHttpClient,
siteUrl: this.context.pageContext.web.absoluteUrl,
listName: this.properties.listName,
needsConfiguration: this.needsConfiguration(),
configureWebPart: this.configureWebPart,
displayMode: this.displayMode,
selectedColumns: this.selectedColumns(),
pageSize: this.properties.pageSize
}
);

ReactDom.render(element, this.domElement);
}

متد render، JSX را از کامپوننت ViewAllItems.tsx بارگیری می کند. فایل‌های ViewAllItems.tsx، IVewAllItemsProps.ts، ViewAllItems.module.scss را به راه حل اضافه کنید.

IViewAllItemsProps.ts

این فایل interface تمام خصوصیاتی را که برای بارگذاری کامپوننت در ReactDOM لازم است تعریف می کند.

export interface IViewAllItemsProps {
spHttpClient: SPHttpClient;
siteUrl: string;
listName: string;
selectedColumns: IItemProp[];
needsConfiguration:boolean;
configureWebPart: () => void;
displayMode: DisplayMode;
pageSize: number;
}

ViewAllItems.module.scss

این فایل ها شامل تمام styles هایی هستند که در فایل ViewAllItems.tsx استفاده می شوند.

@import '~@microsoft/sp-office-ui-fabric-core/dist/sass/SPFabricCore.scss';

.viewAllItems {
.container {
margin: 0px auto;
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), 0 25px 50px 0 rgba(0, 0, 0, 0.1);
}

.row {
@include ms-Grid-row;
@include ms-fontColor-white;
background-color: $ms-color-themeDark;
padding: 20px;
}

.column {
@include ms-Grid-col;
@include ms-lg10;
@include ms-xl8;
@include ms-xlPush2;
@include ms-lgPush1;
}

.title {
@include ms-font-xl;
@include ms-fontColor-white;
}

.subTitle {
@include ms-font-l;
@include ms-fontColor-white;
}

.description {
@include ms-font-l;
@include ms-fontColor-white;
}
.status{
float:left
}
.button {
// Our button
text-decoration: none;
height: 32px;

// Primary Button
min-width: 80px;
background-color: $ms-color-themePrimary;
border-color: $ms-color-themePrimary;
color: $ms-color-white;

// Basic Button
outline: transparent;
position: relative;
font-family: "Segoe UI WestEuropean","Segoe UI",-apple-system,
BlinkMacSystemFont,Roboto,"Helvetica Neue",sans-serif;
-webkit-font-smoothing: antialiased;
font-size: $ms-font-size-m;
font-weight: $ms-font-weight-regular;
border-width: 0;
text-align: center;
cursor: pointer;
display: inline-block;
padding: 0 16px;

.label {
font-weight: $ms-font-weight-semibold;
font-size: $ms-font-size-m;
height: 32px;
line-height: 32px;
margin: 0 4px;
vertical-align: top;
display: inline-block;
}
}
}

ViewAllItems.tsx

کلاس ViewAllItems از React.Component که Props و State را به عنوان آرگومان دارد ارث می برد. ما Props (IViewAllItemsProps.ts) را تعریف کرده ایم. state را همانطور که در ادامه در فایل tsx بالای کلاس نشان داده شده است تعریف کنید.

export interface IViewAllItemsState {
items?: any[];
columns?:IColumn[];
status?: string;
currentPage?: number;
itemCount?: number;
pageSize?: number;
}

داخل کلاس، تعریف Constructor را اضافه کنید. این ویژگی های پیش فرض و state زمانی که کامپوننت در ابتدا بارگذاری می شود را تنظیم می کند.

private selectQuery: string[] = [];//global variable to set the select query params
//for the rest api request
private expandQuery: string[] = [];//global variable to expand the params for people picker
//and lookup column types
constructor(props: IViewAllItemsProps){
super(props);

this.state ={
items:[],
columns: this.buildColumns(this.props),
currentPage:1,
pageSize: this.props.pageSize
};
this._onPageUpdate = this._onPageUpdate.bind(this);
this.getListItemsCount(`${this.props.siteUrl}/_api/web/lists/GetByTitle
('${props.listName}')/ItemCount`);
const queryParam = this.buildQueryParams(props);
this.readItems(`${this.props.siteUrl}/_api/web/lists/GetByTitle
('${props.listName}')/items${queryParam}`);
}

متد componentWillReceiveProps را به کلاس ViewAllItems اضافه کنید. این روش چرخه حیات متد است که در صورت تغییر ویژگی های ارائه شده برای این کامپوننت، JSX را ارائه می دهد.

public componentWillReceiveProps(nextProps: IViewAllItemsProps): void{

this.setState({
columns:this.buildColumns(nextProps),
pageSize: nextProps.pageSize
});
this.getListItemsCount(`${this.props.siteUrl}/_api/web/lists/GetByTitle
('${this.props.listName}')/ItemCount`);
//const selectColumns = nextProps.selectedColumns === null ||
//nextProps.selectedColumns===undefined || nextProps.selectedColumns.length === 0? "" :
//'?$select='+nextProps.selectedColumns.join();
const queryParam = this.buildQueryParams(nextProps);
this.readItems(`${this.props.siteUrl}/_api/web/lists/GetByTitle
('${nextProps.listName}')/items${queryParam}`);
}

با قطعه کد زیر متد render را به کلاس اضافه کنید. هنگامی که عنصر JSX در DOM بارگذاری می‌شود، با فراخوانی این متد که در کلاس webpart که یک Boolean برمی‌گرداند، بررسی می‌کند که آیا webpart به پیکربندی نیاز دارد یا خیر. اگر متد true را برگرداند، جزء پیکربندی JSX را در DOM بارگذاری می‌کند، در غیر این صورت JSX فعلی را در DOM بارگذاری می‌کند.

public render(): JSX.Element {

const { needsConfiguration, configureWebPart} = this.props;
let {items, columns, pageSize} = this.state;
return (
<div className={styles.viewAllItems}>
<div>
{needsConfiguration &&
<Config configure={configureWebPart} {...this.props}/>
}
{ needsConfiguration === false &&
<div>
<div>
<div>
<div className={styles.status}>{this.state.status}</div>
<Paging
totalItems={ this.state.itemCount }
itemsCountPerPage={ this.state.pageSize }
onPageUpdate={ this._onPageUpdate }
currentPage={ this.state.currentPage }/>
<div></div>
<DetailsList
items = {items}
columns = {columns}
isHeaderVisible = {true}
layoutMode = {LayoutMode.justified}
constrainMode ={ConstrainMode.unconstrained}
checkboxVisibility={CheckboxVisibility.hidden}
onColumnHeaderClick={ this._onColumnClick }
/>
</div>
</div>
</div>
}
</div>
</div>
);
}

متد readItems را به کلاس ViewAllItems اضافه کنید. این متد آیتم‌های لیست را از شیرپوینت برمی گرداند.

private readItems(url: string) {
this.setState({
items: [],
status: 'Loading all items...'
});

this.props.spHttpClient.get(url,
SPHttpClient.configurations.v1,
{
headers: {
'Accept': 'application/json;odata=nometadata',
'odata-version': ''
}
}).then((response: SPHttpClientResponse): Promise<{value: any[]}> =>{
return response.json();
}).then((response: {value: any[]}): void => {
//this.props.Status(`${response.d.__next}`);
//this.props.siteUrl = response['odata.nextLink'];
this.setState({
items: response.value,
//columns: _buildColumns(response.value),
status: `Showing items ${(this.state.currentPage - 1)*this.props.pageSize +1} -
${(this.state.currentPage -1) * this.props.pageSize + response.value.length}
of ${this.state.itemCount}`
});
}, (error: any): void => {
this.setState({
items: [],
status: 'Loading all items failed with error: ' + error
});
});
}

متد getListItemsCount را اضافه کنید که تعداد آیتم‌های لیست را که توسط مؤلفه Paging برای ایجاد صفحه‌بندی لازم است، برمی‌گرداند.

Private getListItemsCount(url: string) {
this.props.spHttpClient.get(url,SPHttpClient.configurations.v1,
{
headers: {
'Accept': 'application/json;odata=nometadata',
'odata-version':''
}
}).then((response: SPHttpClientResponse): Promise<{value: number}> =>{
return response.json();
}).then((response: {value: number}): void => {
this.setState({
itemCount: response.value
});
});
}

متد _onPageUpdate را به کلاس ViewAllItems اضافه کنید. این متد زمانی فعال می شود که شماره صفحه روی نما کلیک شود. این متد به نوبه خود متد readItems را با ارسال url به روز شده به عنوان آرگومان فراخوانی می کند. URL با skiptoken، شناسه صفحه و اندازه صفحه به عنوان پارامترهایی ساخته شده اند تا هنگام کلیک روی شماره صفحه، موارد مناسب را از لیست دریافت کنید.

private _onPageUpdate(pageNumber: number) {
this.setState({
currentPage: pageNumber,
});
const p_ID = (pageNumber - 1)*this.props.pageSize;
const selectColumns = '&$select='+this.selectQuery;
const expandColumns = '&$expand='+this.expandQuery;
const queryParam = `%24skiptoken=Paged%3dTRUE%26p_ID=${p_ID}&$top=${this.props.pageSize}`;
var url = `${this.props.siteUrl}/_api/web/lists/GetByTitle('${this.props.listName}')/items?`+
queryParam + selectColumns+expandColumns;
this.readItems(url);
}

متد _onColumnClick را به کلاس ViewAllItems اضافه کنید. این متد زمانی فعال می شود که کاربر روی سرصفحه های ستون در نمای لیست کلیک می کند. این متد مرتب سازی نتایج نمایش داده شده را انجام می دهد.

private _onColumnClick(event: React.MouseEvent<HTMLElement>, column: IColumn) {
let { items, columns } = this.state;
let isSortedDescending = column.isSortedDescending;

// If we've sorted this column, flip it.
if (column.isSorted) {
isSortedDescending = !isSortedDescending;
}

// Sort the items.
items = items!.concat([]).sort((a, b) => {
let firstValue = a[column.fieldName];
let secondValue = b[column.fieldName];

if (isSortedDescending) {
return firstValue > secondValue ? -1 : 1;
} else {
return firstValue > secondValue ? 1 : -1;
}
});

// Reset the items and columns to match the state.
this.setState({
items: items,
columns: columns!.map(col => {
col.isSorted = (col.key === column.key);

if (col.isSorted) {
col.isSortedDescending = isSortedDescending;
}
return col;
})
});
}

متدهای buildQueryParams و buildColumns را به کلاس ViewAllItems اضافه کنید.

  • buildQueryParams - این متد رشته کوئری url را برمی گرداند که توسط SharePoint Rest API برای انتخاب و گسترش ستون‌های انتخاب شده در webpart property pane مورد نیاز است.
  • buildColumns - این متد آرایه‌ای از ستون‌ها را برمی‌گرداند که DetailsList office UI fabric component برای ساخت view مورد نیاز است.

private buildQueryParams(props: IViewAllItemsProps): string{
this.selectQuery = [];
this.expandQuery = [];
props.selectedColumns.forEach(element => {
if(element.text === "Person or Group" || element.text === "Lookup"){
this.selectQuery.push(element.key+"/Title");
this.expandQuery.push(element.key);
}
else{
this.selectQuery.push(element.key);
}
});
const queryParam = `?%24skiptoken=Paged%3dTRUE%26p_ID=1&$top=${props.pageSize}`;
const selectColumns = this.selectQuery === null || this.selectQuery===undefined ||
this.selectQuery.length === 0? "" : '&$select='+this.selectQuery.join();
const expandColumns = this.expandQuery === null || this.expandQuery===undefined ||
this.expandQuery.length === 0? "" : '&$expand='+this.expandQuery.join();
return queryParam+selectColumns+expandColumns;
}
private buildColumns(props: IViewAllItemsProps): IColumn[]{
const columns: IColumn[]=[];
props.selectedColumns.forEach(element => {
if(element.text === "Person or Group" || element.text === "Lookup"){
const column: IColumn ={
key: element.key,
name: element.key.indexOf("_x0020_") !== -1?element.key.replace("_x0020_"," "):element.key,
fieldName: element.key,
minWidth: 100,
maxWidth: 350,
isResizable: true,
data: 'string',
onRender: (item: any) => {
return (
<span>
{ item[element.key]["Title"] }
</span>
);
}
};
columns.push(column);
}
else{
const column: IColumn ={
key: element.key,
name: element.key.indexOf("_x0020_") !== -1?element.key.replace("_x0020_"," "):element.key,
fieldName: element.key,
minWidth: 100,
maxWidth: 350,
isResizable: true,
data: 'string',
isMultiline: element.text === "Multiple lines of text" ? true:false
};
columns.push(column);
}
});
return columns;
}

 

کامپوننت پیکربندی

پوشه Config را به راه حل اضافه کنید و سپس فایل های IConfigProp.ts، Config.module.scss و Config.tsx را به این پوشه اضافه کنید.

IConfigProp.ts

رابط IConfigProp.ts خصوصیاتی را که برای بارگذاری مولفه Config.tsx لازم است را تعریف می کند.

import { DisplayMode } from '@microsoft/sp-core-library';

export interface IConfigProps {
displayMode: DisplayMode;
configure: () => void;
}

 

Config.module.scss

این فایل شامل style است که برای استایل دادن به کامپوننت Config.tsx لازم است.

.placeholder {
display: -webkit-box;
display: -ms-flexbox;
display: flex;

.placeholderContainer {
-webkit-box-align: center;
-ms-flex-align: center;
-ms-grid-row-align: center;
align-items: center;
color: "[theme:neutralSecondary, default: #666666]";
background-color: "[theme:neutralLighter, default: #f4f4f4]";
width: 100%;
padding: 80px 0;

.placeholderHead {
color: "[theme:neutralPrimary, default: #333333]";

.placeholderHeadContainer {
height: 100%;
white-space: nowrap;
text-align: center;
}

.placeholderIcon {
display: inline-block;
vertical-align: middle;
white-space: normal;
}

.placeholderText {
display: inline-block;
vertical-align: middle;
white-space: normal
}
}

.placeholderDescription {
width: 65%;
vertical-align: middle;
margin: 0 auto;
text-align: center;

.placeholderDescriptionText {
color: "[theme:neutralSecondary, default: #666666]";
font-size: 17px;
display: inline-block;
margin: 24px 0;
font-weight: 100;
}

button {
font-size: 14px;
font-weight: 400;
box-sizing: border-box;
display: inline-block;
text-align: center;
cursor: pointer;
vertical-align: top;
min-width: 80px;
height: 32px;
background-color: "[theme:themePrimary, default: #0078d7]";
color: #fff;
user-select: none;
outline: transparent;
border-width: 1px;
border-style: solid;
border-color: transparent;
border-image: initial;
text-decoration: none;
}
}
}
}

[dir=ltr] .placeholder,
[dir=rtl] .placeholder {

.placeholderContainer {

.placeholderHead {

.placeholderText {
padding-left: 20px;
}
}
}
}

.placeholderOverlay {
position: relative;
height: 100%;
z-index: 1;

.placeholderSpinnerContainer {
position: relative;
width: 100%;
margin: 164px 0
}
}

 

Config.tsx

کلاس را با قطعه کد زیر در Config.tsx جایگزین کنید. رویداد _handleButtonClick متد configureWebPart را در فایل webpart.ts فعال می‌کند که به عنوان یک ویژگی به این مؤلفه ارسال می‌شود.

import * as React from 'react';
import { Fabric } from 'office-ui-fabric-react';
import { DisplayMode } from '@microsoft/sp-core-library';
import { IConfigProps } from './IConfigProps';
import styles from './Config.module.scss';
import { PrimaryButton } from 'office-ui-fabric-react/lib/Button';

export class Config extends React.Component<IConfigProps, {}> {

constructor(props: IConfigProps){
super(props);
this._handleBtnClick = this._handleBtnClick.bind(this);
}
public render(): JSX.Element {
return (
<Fabric>
{ this.props.displayMode === DisplayMode.Edit &&
<div className={`${styles.placeholder}`}>
<div className={styles.placeholderContainer}>
<div className={styles.placeholderHead}>
<div className={styles.placeholderHeadContainer}>
<i className={`${styles.placeholderIcon} ms-fontSize-su
ms-Icon ms-ICon--CheckboxComposite`}></i>
<span className={`${styles.placeholderText} ms-fontWeight-light
ms-fontSize-xxl`}>Configure your web part</span>
</div>
</div>
<div className={styles.placeholderDescription}>
<span className={styles.placeholderDescriptionText}>Please configure the web part.</span>
</div>
<div className={styles.placeholderDescription}>
<PrimaryButton
text="Configure"
ariaLabel="Configure"
ariaDescription="Please configure the web part"
onClick={this._handleBtnClick} />
</div>
</div>
</div>
}
{ this.props.displayMode === DisplayMode.Read &&
<div className={`${styles.placeholder}`}>
<div className={styles.placeholderContainer}>
<div className={styles.placeholderHead}>
<div className={styles.placeholderHeadContainer}>
<i className={`${styles.placeholderIcon} ms-fontSize-su ms-Icon
ms-ICon--CheckboxComposite`}></i>
<span className={`${styles.placeholderText}
ms-fontWeight-light ms-fontSize-xxl`}>Configure your web part</span>
</div>
</div>
<div className={styles.placeholderDescription}>
<span className={styles.placeholderDescriptionText}>Please configure the web part.</span>
</div>
</div>
</div>
}
</Fabric>
);
}
private _handleBtnClick(event?: React.MouseEvent<HTMLButtonElement>) {
this.props.configure();
}
}

 

Paging Component

پوشه Paging را به راه حل اضافه کنید و سپس فایل‌های IPagingProp.ts، Paging.module.scss و Paging.tsx را به این پوشه اضافه کنید.

IPagingProp.ts

رابط IPagingProp.ts خصوصیاتی را که برای بارگیری کامپوننت Paging.tsx لازم است را تعریف می‌کند.

export interface IPagingProps {
totalItems: number;
itemsCountPerPage: number;
onPageUpdate: (pageNumber: number) => void;
currentPage: number;
}

 

Paging.module.scss

این فایل شامل style است که برای استایل دادن به کامپوننت Paging.tsx لازم است.

.paginationContainer {
text-align: right;
.searchWp__paginationContainer__pagination {
display: inline-block;
text-align: center;

ul {
display: inline-block;
padding-left: 0;
border-radius: 4px;

li {
display: inline;

a {
float: left;
padding: 5px 10px;
text-decoration: none;
border-radius: 15px;

i {
font-size: 10px;
}
}

a:visited {
color: inherit;
}

a.active {
background-color: #0078d7!important;
color: white!important;
}
}
}
}
}

Paging.tsx

کلاس را با قطعه کد زیر در Paging.tsx جایگزین کنید. رویداد _onPageUpdate متد _onPageUpdate را در فایل ViewAllItems.tsx راه‌اندازی می‌کند که به عنوان یک ویژگی به این کامپوننت ارسال می‌شود.

import * as React from "react";
import {IPagingProps} from "./IPagingProps";
import { PrimaryButton } from 'office-ui-fabric-react/lib/Button';
import Pagination from "react-js-pagination";
import styles from './Paging.module.scss';

export default class Paging extends React.Component<IPagingProps, null> {

constructor(props: IPagingProps) {
super(props);

this._onPageUpdate = this._onPageUpdate.bind(this);
}

public render(): React.ReactElement<IPagingProps> {

return(
<div className={`${styles.paginationContainer}`}>
<div className={`${styles.searchWp__paginationContainer__pagination}`}>
<Pagination
activePage={this.props.currentPage}
firstPageText={<i className="ms-Icon ms-Icon--ChevronLeftEnd6" aria-hidden="true"></i>}
lastPageText={<i className="ms-Icon ms-Icon--ChevronRightEnd6" aria-hidden="true"></i>}
prevPageText={<i className="ms-Icon ms-Icon--ChevronLeft" aria-hidden="true"></i>}
nextPageText={<i className="ms-Icon ms-Icon--ChevronRight" aria-hidden="true"></i>}
activeLinkClass={ `${styles.active}` }
itemsCountPerPage={ this.props.itemsCountPerPage }
totalItemsCount={ this.props.totalItems }
pageRangeDisplayed={10}
onChange={this.props.onPageUpdate}
/>
</div>
</div>
);
}

private _onPageUpdate(pageNumber: number): void {
this.props.onPageUpdate(pageNumber);
}

 

پکیج بندی و استقرار

  • برای جمع‌آوری راه‌حل‌، gulp task زیر را اجرا کنید. این یک نسخه انتشار پروژه شما را با استفاده از یک برچسب پویا به عنوان URL میزبان برای assets های شما اجرا می کند. این URL به طور خودکار بر اساس تنظیمات tenant CDN شما به روز می شود:

gulp bundle --ship

  • برای پکیج بندی راه حل خود، task زیر را اجرا کنید. این اجرا باعث ایجاد یک پکیج sppkg به روز شده در پوشه sharepoint/solution می‌شود.

gulp package-solution --ship

  • بسته راه حل client-side جدید ایجاد شده را در کاتالوگ برنامه در tenant خود آپلود یا drag and drop کنید.
  • بر اساس تنظیمات tenant ، اگر CDN را در tenant خود فعال نکرده باشید، و تنظیم includeClientSideAssets در package-solution.json درست باشد، URL بارگیری asset ها به صورت پویا به روز می شود و مستقیماً به پوشه ClientSideAssets که در the app catalog site collection قرار دارد اشاره می کند.

1

2

3

مطالب مرتبط

ارسال دیدگاه

آخرین نوشته ها