Added core code to HomeController and DataService
This commit is contained in:
parent
428e422cc3
commit
7d50472046
|
@ -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
|
||||
|
|
|
@ -13,7 +13,8 @@
|
|||
"description": { "default": "AngularSearch description" },
|
||||
"officeFabricIconFontName": "Page",
|
||||
"properties": {
|
||||
"description": "AngularSearch"
|
||||
"description": "AngularSearch",
|
||||
"contentTypes": ""
|
||||
}
|
||||
}]
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
})
|
||||
]
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
export interface IAngularSearchWebPartProps {
|
||||
description: string;
|
||||
contentTypes: string;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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 [];
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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>
|
|
@ -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;
|
||||
}
|
Loading…
Reference in New Issue