Overview
Search has been an integral part of SharePoint over the years. Search helps us to get the security trimmed results across the tenant. Unfortunately, modern SharePoint sites do not provide the search related web parts by default.
In this article, we will explore to query the Search REST API and get the results. We will use React JS in this example.
Create SPFx Solution
Open the command prompt. Create a directory for SPFx solution.
Navigate the above-created directory.
Run Yeoman SharePoint Generator to create the solution.
Yeoman generator will present you with the wizard by asking questions about the solution to be created.
Solution Name
Hit enter to have the default name (spfx-react-search in this case) or type in any other name for your solution.
Selected choice - Hit enter
Target for component
Here, we can select the target environment where we are planning to deploy the client web part i.e. SharePoint Online or SharePoint OnPremise (SharePoint 2016 onwards).
Selected choice - SharePoint Online only (latest)
Place of files
We may choose to use the same folder or create a subfolder for our solution.
Selected choice - Same folder
Deployment option
Selecting Y will allow the app to deployed instantly to all sites and will be accessible everywhere.
Selected choice - N (install on each site explicitly)
Type of client-side component to create
We can choose to create client-side webpart or an extension. Choose the webpart option.
Selected choice - WebPart
Web part name
Hit enter to select the default name or type in any other name.
Selected choice - SearchResultsViewer
Web part description
Hit enter to select the default description or type in any other value.
Selected choice - Retrieve search results using the REST API.
Framework to use
Select any JavaScript framework to develop the component. Available choices are (No JavaScript Framework, React, and Knockout)
Selected choice - React
Model for Search Results
We will define an interface for representing the SharePoint search results.
Add an interface (ISPSearchResult.ts) representing the SharePoint search result.
- export interface ISPSearchResult
- {
- Title: string;
- Description: string;
- Url: string
- }
React JS acts on the state change. Let us add state to our solution (ISearchResultsViewerState.ts)
- import {ISPSearchResult} from './ISPSearchResult';
-
- export interface ISearchResultsViewerState {
- status: string;
- searchText: string;
- items: ISPSearchResult[];
- }
Configure SearchResultsViewer.tsx for this state.
Add Controls to WebPart
Open SearchResultsViewer.tsx under “\src\webparts\searchResultsViewer\components\” folder.
Modify the Render method to include the required controls.
Text field
-
- import { TextField } from 'office-ui-fabric-react/lib/TextField';
- import './TextField.Examples.scss';
-
- <TextField
- required={true}
- name="txtSearchText"
- placeholder="Search..."
- value={this.state.searchText}
- onChanged={e => this.setState({ searchText: e })}
- />
Button
-
- import { IButtonProps, DefaultButton } from 'office-ui-fabric-react/lib/Button';
-
- <DefaultButton
- data-automation-id="search"
- target="_blank"
- title="Search"
- onClick={this._searchClicked}
- >
- Search
- </DefaultButton>
-
- private _searchClicked(): void {
- }
List
-
- import { FocusZone, FocusZoneDirection } from 'office-ui-fabric-react/lib/FocusZone';
- import { List } from 'office-ui-fabric-react/lib/List';
-
-
- import { Link } from 'office-ui-fabric-react/lib/Link';
-
- <FocusZone direction={FocusZoneDirection.vertical}>
- <div className="ms-ListGhostingExample-container" data-is-scrollable={true}>
- <List items={this.state.items} onRenderCell={this._onRenderCell} />
- </div>
- </FocusZone>
-
- private _onRenderCell(item: ISPSearchResult, index: number, isScrolling: boolean): JSX.Element {
- return (
- <div className="ms-ListGhostingExample-itemCell" data-is-focusable={true}>
- <div className="ms-ListGhostingExample-itemContent">
- <div className="ms-ListGhostingExample-itemName">
- <Link href={item.Url}>{item.Title}</Link>
- </div>
- <div className="ms-ListGhostingExample-itemName">{item.Description}</div>
- <p></p>
- </div>
- </div>
- );
- }
In the command prompt type “gulp serve” to see the controls on webpart.
Implement service to retrieve search results
- Add a folder “services” to the solution.
- To the “services” folder, add a file SearchService.ts
- We will use the REST API to get the search results.
- import { SPHttpClient, SPHttpClientResponse } from '@microsoft/sp-http';
- import { IWebPartContext } from '@microsoft/sp-webpart-base';
- import { ISPSearchResult } from '../components/ISPSearchResult';
- import { ISearchResults, ICells, ICellValue, ISearchResponse } from './ISearchService';
- import { escape } from '@microsoft/sp-lodash-subset';
-
- export default class SearchService {
- constructor(private _context: IWebPartContext) {
- }
-
- public getSearchResults(query: string): Promise<ISPSearchResult[]> {
-
- let url: string = this._context.pageContext.web.absoluteUrl + "/_api/search/query?querytext='" + query + "'";
-
- return new Promise<ISPSearchResult[]>((resolve, reject) => {
-
- this._getSearchData(url).then((res: ISearchResults) => {
- let searchResp: ISPSearchResult[] = [];
-
-
- if (typeof res["odata.error"] !== "undefined") {
- if (typeof res["odata.error"]["message"] !== "undefined") {
- Promise.reject(res["odata.error"]["message"].value);
- return;
- }
- }
-
- if (!this._isNull(res)) {
- const fields: string = "Title,Path,Description";
-
-
- if (typeof res.PrimaryQueryResult.RelevantResults.Table !== 'undefined') {
- if (typeof res.PrimaryQueryResult.RelevantResults.Table.Rows !== 'undefined') {
- searchResp = this._setSearchResults(res.PrimaryQueryResult.RelevantResults.Table.Rows, fields);
- }
- }
- }
-
-
- resolve(searchResp);
- });
- });
- }
-
-
-
-
-
-
- private _getSearchData(url: string): Promise<ISearchResults> {
- return this._context.spHttpClient.get(url, SPHttpClient.configurations.v1, {
- headers: {
- 'odata-version': '3.0'
- }
- }).then((res: SPHttpClientResponse) => {
- return res.json();
- }).catch(error => {
- return Promise.reject(JSON.stringify(error));
- });
- }
-
-
-
-
-
-
-
- private _setSearchResults(crntResults: ICells[], fields: string): any[] {
- const temp: any[] = [];
-
- if (crntResults.length > 0) {
- const flds: string[] = fields.toLowerCase().split(',');
-
- crntResults.forEach((result) => {
-
- var val: Object = {}
-
- result.Cells.forEach((cell: ICellValue) => {
- if (flds.indexOf(cell.Key.toLowerCase()) !== -1) {
-
- val[cell.Key] = cell.Value;
- }
- });
-
-
- temp.push(val);
- });
- }
-
- return temp;
- }
-
-
-
-
-
-
- private _isNull(value: any): boolean {
- return value === null || typeof value === "undefined";
- }
- }
Test the WebPart
- On the command prompt, type “gulp serve”
- Open SharePoint site
- Navigate to /_layouts/15/workbench.aspx
- Add the webpart to page.
- Type the search text and verify the search results.
Troubleshooting
In some cases, SharePoint workbench (https://[tenant].sharepoint.com/_layouts/15/workbench.aspx) shows below error although “gulp serve” is running.
Open below URL in the next tab of the browser. Accept the warning message.
https://localhost:4321/temp/manifests.js
Summary
Modern SharePoint does not have web part for displaying search results. However, using the search REST API the results can be achieved.