Added core code to HomeController and DataService

This commit is contained in:
dhartman 2016-10-11 18:37:17 -04:00
parent 428e422cc3
commit 7d50472046
8 changed files with 220 additions and 26 deletions

View File

@ -9,6 +9,10 @@ through SharePoint's REST API.
The logic for querying the SharePoint Content Types in the properties of the webpart was in part due to Chris O'Brien and this blog post
http://www.sharepointnutsandbolts.com/2016/09/sharepoint-framework-spfx-web-part-properties-dynamic-dropdown.html?m=0
Environment:
Enable publishing features on site collection
Enable publishing features on site
### Building the code

View File

@ -13,7 +13,8 @@
"description": { "default": "AngularSearch description" },
"officeFabricIconFontName": "Page",
"properties": {
"description": "AngularSearch"
"description": "AngularSearch",
"contentTypes": ""
}
}]
}

View File

@ -16,6 +16,7 @@ import { IAngularSearchWebPartProps } from './IAngularSearchWebPartProps';
import * as angular from 'angular';
import HomeController from './app/HomeController';
import DataService from './app/DataService';
import MockHttpClient from './MockHttpClient';
import 'ng-office-ui-fabric';
@ -35,7 +36,7 @@ export interface ISPStrVal {
export default class AngularSearchWebPart extends BaseClientSideWebPart<IAngularSearchWebPartProps> {
private $injector: ng.auto.IInjectorService;
private _listsInThisSite: IPropertyPaneDropdownOption[] = [];
private _CTypesInThisSite: IPropertyPaneDropdownOption[] = [];
get baseUrl(): string { return '$BASEURL$'; }
@ -50,12 +51,12 @@ export default class AngularSearchWebPart extends BaseClientSideWebPart<IAngular
//Determine if we are in a local environment
if (this.context.environment.type == EnvironmentType.Local) {
this._getMockOptions().then((data) => {
this._listsInThisSite = data;
this._CTypesInThisSite = data;
});
}
else {
this._getOptions().then((data) => {
this._listsInThisSite = data;
this._CTypesInThisSite = data;
});
}
@ -66,7 +67,7 @@ export default class AngularSearchWebPart extends BaseClientSideWebPart<IAngular
if (this.renderedOnce === false) {
const wp: AngularSearchWebPart = this;
this.domElement.innerHTML = `<angularsearch web="${this.context.pageContext.web.absoluteUrl}" hello="${wp.title}" style='${angular.toJson(styles)}'></angularsearch>`;
this.domElement.innerHTML = `<angularsearch web="${this.context.pageContext.web.absoluteUrl}" style='${angular.toJson(styles)}' contentType='${this.properties.contentTypes}'></angularsearch>`;
let sce: ng.ISCEDelegateService;
angular.module('angularsearchapp', [
@ -77,11 +78,12 @@ export default class AngularSearchWebPart extends BaseClientSideWebPart<IAngular
controllerAs: 'vm',
bindings: {
web: '@',
hello: '@',
style: '<'
style: '<',
contentType: '@'
},
templateUrl: `${this.baseUrl}home-template.html`
})
.service('DataService', DataService)
.config(function ($sceDelegateProvider: ng.ISCEDelegateProvider): void {
$sceDelegateProvider.resourceUrlWhitelist([
// Allow same origin resource loads.
@ -93,6 +95,10 @@ export default class AngularSearchWebPart extends BaseClientSideWebPart<IAngular
this.$injector = angular.bootstrap(this.domElement, ['angularsearchapp']);
}
this.$injector.get('$rootScope').$broadcast('configurationChanged', {
contentType: this.properties.contentTypes
});
}
private _getCTypes(url: string): Promise<ISPCTypeLists> {
@ -130,14 +136,14 @@ export default class AngularSearchWebPart extends BaseClientSideWebPart<IAngular
}
private _getOptions(): Promise<IPropertyPaneDropdownOption[]> {
var url = this.context.pageContext.web.absoluteUrl + '/_api/web/AvailableContentTypes?&filter=Group eq \'Document Content Types\'';
var url = this.context.pageContext.web.absoluteUrl + '/_api/web/AvailableContentTypes?$filter=Group eq \'Page Layout Content Types\'';
return this._getCTypes(url).then((response) => {
var options: Array<IPropertyPaneDropdownOption> = new Array<IPropertyPaneDropdownOption>();
var lists: ISPCType[] = response.value;
lists.forEach((list: ISPCType) => {
console.log("Found Content Type(s)");
options.push({ key: list.Id.StringValue, text: list.Name });
options.push({ key: list.Name, text: list.Name });
});
return options;
@ -160,9 +166,9 @@ export default class AngularSearchWebPart extends BaseClientSideWebPart<IAngular
PropertyPaneTextField('description', {
label: strings.DescriptionFieldLabel
}),
PropertyPaneDropdown('test', {
PropertyPaneDropdown('contentTypes', {
label: 'Dropdown',
options: this._listsInThisSite
options: this._CTypesInThisSite,
})
]
}

View File

@ -1,3 +1,4 @@
export interface IAngularSearchWebPartProps {
description: string;
contentTypes: string;
}

View File

@ -0,0 +1,62 @@
import { ISearchResults } from './../models/ISearchResults'
export interface IDataService {
getSearchResults(webUrl: string, contentType: string): ng.IPromise<ISearchResults>;
}
export default class DataService implements IDataService {
public static $inject: string[] = ['$q', '$http'];
constructor(private $q: ng.IQService, private $http: ng.IHttpService) { }
public getSearchResults(webUrl: string, contentType: string): ng.IPromise<ISearchResults> {
const deferred: ng.IDeferred<ISearchResults> = this.$q.defer();
this.$http({
url: `${webUrl}/_api/search/query?queryText='ContentType:"${contentType}"'`,
method: 'GET',
headers: {
'Accept': 'application/json;odata=verbose'
}
}).then((response: ng.IHttpPromiseCallbackArg<any>): void => {
if (response != null && response.data != null) {
const result: ISearchResults = response.data.d.query;
if (typeof result.PrimaryQueryResult !== 'undefined' &&
typeof result.PrimaryQueryResult.RelevantResults !== 'undefined' &&
typeof result.PrimaryQueryResult.RelevantResults.Table !== 'undefined' &&
typeof result.PrimaryQueryResult.RelevantResults.Table.Rows !== 'undefined') {
deferred.resolve(result);
}
else {
deferred.reject("problem getting search results");
}
}
else {
deferred.reject("problem getting search results");
}
}, (error: any): void => {
deferred.reject(error);
});
return deferred.promise;
}
private getRequestDigest(webUrl: string): ng.IPromise<string> {
const deferred: ng.IDeferred<string> = this.$q.defer();
this.$http({
url: webUrl + '/_api/contextinfo',
method: 'POST',
headers: {
'Accept': 'application/json;odata=nometedata'
}
})
.then((digestResult: ng.IHttpPromiseCallbackArg<{ FormDigestValue: string }>): void => {
deferred.resolve(digestResult.data.FormDigestValue);
}, (error: any): void => {
deferred.reject(error);
});
return deferred.promise;
}
}

View File

@ -1,14 +1,85 @@
import { IDataService } from './DataService';
import { ISearchResults, ICells, ICellValue } from './../models/ISearchResults';
interface IConfigurationChangeArgs {
contentType: string;
}
export default class HomeController {
public static $inject: string[] = ['$rootScope', '$scope', '$attrs'];
public styles: any = null;
public hello: string = null;
private web: string = null;
public static $inject: string[] = ['DataService', '$rootScope', '$scope', '$attrs'];
public status: string = undefined;
public styles: any = null;
public searchNotConfigured: boolean = true;
public items: any[] = [];
private _web: string = null;
private _contentType: string = undefined;
constructor(private dataService: IDataService, private $rootScope: ng.IRootScopeService, private $scope: ng.IScope, private $attrs: ng.IAttributes) {
const vm: HomeController = this;
constructor(private $rootScope: ng.IRootScopeService, private $scope: ng.IScope, private $attrs: ng.IAttributes) {
let vm: HomeController = this;
vm.styles = $attrs['style'];
vm.hello = $attrs['hello'];
vm.web = $attrs['web'];
vm._web = $attrs['web'];
vm._contentType = $attrs['contenttype'];
if (this._contentType !== undefined) {
this._init(this._contentType, vm.$scope);
}
else {
this._init(undefined, undefined);
}
$rootScope.$on('configurationChanged',
(event: ng.IAngularEvent, args: IConfigurationChangeArgs): void => {
vm._init(args.contentType, vm.$scope);
});
}
private _init(ctype: string, $scope: ng.IScope): void {
if (ctype !== undefined && ctype.length > 0) {
this._contentType = ctype;
this.searchNotConfigured = false;
}
else {
this.searchNotConfigured = true;
}
this.status = this.searchNotConfigured ? 'Please configure the search settings in the Web Part properties' : 'Ready';
if ($scope) {
//$scope.$digest();
//get search results
this.getSearchResults();
}
}
public getSearchResults(): void {
this.status = 'Loading search results...';
this.dataService.getSearchResults(this._web, this._contentType)
.then((results: ISearchResults): void => {
this.items = this._setSearchResults(results.PrimaryQueryResult.RelevantResults.Table.Rows.results);
console.log(this.items);
});
}
private _setSearchResults(searchResults: ICells[]): any[] {
if (searchResults.length > 0) {
const temp: any[] = [];
searchResults.forEach((result: ICells) => {
var val: Object = {};
result.Cells.results.forEach((cell: ICellValue) => {
val[cell.Key] = cell.Value;
});
temp.push(val);
});
return temp;
}
else {
return [];
}
}
}

View File

@ -1,14 +1,30 @@
<div class="{{::vm.styles.angularTemplate}}">
<div class="{{::vm.styles.container}}">
<div class="ms-Grid-row ms-bgColor-themeDark ms-fontColor-white {{::vm.styles.row}}">
<div class="ms-Grid-col ms-u-lg10 ms-u-xl8 ms-u-xlPush2 ms-u-lgPush1">
<span class="ms-font-xl ms-fontColor-white">Welcome to SharePoint!</span>
<p class="ms-font-l ms-fontColor-white">Customize SharePoint experiences using Web Parts.</p>
<p class="ms-font-l ms-fontColor-white">{{::vm.hello}}</p>
<a href="https://github.com/SharePoint/sp-dev-docs/wiki" class="ms-Button {{::vm.styles.button}}">
<span class="ms-Button-label">Learn more</span>
</a>
<div class="ms-Grid-col ms-u-lg10 ms-u-x-18 ms-u-xlPush2 ms-u-lgPush1">
<span class="ms-font-xl ms-fontColor-white">
Sample SharePoint Search in Angular
</span>
</div>
</div>
<div class="ms-Grid-row ms-bgColor-themeDark mg-fontColor-white ${::vm.styles.row}">
<div class="ms-Grid-col ms-u-lg10 ms-u-x-18 ms-u-xlPush2 ms-u-lgPush1">
<uif-button ng-click="vm.getSearchResults()" ng-disabled="vm.searchNotConfigured">
Refresh Search Results
</uif-button>
</div>
</div>
<div class="ms-Grid-row ms-bgColor-themeDark mg-fontColor-white ${::vm.styles.row}">
<div class="ms-Grid-col ms-u-lg10 ms-u-x-18 ms-u-xlPush2 ms-u-lgPush1">
<div class="ms-fontColor-white">{{vm.status}}</div>
</div>
</div>
<uif-list>
<uif-list-item ng-repeat="item in vm.items">
<uif-list-item-primary-text>{{item.Title}}</uif-list-item-primary-text>
<uif-list-item-secondary-text>By: {{item.Author}}</uif-list-item-secondary-text>
<uif-list-item-tertiary-text>{{item.HitHighlightedSummary}}</uif-list-item-tertiary-text>
</uif-list>
</div>
</div>

View File

@ -0,0 +1,33 @@
export interface ISearchResults {
PrimaryQueryResult: IPrimaryQueryResult;
}
export interface IPrimaryQueryResult {
RelevantResults: IRelevantResults;
}
export interface IRelevantResults {
Table: ITable;
}
export interface ITable {
Rows: IResults;
}
export interface IResults {
results: Array<ICells>;
}
export interface ICells {
Cells: IResultValues;
}
export interface IResultValues {
results: Array<ICellValue>;
}
export interface ICellValue {
Key: string;
Value: string;
ValueType: string;
}