Add CRUD operations. (#368)
Extend the sample so it uses SharePoint data.
This commit is contained in:
parent
874f0ebd8f
commit
9c9807c4fd
|
@ -5,7 +5,7 @@
|
||||||
Sample Todo web part demonstrating how you can utilize [Vue](https://vuejs.org/v2) (a progressive framework for building user interfaces) with SharePoint Framework using handy [single-file components](https://vuejs.org/v2/guide/single-file-components.html) approach.
|
Sample Todo web part demonstrating how you can utilize [Vue](https://vuejs.org/v2) (a progressive framework for building user interfaces) with SharePoint Framework using handy [single-file components](https://vuejs.org/v2/guide/single-file-components.html) approach.
|
||||||
|
|
||||||
## Used SharePoint Framework Version
|
## Used SharePoint Framework Version
|
||||||
![drop](https://img.shields.io/badge/drop-1.3.0-green.svg)
|
![drop](https://img.shields.io/badge/drop-ga-green.svg)
|
||||||
|
|
||||||
## Applies to
|
## Applies to
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ Sample Todo web part demonstrating how you can utilize [Vue](https://vuejs.org/v
|
||||||
|
|
||||||
Solution|Author(s)
|
Solution|Author(s)
|
||||||
--------|---------
|
--------|---------
|
||||||
vuejs-todo-single-file-component|Sergei Sergeev ([@sergeev_srg](https://twitter.com/sergeev_srg))
|
vuejs-todo-single-file-component|Sergei Sergeev ([@sergeev_srg](https://twitter.com/sergeev_srg)), Dimcho Tsanov ([Singens](http://singens.com))
|
||||||
|
|
||||||
## Version history
|
## Version history
|
||||||
|
|
||||||
|
@ -26,6 +26,7 @@ Version|Date|Comments
|
||||||
0.0.2|March 30, 2017|Updated to GA
|
0.0.2|March 30, 2017|Updated to GA
|
||||||
0.0.3|June 14, 2017|Fix webpack 2 issues
|
0.0.3|June 14, 2017|Fix webpack 2 issues
|
||||||
0.0.4|October 7, 2017|Updated packages to latest versions, misc fixing
|
0.0.4|October 7, 2017|Updated packages to latest versions, misc fixing
|
||||||
|
1.0.0|November 15, 2017|Added data provider that demonstrats the CRUD operations
|
||||||
|
|
||||||
## Disclaimer
|
## Disclaimer
|
||||||
**THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.**
|
**THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.**
|
||||||
|
|
|
@ -6,27 +6,30 @@
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@microsoft/sp-core-library": "~1.3.0",
|
"@microsoft/sp-core-library": "~1.3.4",
|
||||||
"@microsoft/sp-lodash-subset": "~1.3.0",
|
"@microsoft/sp-webpart-base": "~1.3.4",
|
||||||
"@microsoft/sp-webpart-base": "~1.3.0",
|
"@microsoft/sp-lodash-subset": "~1.3.4",
|
||||||
|
"@microsoft/sp-office-ui-fabric-core": "~1.3.4",
|
||||||
"@types/webpack-env": ">=1.12.1 <1.14.0",
|
"@types/webpack-env": ">=1.12.1 <1.14.0",
|
||||||
"vue": "^2.4.4",
|
|
||||||
"vue-class-component": "^5.0.1",
|
"immutability-helper": "^2.5.0",
|
||||||
"vue-property-decorator": "^5.3.0",
|
"vue": "~2.4.4",
|
||||||
"vue-template-compiler": "^2.4.4"
|
"vue-class-component": "~5.0.1",
|
||||||
|
"vue-property-decorator": "~5.3.0",
|
||||||
|
"vue-template-compiler": "~2.4.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@microsoft/sp-build-web": "~1.3.0",
|
"@microsoft/sp-build-web": "~1.3.4",
|
||||||
"@microsoft/sp-module-interfaces": "~1.3.0",
|
"@microsoft/sp-module-interfaces": "~1.3.4",
|
||||||
"@microsoft/sp-webpart-workbench": "~1.3.0",
|
"@microsoft/sp-webpart-workbench": "~1.3.4",
|
||||||
|
"gulp": "~3.9.1",
|
||||||
"@types/chai": ">=3.4.34 <3.6.0",
|
"@types/chai": ">=3.4.34 <3.6.0",
|
||||||
"@types/mocha": ">=2.2.33 <2.6.0",
|
"@types/mocha": ">=2.2.33 <2.6.0",
|
||||||
"css-loader": "^0.28.4",
|
"ajv": "~5.2.2",
|
||||||
"gulp": "~3.9.1",
|
"node-sass": "~4.5.3",
|
||||||
"node-sass": "^4.5.3",
|
"sass-loader": "~6.0.6",
|
||||||
"sass-loader": "^6.0.6",
|
"vue-loader": "~13.0.5",
|
||||||
"vue-loader": "^13.0.5",
|
"webpack-merge": "~4.1.0"
|
||||||
"webpack-merge": "^4.1.0"
|
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "gulp bundle",
|
"build": "gulp bundle",
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
import { ITaskList } from '../models/ICommonObjects';
|
||||||
|
import {
|
||||||
|
IPropertyPaneDropdownOption,
|
||||||
|
} from '@microsoft/sp-webpart-base';
|
||||||
|
|
||||||
|
export class Utils {
|
||||||
|
|
||||||
|
public GetKeyFroDropdown(list: ITaskList): string {
|
||||||
|
|
||||||
|
return list.Id + "#" + list.ListItemEntityTypeFullName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GetListId(option: IPropertyPaneDropdownOption): string {
|
||||||
|
let result = "";
|
||||||
|
let keyAsString = option.key.toString();
|
||||||
|
if (keyAsString.indexOf("#") > 0) {
|
||||||
|
result = keyAsString.split("#")[0];
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GetListItemEntityType(option: IPropertyPaneDropdownOption): string {
|
||||||
|
let result = "";
|
||||||
|
let keyAsString = option.key.toString();
|
||||||
|
if (keyAsString.indexOf("#") > 0) {
|
||||||
|
result = keyAsString.split("#")[1];
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
import { IWebPartContext } from '@microsoft/sp-webpart-base';
|
||||||
|
import { ITodoItem, ITaskList } from '../models/ICommonObjects';
|
||||||
|
|
||||||
|
interface ITodoDataProvider {
|
||||||
|
|
||||||
|
selectedList: ITaskList;
|
||||||
|
|
||||||
|
webPartContext: IWebPartContext;
|
||||||
|
|
||||||
|
getTaskLists(): Promise<ITaskList[]>;
|
||||||
|
|
||||||
|
getItems(): Promise<ITodoItem[]>;
|
||||||
|
|
||||||
|
createItem(title: string): Promise<ITodoItem[]>;
|
||||||
|
|
||||||
|
updateItem(itemUpdated: ITodoItem): Promise<ITodoItem[]>;
|
||||||
|
|
||||||
|
deleteItem(itemDeleted: ITodoItem): Promise<ITodoItem[]>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ITodoDataProvider;
|
|
@ -0,0 +1,153 @@
|
||||||
|
import { IWebPartContext } from '@microsoft/sp-webpart-base';
|
||||||
|
import * as lodash from '@microsoft/sp-lodash-subset';
|
||||||
|
import ITodoDataProvider from './ITodoDataProvider';
|
||||||
|
import { ITodoItem, ITaskList } from '../models/ICommonObjects';
|
||||||
|
|
||||||
|
export default class MockDataProvider implements ITodoDataProvider {
|
||||||
|
|
||||||
|
private _idCounter: number;
|
||||||
|
private _taskLists: ITaskList[];
|
||||||
|
private _items: { [listId: string]: ITodoItem[] };
|
||||||
|
private _selectedList: ITaskList;
|
||||||
|
private _webPartContext: IWebPartContext;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this._idCounter = 0;
|
||||||
|
|
||||||
|
this._taskLists = [
|
||||||
|
this._createMockTaskList('1', 'List One', "SP.Data.OneListItem"),
|
||||||
|
this._createMockTaskList('2', 'List Two', 'SP.Data.TwoListItem'),
|
||||||
|
this._createMockTaskList('3', 'List Three', 'SP.Data.ThreetListItem')
|
||||||
|
];
|
||||||
|
|
||||||
|
let listOneItems = [
|
||||||
|
this._createMockTodoItem('Sunt filet mignon', true),
|
||||||
|
this._createMockTodoItem('Laborum flank ', false),
|
||||||
|
this._createMockTodoItem('consectetur ex', false)
|
||||||
|
];
|
||||||
|
for (let i = 0; i < 2000; i++) {
|
||||||
|
listOneItems.push(this._createMockTodoItem(this._getRandomString(i % 5), i % 2 == 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
this._items = {
|
||||||
|
'1': listOneItems,
|
||||||
|
'2': [
|
||||||
|
this._createMockTodoItem('Ut custodiant te sermonem', false),
|
||||||
|
this._createMockTodoItem('Dixi sunt implicatae', false),
|
||||||
|
this._createMockTodoItem('Est, ante me factus singulis', true),
|
||||||
|
this._createMockTodoItem('Tu omne quod ille voluit', false)
|
||||||
|
],
|
||||||
|
'3': [
|
||||||
|
this._createMockTodoItem('Integer massa lectus ', true),
|
||||||
|
this._createMockTodoItem('Phasellus sodales ', false),
|
||||||
|
this._createMockTodoItem('finibus porttitor dolor', false),
|
||||||
|
this._createMockTodoItem('Vestibulum at rutrum nisi', true)
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public set webPartContext(value: IWebPartContext) {
|
||||||
|
this._webPartContext = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get webPartContext(): IWebPartContext {
|
||||||
|
return this._webPartContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
public set selectedList(value: ITaskList) {
|
||||||
|
this._selectedList = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get selectedList(): ITaskList {
|
||||||
|
return this._selectedList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getTaskLists(): Promise<ITaskList[]> {
|
||||||
|
debugger;
|
||||||
|
const taskLists: ITaskList[] = this._taskLists;
|
||||||
|
|
||||||
|
return new Promise<ITaskList[]>((resolve) => {
|
||||||
|
setTimeout(() => resolve(taskLists), 500);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public getItems(): Promise<ITodoItem[]> {
|
||||||
|
|
||||||
|
const items: ITodoItem[] = lodash.clone(this._items[this._selectedList.Id]);
|
||||||
|
|
||||||
|
return new Promise<ITodoItem[]>((resolve) => {
|
||||||
|
setTimeout(() => resolve(items), 500);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public createItem(title: string): Promise<ITodoItem[]> {
|
||||||
|
const newItem = this._createMockTodoItem(title, false);
|
||||||
|
|
||||||
|
this._items[this._selectedList.Id] = this._items[this._selectedList.Id].concat(newItem);
|
||||||
|
|
||||||
|
return this.getItems();
|
||||||
|
}
|
||||||
|
|
||||||
|
public updateItem(itemUpdated: ITodoItem): Promise<ITodoItem[]> {
|
||||||
|
const index: number =
|
||||||
|
lodash.findIndex(
|
||||||
|
this._items[this._selectedList.Id],
|
||||||
|
(item: ITodoItem) => item.Id === itemUpdated.Id
|
||||||
|
);
|
||||||
|
|
||||||
|
if (index !== -1) {
|
||||||
|
this._items[this._selectedList.Id][index] = itemUpdated;
|
||||||
|
return this.getItems();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return Promise.reject(new Error(`Item to update doesn't exist.`));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public deleteItem(itemDeleted: ITodoItem): Promise<ITodoItem[]> {
|
||||||
|
this._items[this._selectedList.Id] = this._items[this._selectedList.Id].filter((item: ITodoItem) => item.Id !== itemDeleted.Id);
|
||||||
|
|
||||||
|
return this.getItems();
|
||||||
|
}
|
||||||
|
|
||||||
|
private _createMockTodoItem(title: string, isCompleted: boolean): ITodoItem {
|
||||||
|
const mockTodoItem: ITodoItem = {
|
||||||
|
Id: this._idCounter++,
|
||||||
|
Title: title,
|
||||||
|
PercentComplete: this._getRandomNumber() * 0.1
|
||||||
|
|
||||||
|
};
|
||||||
|
return mockTodoItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _createMockTaskList(id: string, title: string, listItemEntityType: string): ITaskList {
|
||||||
|
const mockTaskList: ITaskList = {
|
||||||
|
Id: id,
|
||||||
|
Title: title,
|
||||||
|
ListItemEntityTypeFullName: listItemEntityType,
|
||||||
|
};
|
||||||
|
return mockTaskList;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _getRandomString(wordCount: number): string {
|
||||||
|
if (wordCount == 0) {
|
||||||
|
wordCount = 2;
|
||||||
|
}
|
||||||
|
var text = "";
|
||||||
|
var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||||
|
|
||||||
|
for (var j = 0; j < wordCount; j++) {
|
||||||
|
for (var i = 0; i < 5; i++) {
|
||||||
|
text += possible.charAt(Math.floor(Math.random() * possible.length));
|
||||||
|
}
|
||||||
|
text += " ";
|
||||||
|
}
|
||||||
|
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _getRandomNumber(): number {
|
||||||
|
return Math.floor(Math.random() * 9) + 1;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,224 @@
|
||||||
|
import {
|
||||||
|
SPHttpClient,
|
||||||
|
SPHttpClientBatch,
|
||||||
|
SPHttpClientResponse
|
||||||
|
} from '@microsoft/sp-http';
|
||||||
|
import { IWebPartContext } from '@microsoft/sp-webpart-base';
|
||||||
|
import ITodoDataProvider from '../dataProviders/ITodoDataProvider';
|
||||||
|
import { ITodoItem, ITaskList } from '../models/ICommonObjects';
|
||||||
|
import { debounce } from '@microsoft/sp-lodash-subset';
|
||||||
|
|
||||||
|
export default class SharePointDataProvider implements ITodoDataProvider {
|
||||||
|
|
||||||
|
private _selectedList: ITaskList;
|
||||||
|
private _webPartContext: IWebPartContext;
|
||||||
|
|
||||||
|
|
||||||
|
public set webPartContext(value: IWebPartContext) {
|
||||||
|
this._webPartContext = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get webPartContext(): IWebPartContext {
|
||||||
|
return this._webPartContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
public set selectedList(value: ITaskList) {
|
||||||
|
this._selectedList = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get selectedList(): ITaskList {
|
||||||
|
return this._selectedList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getTaskLists(): Promise<ITaskList[]> {
|
||||||
|
|
||||||
|
const listTemplateId: string = '171';
|
||||||
|
const queryUrl: string = `${this._webPartContext.pageContext.web.absoluteUrl}/_api/web/lists?$filter=BaseTemplate eq ${listTemplateId}`;
|
||||||
|
|
||||||
|
return this._webPartContext.spHttpClient.get(queryUrl, SPHttpClient.configurations.v1)
|
||||||
|
.then((response: SPHttpClientResponse) => {
|
||||||
|
return response.json();
|
||||||
|
})
|
||||||
|
.then((json: { value: ITaskList[] }) => {
|
||||||
|
return json.value;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public getItems(): Promise<ITodoItem[]> {
|
||||||
|
return this._getItems(this.webPartContext.spHttpClient);
|
||||||
|
}
|
||||||
|
|
||||||
|
public createItem(title: string): Promise<ITodoItem[]> {
|
||||||
|
const batch: SPHttpClientBatch = this.webPartContext.spHttpClient.beginBatch();
|
||||||
|
|
||||||
|
const batchPromises: Promise<{}>[] = [
|
||||||
|
this._createItem(batch, title),
|
||||||
|
this._getItemsBatched(batch)
|
||||||
|
];
|
||||||
|
|
||||||
|
return this._resolveBatch(batch, batchPromises);
|
||||||
|
}
|
||||||
|
|
||||||
|
public deleteItem(itemToBeDeleted: ITodoItem): Promise<ITodoItem[]> {
|
||||||
|
//Approach 1: it is not working here with DELETE
|
||||||
|
// const batch: SPHttpClientBatch = this.webPartContext.spHttpClient.beginBatch();
|
||||||
|
// const batchPromises: Promise<{}>[] = [
|
||||||
|
// this._deleteItem(batch, itemToBeDeleted),
|
||||||
|
// this._getItemsBatched(batch)
|
||||||
|
// ];
|
||||||
|
// return this._resolveBatch(batch, batchPromises);
|
||||||
|
|
||||||
|
|
||||||
|
//Approach 2:
|
||||||
|
return this._deleteItem2(this.webPartContext.spHttpClient, itemToBeDeleted);
|
||||||
|
}
|
||||||
|
|
||||||
|
public updateItem(itemUpdated: ITodoItem): Promise<ITodoItem[]> {
|
||||||
|
const batch: SPHttpClientBatch = this.webPartContext.spHttpClient.beginBatch();
|
||||||
|
|
||||||
|
const batchPromises: Promise<{}>[] = [
|
||||||
|
this._updateItem(batch, itemUpdated),
|
||||||
|
this._getItemsBatched(batch)
|
||||||
|
];
|
||||||
|
|
||||||
|
return this._resolveBatch(batch, batchPromises);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _getItems(requester: SPHttpClient): Promise<ITodoItem[]> {
|
||||||
|
debugger;
|
||||||
|
const queryUrl: string = `${this._webPartContext.pageContext.web.absoluteUrl}` +
|
||||||
|
`/_api/web/lists(guid'${this._selectedList.Id}')/items?$select=Id,Title,PercentComplete`;
|
||||||
|
|
||||||
|
return requester.get(queryUrl, SPHttpClient.configurations.v1)
|
||||||
|
.then((response: SPHttpClientResponse) => {
|
||||||
|
return response.json();
|
||||||
|
})
|
||||||
|
//Approach 1: Of the property names of ITodoItem are equal to the internal names of the list, this will work
|
||||||
|
// .then((json: { value: ITodoItem[] }) => {
|
||||||
|
// debugger;
|
||||||
|
// return json.value;
|
||||||
|
// // .map((task: ITodoItem) => { debugger; return task; });
|
||||||
|
// });
|
||||||
|
//Approach 2: manually create the ITodoItem object; useful when the properties are different form the internal names of the list
|
||||||
|
.then((json: any) => {
|
||||||
|
debugger;
|
||||||
|
return json.value.map((item: any) => {
|
||||||
|
debugger;
|
||||||
|
let newItem: ITodoItem = {
|
||||||
|
Id: item.Id,
|
||||||
|
Title: item.Title,
|
||||||
|
PercentComplete: item.PercentComplete
|
||||||
|
};
|
||||||
|
return newItem;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private _getItemsBatched(requester: SPHttpClientBatch): Promise<ITodoItem[]> {
|
||||||
|
const queryUrl: string = `${this._webPartContext.pageContext.web.absoluteUrl}` +
|
||||||
|
`/_api/web/lists(guid'${this._selectedList.Id}')/items?$select=Id,Title,PercentComplete`;
|
||||||
|
|
||||||
|
return requester.get(queryUrl, SPHttpClientBatch.configurations.v1)
|
||||||
|
.then((response: SPHttpClientResponse) => {
|
||||||
|
return response.json();
|
||||||
|
})
|
||||||
|
.then((json: { value: ITodoItem[] }) => {
|
||||||
|
debugger;
|
||||||
|
return json.value.map((task: ITodoItem) => {
|
||||||
|
debugger;
|
||||||
|
return task;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private _createItem(batch: SPHttpClientBatch, title: string): Promise<SPHttpClientResponse> {
|
||||||
|
|
||||||
|
const body: {} = {
|
||||||
|
'@data.type': this._selectedList.ListItemEntityTypeFullName,
|
||||||
|
'Title': title
|
||||||
|
};
|
||||||
|
|
||||||
|
return batch.post(
|
||||||
|
`${this._webPartContext.pageContext.web.absoluteUrl}/_api/web/lists(guid'${this._selectedList.Id}')/items`,
|
||||||
|
SPHttpClientBatch.configurations.v1,
|
||||||
|
{ body: JSON.stringify(body) }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _deleteItem(batch: SPHttpClientBatch, item: ITodoItem): Promise<SPHttpClientResponse> {
|
||||||
|
const itemDeletedUrl: string = `${this._webPartContext.pageContext.web.absoluteUrl}/_api/web/lists(guid'${this._selectedList.Id}')/items(${item.Id})`;
|
||||||
|
|
||||||
|
const headers: Headers = new Headers();
|
||||||
|
headers.append('If-Match', '*');
|
||||||
|
|
||||||
|
return batch.fetch(itemDeletedUrl,
|
||||||
|
SPHttpClientBatch.configurations.v1,
|
||||||
|
{
|
||||||
|
headers,
|
||||||
|
method: 'DELETE'
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _deleteItem2(requester: SPHttpClient, item: ITodoItem): Promise<ITodoItem[]> {
|
||||||
|
const itemDeletedUrl: string = `${this._webPartContext.pageContext.web.absoluteUrl}/_api/web/lists(guid'${this._selectedList.Id}')/items(${item.Id})`;
|
||||||
|
debugger;
|
||||||
|
const headers: Headers = new Headers();
|
||||||
|
headers.append('If-Match', '*');
|
||||||
|
|
||||||
|
return requester.fetch(itemDeletedUrl,
|
||||||
|
SPHttpClient.configurations.v1,
|
||||||
|
{
|
||||||
|
headers,
|
||||||
|
method: 'DELETE'
|
||||||
|
}
|
||||||
|
).then((response: any) => {
|
||||||
|
debugger;
|
||||||
|
if (response.status >= 200 && response.status < 300) {
|
||||||
|
return response;
|
||||||
|
} else {
|
||||||
|
return Promise.reject(new Error(JSON.stringify(response)));
|
||||||
|
}
|
||||||
|
}).then(() => {
|
||||||
|
return this._getItems(requester);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private _updateItem(batch: SPHttpClientBatch, item: ITodoItem): Promise<SPHttpClientResponse> {
|
||||||
|
|
||||||
|
const itemUpdatedUrl: string = `${this._webPartContext.pageContext.web.absoluteUrl}/_api/web/lists(guid'${this._selectedList.Id}')/items(${item.Id})`;
|
||||||
|
const headers: Headers = new Headers();
|
||||||
|
headers.append('If-Match', '*');
|
||||||
|
|
||||||
|
const body: {} = {
|
||||||
|
'@data.type': this._selectedList.ListItemEntityTypeFullName,
|
||||||
|
'PercentComplete': item.PercentComplete
|
||||||
|
};
|
||||||
|
|
||||||
|
return batch.fetch(itemUpdatedUrl,
|
||||||
|
SPHttpClientBatch.configurations.v1,
|
||||||
|
{
|
||||||
|
body: JSON.stringify(body),
|
||||||
|
headers,
|
||||||
|
method: 'PATCH'
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private _resolveBatch(batch: SPHttpClientBatch, promises: Promise<{}>[]): Promise<ITodoItem[]> {
|
||||||
|
return batch.execute()
|
||||||
|
.then(() => {
|
||||||
|
return Promise.all(promises);
|
||||||
|
}).then((values: any) => {
|
||||||
|
debugger;
|
||||||
|
return Promise.resolve(values[values.length - 1]);
|
||||||
|
// return values[values.length - 1];
|
||||||
|
}).catch((ex) => {
|
||||||
|
debugger;
|
||||||
|
throw ex;
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
/**
|
||||||
|
* This interface describes a list item in Task list.
|
||||||
|
*/
|
||||||
|
export interface ITodoItem {
|
||||||
|
Id: number;
|
||||||
|
Title: string;
|
||||||
|
PercentComplete: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This interface describes Task list.
|
||||||
|
*/
|
||||||
|
export interface ITaskList {
|
||||||
|
Id?: string;
|
||||||
|
Title?: string;
|
||||||
|
ListItemEntityTypeFullName?: string;
|
||||||
|
}
|
|
@ -1,4 +1,12 @@
|
||||||
|
import { ITaskList } from '../../models/ICommonObjects';
|
||||||
|
/**
|
||||||
|
* This interface describes the serialized properties of the webpart
|
||||||
|
*/
|
||||||
export interface ITodoWebPartProps {
|
export interface ITodoWebPartProps {
|
||||||
message: string;
|
|
||||||
todos: string[];
|
/**
|
||||||
|
* Represents the selected Task list
|
||||||
|
*/
|
||||||
|
SelectedList: ITaskList;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,12 +10,10 @@
|
||||||
"preconfiguredEntries": [{
|
"preconfiguredEntries": [{
|
||||||
"groupId": "a0e1eddd-ea67-4775-a52b-0141c5807146",
|
"groupId": "a0e1eddd-ea67-4775-a52b-0141c5807146",
|
||||||
"group": { "default": "Under Development" },
|
"group": { "default": "Under Development" },
|
||||||
"title": { "default": "ToDo" },
|
"title": { "default": "ToDo Vue.js" },
|
||||||
"description": { "default": "My Todo's" },
|
"description": { "default": "My Todo's demo with Vue.js" },
|
||||||
"officeFabricIconFontName": "Page",
|
"officeFabricIconFontName": "TaskSolid",
|
||||||
"properties": {
|
"properties": {
|
||||||
"message": "todos",
|
|
||||||
"todos": []
|
|
||||||
}
|
}
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,43 +1,104 @@
|
||||||
import { Version } from '@microsoft/sp-core-library';
|
import { Version, Environment, EnvironmentType } from '@microsoft/sp-core-library';
|
||||||
import {
|
import {
|
||||||
BaseClientSideWebPart,
|
BaseClientSideWebPart,
|
||||||
IPropertyPaneConfiguration,
|
IPropertyPaneConfiguration,
|
||||||
PropertyPaneTextField
|
PropertyPaneTextField,
|
||||||
|
PropertyPaneDropdown,
|
||||||
|
IPropertyPaneField,
|
||||||
|
PropertyPaneLabel,
|
||||||
|
IPropertyPaneDropdownOption
|
||||||
} from '@microsoft/sp-webpart-base';
|
} from '@microsoft/sp-webpart-base';
|
||||||
import { escape } from '@microsoft/sp-lodash-subset';
|
import { findIndex } from '@microsoft/sp-lodash-subset';
|
||||||
|
|
||||||
import * as Vue from 'vue';
|
import * as Vue from 'vue';
|
||||||
import TodoComponent from './components/todo/Todo.vue';
|
import TodoComponent from './components/todo/Todo.vue';
|
||||||
|
import { ITodoProps } from './components/todo/ITodoProps';
|
||||||
|
|
||||||
import * as strings from 'toDoStrings';
|
import * as strings from 'toDoStrings';
|
||||||
import { ITodoWebPartProps } from './ITodoWebPartProps';
|
import { ITodoWebPartProps } from './ITodoWebPartProps';
|
||||||
|
|
||||||
|
import ITodoDataProvider from '../../dataProviders/ITodoDataProvider';
|
||||||
|
import MockDataProvider from '../../dataProviders//MockDataProvider';
|
||||||
|
import SharePointDataProvider from '../../dataProviders/SharePointDataProvider';
|
||||||
|
import { ITaskList } from '../../models/ICommonObjects';
|
||||||
|
import { Utils } from '../../common/Utils';
|
||||||
export default class TodoWebPart extends BaseClientSideWebPart<ITodoWebPartProps> {
|
export default class TodoWebPart extends BaseClientSideWebPart<ITodoWebPartProps> {
|
||||||
|
|
||||||
public data: ITodoWebPartProps;
|
private _data: ITodoProps;
|
||||||
|
private _dropdownOptions: IPropertyPaneDropdownOption[];
|
||||||
|
private _dataProvider: ITodoDataProvider;
|
||||||
|
private _selectedList: ITaskList;
|
||||||
|
|
||||||
|
private _disableDropdown: boolean;
|
||||||
|
|
||||||
|
|
||||||
|
protected onInit(): Promise<void> {
|
||||||
|
|
||||||
|
this.context.statusRenderer.displayLoadingIndicator(this.domElement, "Todo");
|
||||||
|
|
||||||
|
/*
|
||||||
|
Create the appropriate data provider depending on where the web part is running.
|
||||||
|
The DEBUG flag will ensure the mock data provider is not bundled with the web part when you package the solution for distribution, that is, using the --ship flag with the package-solution gulp command.
|
||||||
|
*/
|
||||||
|
if (DEBUG && Environment.type === EnvironmentType.Local) {
|
||||||
|
this._dataProvider = new MockDataProvider();
|
||||||
|
} else {
|
||||||
|
this._dataProvider = new SharePointDataProvider();
|
||||||
|
this._dataProvider.webPartContext = this.context;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
If we have serialized list in the webpart properties, use it
|
||||||
|
*/
|
||||||
|
if (this.properties.SelectedList) {
|
||||||
|
this._dataProvider.selectedList = this.properties.SelectedList;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Approach 1:
|
||||||
|
Get the list of tasks lists from the current site and store them in the variable _dropdownOptions
|
||||||
|
_dropdownOptions will be used to populate the property pane dropdown field when pane opens.
|
||||||
|
|
||||||
|
Approach 2:
|
||||||
|
Get the list of tasks lists from the current site and load them in the property pane only when the property pane is open.
|
||||||
|
For this approach please review the sample: react-custompropertypanecontrols
|
||||||
|
|
||||||
|
*/
|
||||||
|
this._loadTaskLists()
|
||||||
|
.then(() => {
|
||||||
|
debugger;
|
||||||
|
/*
|
||||||
|
If a list is already selected, then we would have stored the list Id in the associated web part property.
|
||||||
|
So, check to see if we do have a selected list for the web part. If we do, then we set that as the selected list
|
||||||
|
in the property pane dropdown field.
|
||||||
|
*/
|
||||||
|
if (this.properties.SelectedList) {
|
||||||
|
this._setSelectedList(this.properties.SelectedList.Id);
|
||||||
|
this.context.statusRenderer.clearLoadingIndicator(this.domElement);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return super.onInit();
|
||||||
|
}
|
||||||
|
|
||||||
public render(): void {
|
public render(): void {
|
||||||
|
|
||||||
this.domElement.innerHTML = `
|
this.domElement.innerHTML = `
|
||||||
<div id="app-${this.context.instanceId}">
|
<div id="app-${this.context.instanceId}">
|
||||||
</div>`;
|
</div>`;
|
||||||
|
|
||||||
this.data = {
|
this._data = {
|
||||||
message: this.properties.message,
|
dataProvider: this._dataProvider,
|
||||||
todos: this.properties.todos
|
webPartDisplayMode: this.displayMode
|
||||||
};
|
};
|
||||||
|
|
||||||
new Vue({
|
new Vue({
|
||||||
el: `#app-${this.context.instanceId}`,
|
el: `#app-${this.context.instanceId}`,
|
||||||
render: h => h(TodoComponent, {
|
render: h => h(TodoComponent, {
|
||||||
props: this.data
|
props: this._data
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
public onBeforeSerialize(): any {
|
|
||||||
this.properties.message = this.data.message;
|
|
||||||
this.properties.todos = this.data.todos;
|
|
||||||
return undefined;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected get dataVersion(): Version {
|
protected get dataVersion(): Version {
|
||||||
|
@ -55,8 +116,10 @@ export default class TodoWebPart extends BaseClientSideWebPart<ITodoWebPartProps
|
||||||
{
|
{
|
||||||
groupName: strings.BasicGroupName,
|
groupName: strings.BasicGroupName,
|
||||||
groupFields: [
|
groupFields: [
|
||||||
PropertyPaneTextField('message', {
|
PropertyPaneDropdown('selectedList', {
|
||||||
label: strings.DescriptionFieldLabel
|
label: "Select a list",
|
||||||
|
disabled: this._disableDropdown,
|
||||||
|
options: this._dropdownOptions
|
||||||
})
|
})
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -65,4 +128,64 @@ export default class TodoWebPart extends BaseClientSideWebPart<ITodoWebPartProps
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected onPropertyPaneFieldChanged(propertyPath: string, oldValue: any, newValue: any): void {
|
||||||
|
debugger;
|
||||||
|
/*
|
||||||
|
Check the property path to see which property pane feld changed.
|
||||||
|
If the property path matches the dropdown, then we set that list as the selected list for the web part.
|
||||||
|
*/
|
||||||
|
if (propertyPath === 'selectedList') {
|
||||||
|
this._setSelectedList(newValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Tell property pane to re-render the web part.
|
||||||
|
This is valid for reactive property pane.
|
||||||
|
*/
|
||||||
|
super.onPropertyPaneFieldChanged(propertyPath, oldValue, newValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _loadTaskLists(): Promise<any> {
|
||||||
|
debugger;
|
||||||
|
return this._dataProvider.getTaskLists()
|
||||||
|
.then((taskLists: ITaskList[]) => {
|
||||||
|
debugger;
|
||||||
|
// Disable dropdown field if there are no results from the server.
|
||||||
|
this._disableDropdown = taskLists.length === 0;
|
||||||
|
let utiility: Utils = new Utils();
|
||||||
|
if (taskLists.length !== 0) {
|
||||||
|
this._dropdownOptions = taskLists.map((list: ITaskList) => {
|
||||||
|
return {
|
||||||
|
key: utiility.GetKeyFroDropdown(list),
|
||||||
|
text: list.Title
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private _setSelectedList(value: string) {
|
||||||
|
debugger;
|
||||||
|
|
||||||
|
const selectedIndex: number = findIndex(this._dropdownOptions,
|
||||||
|
(item: IPropertyPaneDropdownOption) => item.key === value
|
||||||
|
);
|
||||||
|
|
||||||
|
const selectedDropDownOption: IPropertyPaneDropdownOption = this._dropdownOptions[selectedIndex];
|
||||||
|
let utiility: Utils = new Utils();
|
||||||
|
|
||||||
|
if (selectedDropDownOption) {
|
||||||
|
this._selectedList = {
|
||||||
|
Title: selectedDropDownOption.text,
|
||||||
|
Id: utiility.GetListId(selectedDropDownOption),
|
||||||
|
ListItemEntityTypeFullName: utiility.GetListItemEntityType(selectedDropDownOption)
|
||||||
|
};
|
||||||
|
|
||||||
|
this._dataProvider.selectedList = this._selectedList;
|
||||||
|
|
||||||
|
this.properties.SelectedList = this._selectedList;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
li {
|
li {
|
||||||
font-size: 30px;
|
font-size: 30px;
|
||||||
|
}
|
||||||
|
.completed
|
||||||
|
{
|
||||||
|
text-decoration: line-through;
|
||||||
}
|
}
|
|
@ -1,12 +1,34 @@
|
||||||
import * as Vue from 'vue';
|
import * as Vue from 'vue';
|
||||||
import { Component, Prop } from 'vue-property-decorator';
|
import { Component, Prop } from 'vue-property-decorator';
|
||||||
|
import { ITodoItem } from '../../../../models/ICommonObjects';
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
export default class TodoItem extends Vue {
|
export default class TodoItem extends Vue {
|
||||||
@Prop()
|
|
||||||
public todoText: string;
|
|
||||||
|
|
||||||
|
@Prop()
|
||||||
|
public todoItem: ITodoItem;
|
||||||
|
|
||||||
|
/*
|
||||||
|
This method is attached to the checkbox click
|
||||||
|
*/
|
||||||
public onComplete(): void {
|
public onComplete(): void {
|
||||||
this.$emit('completed', this.todoText);
|
|
||||||
|
//// Approach 2: update the property PercentComplete when the checkbox is clicked
|
||||||
|
// if (this.todoItem.PercentComplete == 1) {
|
||||||
|
// this.todoItem.PercentComplete = 0;
|
||||||
|
// }
|
||||||
|
// else {
|
||||||
|
// this.todoItem.PercentComplete = 1;
|
||||||
|
// }
|
||||||
|
|
||||||
|
this.$emit('completed', this.todoItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
This is a system Vue.js hook. Added here only for demonstrations
|
||||||
|
*/
|
||||||
|
public created(): void {
|
||||||
|
debugger;
|
||||||
|
console.log(this.todoItem.Title + " | " + this.todoItem.Id);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,14 +1,24 @@
|
||||||
<template>
|
<template>
|
||||||
<li>
|
<li>
|
||||||
<div class="view">
|
<div class="view">
|
||||||
<input type="checkbox" @click="onComplete">
|
<!-- Approach 1: delete item when the checkbox is clicked -->
|
||||||
<label>{{todoText}}</label>
|
<!-- <input id="" type="checkbox" @click="onComplete" /> -->
|
||||||
|
|
||||||
|
<!-- Approach 2: update the property PercentComplete when the checkbox is clicked -->
|
||||||
|
<span v-if="todoItem.PercentComplete === 1">
|
||||||
|
<input type="checkbox" @click="onComplete" checked />
|
||||||
|
</span>
|
||||||
|
<span v-else>
|
||||||
|
<input type="checkbox" @click="onComplete" />
|
||||||
|
</span>
|
||||||
|
<label v-bind:class="[ todoItem.PercentComplete == 1 ? 'completed':'' ]" >
|
||||||
|
{{todoItem.Title}}</label>
|
||||||
|
<label> | {{todoItem.PercentComplete * 100}} % </label>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
module.exports = require('./TodoItem');
|
module.exports = require("./TodoItem");
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped src="./todoitem.scss" lang="scss"></style>
|
<style scoped src="./todoitem.scss" lang="scss"></style>
|
|
@ -0,0 +1,9 @@
|
||||||
|
import ITodoDataProvider from '../../../../dataProviders/ITodoDataProvider';
|
||||||
|
import { DisplayMode } from '@microsoft/sp-core-library';
|
||||||
|
|
||||||
|
|
||||||
|
export interface ITodoProps {
|
||||||
|
dataProvider: ITodoDataProvider;
|
||||||
|
webPartDisplayMode: DisplayMode;
|
||||||
|
|
||||||
|
}
|
|
@ -17,4 +17,21 @@ ul{
|
||||||
border: 1px solid #d6d4d4;
|
border: 1px solid #d6d4d4;
|
||||||
width: 300px;
|
width: 300px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.notification{
|
||||||
|
text-align: center;
|
||||||
|
padding-top: 50px;
|
||||||
|
}
|
||||||
|
.notificationIcon{
|
||||||
|
font-size: 20px;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
.notificationHeader
|
||||||
|
{
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
.notificationDescription
|
||||||
|
{
|
||||||
|
font-size: 18px;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
|
@ -1,35 +1,103 @@
|
||||||
import * as Vue from 'vue';
|
import * as Vue from 'vue';
|
||||||
import { Component, Prop } from 'vue-property-decorator';
|
import { Component, Prop } from 'vue-property-decorator';
|
||||||
import TodoItem from '../todo-item/Todoitem.vue';
|
import TodoItem from '../todo-item/Todoitem.vue';
|
||||||
import { ITodoWebPartProps } from '../../ITodoWebPartProps';
|
import { ITodoProps } from './ITodoProps';
|
||||||
|
import ITodoDataProvider from '../../../../dataProviders/ITodoDataProvider';
|
||||||
|
import { DisplayMode } from '@microsoft/sp-core-library';
|
||||||
|
import { ITodoItem } from '../../../../models/ICommonObjects';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
components: {
|
components: {
|
||||||
'todo-item': TodoItem
|
'todo-item': TodoItem
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
export default class Todo extends Vue implements ITodoWebPartProps {
|
export default class Todo extends Vue implements ITodoProps {
|
||||||
@Prop()
|
@Prop()
|
||||||
public message: string;
|
public dataProvider: ITodoDataProvider;
|
||||||
@Prop()
|
@Prop()
|
||||||
public todos: string[];
|
public webPartDisplayMode: DisplayMode;
|
||||||
|
|
||||||
|
public mytodos: ITodoItem[] = [];
|
||||||
|
|
||||||
public mytodos: string[] = this.todos;
|
|
||||||
public todoTitle: string = '';
|
public todoTitle: string = '';
|
||||||
|
|
||||||
|
public isLoading = true;
|
||||||
|
/*
|
||||||
|
This method is attached to the textbox whne the Enter key is hitted
|
||||||
|
*/
|
||||||
public addTodo(): void {
|
public addTodo(): void {
|
||||||
if(!this.todoTitle){
|
|
||||||
|
debugger;
|
||||||
|
if (!this.todoTitle) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.mytodos.push(this.todoTitle);
|
if (this.dataProvider.selectedList) {
|
||||||
this.todoTitle = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
public completed(todo: string): void {
|
this.dataProvider.createItem(this.todoTitle).then(
|
||||||
const index: number = this.mytodos.indexOf(todo, 0);
|
(allItems: ITodoItem[]) => {
|
||||||
if (index > -1) {
|
debugger;
|
||||||
this.mytodos.splice(index, 1);
|
if (allItems && allItems.length > 0) {
|
||||||
|
this.mytodos = allItems;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.mytodos = [];
|
||||||
|
}
|
||||||
|
this.todoTitle = '';
|
||||||
|
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
This method is triggered from the child componenets 'todo-item'
|
||||||
|
*/
|
||||||
|
public completed(todo: ITodoItem): void {
|
||||||
|
debugger;
|
||||||
|
if (this.dataProvider.selectedList) {
|
||||||
|
|
||||||
|
//// Approach 1: delete item when the checkbox is clicked
|
||||||
|
this.dataProvider.deleteItem(todo).then(
|
||||||
|
(allItems: ITodoItem[]) => {
|
||||||
|
debugger;
|
||||||
|
if (allItems && allItems.length > 0) {
|
||||||
|
this.mytodos = allItems;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.mytodos = [];
|
||||||
|
}
|
||||||
|
this.todoTitle = '';
|
||||||
|
});
|
||||||
|
|
||||||
|
//// Approach 2: update the property PercentComplete when the checkbox is clicked
|
||||||
|
// this.dataProvider.updateItem(todo).then(
|
||||||
|
// (allItems: ITodoItem[]) => {
|
||||||
|
// debugger;
|
||||||
|
// if (allItems && allItems.length > 0) {
|
||||||
|
// this.mytodos = allItems;
|
||||||
|
// this.todoTitle = '';
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
This is a system Vue.js hook. It is used here to communicate with SharePoint and get list items
|
||||||
|
*/
|
||||||
|
public created(): void {
|
||||||
|
debugger;
|
||||||
|
if (this.dataProvider.selectedList) {
|
||||||
|
|
||||||
|
this.dataProvider.getItems().then(
|
||||||
|
(results: ITodoItem[]) => {
|
||||||
|
debugger;
|
||||||
|
if (results && results.length > 0) {
|
||||||
|
this.mytodos = results;
|
||||||
|
}
|
||||||
|
this.isLoading = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,17 +1,53 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<h1>{{message}}</h1>
|
<div v-if="webPartDisplayMode === 1">
|
||||||
<div id="new-todo">
|
<span v-if="dataProvider.selectedList!= null">
|
||||||
<input type="text" @keyup.enter="addTodo" v-model="todoTitle" placeholder="what needs to be done?">
|
<div id="new-todo">
|
||||||
|
<input type="text" @keyup.enter="addTodo" v-model="todoTitle" placeholder="what needs to be done?">
|
||||||
|
</div>
|
||||||
|
<ul>
|
||||||
|
<todo-item v-for="item in mytodos" :key="item.Id"
|
||||||
|
:todoText="item.Title"
|
||||||
|
:todoId="item.Id"
|
||||||
|
:todoItem="item"
|
||||||
|
v-on:completed="completed">
|
||||||
|
</todo-item>
|
||||||
|
</ul>
|
||||||
|
</span>
|
||||||
|
<span v-else>
|
||||||
|
<div class="notification">
|
||||||
|
<div class="notificationIcon">
|
||||||
|
<i class="ms-Icon ms-Icon--ErrorBadge notificationIcon" aria-hidden="true"></i>
|
||||||
|
<span class="notificationHeader">
|
||||||
|
WebPart is not configured
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<ul>
|
<div v-if="webPartDisplayMode === 2">
|
||||||
<todo-item v-for="(todo, index) in mytodos" :key="index + todo" :todoText="todo" v-on:completed="completed"></todo-item>
|
<div class="notification">
|
||||||
</ul>
|
<div class="notificationIcon">
|
||||||
|
<i class="ms-Icon ms-Icon--ErrorBadge notificationIcon" aria-hidden="true"></i>
|
||||||
|
<span class="notificationHeader">
|
||||||
|
Edit Mode
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="notificationDescription">
|
||||||
|
<span v-if="dataProvider.selectedList!= null">
|
||||||
|
Selected List: {{dataProvider.selectedList.Title}}
|
||||||
|
</span>
|
||||||
|
<span v-else>
|
||||||
|
WebPart is not configured. Please select Task list.
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
module.exports = require('./Todo');
|
module.exports = require("./Todo");
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped src="./todo.scss" lang="scss"></style>
|
<style scoped src="./todo.scss" lang="scss"></style>
|
|
@ -9,7 +9,9 @@
|
||||||
"experimentalDecorators": true,
|
"experimentalDecorators": true,
|
||||||
"allowSyntheticDefaultImports": true,
|
"allowSyntheticDefaultImports": true,
|
||||||
"types": [
|
"types": [
|
||||||
|
"es6-promise",
|
||||||
|
"es6-collections",
|
||||||
"webpack-env"
|
"webpack-env"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,4 +5,7 @@
|
||||||
Code that is wrapped inside an if(UNIT_TEST) {...}
|
Code that is wrapped inside an if(UNIT_TEST) {...}
|
||||||
block will not be included in the final bundle when the
|
block will not be included in the final bundle when the
|
||||||
--ship flag is specified */
|
--ship flag is specified */
|
||||||
declare const UNIT_TEST: boolean;
|
declare const UNIT_TEST: boolean;
|
||||||
|
|
||||||
|
/* Global defintion for SPO builds */
|
||||||
|
declare const DATACENTER: boolean;
|
Loading…
Reference in New Issue