Please specify what version of the library you are using: [ 1.1.2]
When making an initial page next using the getPaged method, the library sets the StartRow property to -10 (assuming we do not set and use the default RowCount = 10)
private defaultKql: string = "";
private searchPage: number = 0;
private currentResults: SearchResults = null;
public async render(): Promise<void> {
sp.setup({
spfxContext: this.context
});
this.defaultKql = `Path:"${this.context.pageContext.site.absoluteUrl}"`;
let queryParameters: UrlQueryParameterCollection = new UrlQueryParameterCollection(window.location.href);
let initialSearchValue: string = null;
let initialResults: ISearchResultItem[] = [];
if (queryParameters.getValue("k")) {
initialSearchValue = queryParameters.getValue("k");
let initialResult: ISearchResult = await this.performSearch(initialSearchValue);
initialResults = initialResult.results;
}
const element: React.ReactElement<SearchWebPartProps> = React.createElement(
SearchWebPart,
{
results: initialResults,
performSearchHandler: this.performSearch,
performSearchNext: this.nextSearchPage,
performSearchPrev: this.prevSearchPage,
initialSearchValue: initialSearchValue
});
ReactDom.render(element, this.domElement);
}
@autobind
private async nextSearchPage(): Promise<ISearchResult> {
this.searchPage++;
this.currentResults = await this.currentResults.getPage(this.searchPage);
return await this.processResults(this.currentResults.PrimarySearchResults);
}
@autobind
private async prevSearchPage(): Promise<ISearchResult> {
--this.searchPage;
this.currentResults = await this.currentResults.getPage(this.searchPage);
return await this.processResults(this.currentResults.PrimarySearchResults);
}
@autobind
private async performSearch(query: string): Promise<ISearchResult> {
this.searchPage = 0;
let queryParameters: UrlQueryParameterCollection = new UrlQueryParameterCollection(window.location.href);
let q: SearchQuery = {
Querytext: `${this.defaultKql} ${query}`,
StartRow: 0
};
this.currentResults = await sp.search(q);
return await this.processResults(this.currentResults.PrimarySearchResults);
}
private async processResults(primaryResults: SearchResult[]): Promise<ISearchResult> {
let result: ISearchResultItem[] = [];
let nextPage = this.searchPage + 1;
let hasNextPageResults = await this.currentResults.getPage(nextPage);
let hasNextPage: boolean = hasNextPageResults.PrimarySearchResults.length > 0;
let hasPrevPage: boolean = false;
if (this.searchPage > 0) {
let prevPage = this.searchPage - 1;
let hasPrevPageResults = await this.currentResults.getPage(prevPage);
hasPrevPage = hasPrevPageResults.PrimarySearchResults.length > 0;
}
this.currentResults.PrimarySearchResults.forEach((v: SearchResult) => {
result.push({
Title: v.Title,
Highlights: v.HitHighlightedSummary,
Url: v.Path
});
});
return {
results: result,
hasNextValues: hasNextPage,
hasPrevValues: hasPrevPage
};
}
And here is the react component:
export default class SearchWebPart extends React.Component<ISearchWebPartProps, ISearchWebPartState> {
private initialSearchValue: string | "";
constructor(props: ISearchWebPartProps) {
super(props);
if (props.initialSearchValue && props.initialSearchValue.length > 0) {
this.initialSearchValue = props.initialSearchValue;
}
this.state = {
results: props.results,
hasNextValues: true,
hasPrevValues: false
};
}
public render(): React.ReactElement<ISearchWebPartProps> {
let searchResults: JSX.Element[] = this.state.results && this.state.results.length > 0 ? this.state.results.map((v: ISearchResultItem) => {
let resultItemHighlights: string = v.Highlights.replace(/<c0>/, "").replace(/<\/c0>/, "").replace(/<ddd\/>/, "");
return (<DocumentCard>
<FileTypeIcon type={IconType.image} size={ImageSize.medium} path={v.Url} />
<DocumentCardLocation
location={v.Title}
locationHref={v.Url}
/>
<DocumentCardTitle title={resultItemHighlights} />
</DocumentCard>);
}) : [(<div>No results</div>)];
let searchBox: JSX.Element = (<SearchBox
placeholder='Search...'
ariaLabel='Search...'
onSearch={this.searchTyped}
defaultValue='Search...'
/>);
if (this.initialSearchValue && this.initialSearchValue.length > 0) {
searchBox = (<SearchBox
placeholder='Search...'
ariaLabel='Search...'
onSearch={this.searchTyped}
defaultValue='Search...'
value={this.initialSearchValue}
/>);
}
let hiddenStyle = { display: 'none' };
return (
<div>
{searchBox}
<ActionButton iconProps={{ iconName: 'Search' }} onClick={(e) => { this.searchTyped((e.target as HTMLElement).nodeValue); }}></ActionButton>
<div className={"cchbc-promise-search-results"}>
{searchResults}
</div>
<ActionButton iconProps={{ iconName: 'Previous' }} onClick={this.performSearchPrev} style={!this.state.hasPrevValues ? hiddenStyle : {}}>Prev</ActionButton>
<ActionButton iconProps={{ iconName: 'Next' }} onClick={this.performSearchNext} style={!this.state.hasNextValues ? hiddenStyle : {}}>Next</ActionButton>
</div>
);
}
@autobind
private performSearchPrev(): void {
this.initialSearchValue = "";
this.props.performSearchPrev().then(this.setStateResults).catch((err: any) => {
console.error(err);
});
}
@autobind
private performSearchNext(): void {
this.initialSearchValue = "";
this.props.performSearchNext().then(this.setStateResults).catch((err: any) => {
console.error(err);
});
}
@autobind
private searchTyped(e): void {
this.initialSearchValue = "";
this.props.performSearchHandler(e).then(this.setStateResults).catch((err: any) => {
console.error(err);
});
}
@autobind
private setStateResults(response: ISearchResult): void {
this.setState({
results: response.results,
hasNextValues: response.hasNextValues,
hasPrevValues: response.hasPrevValues
});
}
}
Can you create a git repo where we can pull down a minimal reproduction of this issue? That will allow us to easily test and ensure that we are looking at what you are looking at. Thanks!
https://github.com/Sartor87/BugReports/tree/master/sp_PnP_Issue_171
Here is a stripped down code for replicating the issue. Please, note that I've resolved it by removing the startRow parameter and setting the initial start page to 1 instead of 0.
Thanks, will still have a look to see what is going on.
I had a look at this today and I think you found the issue. The pages should start with 1, which you can see in the search docs paging example. We did a long time ago go back and forth on if pages should start with 0 or 1 so perhaps that caused some confusion.
I am going to close this as resolved. Thanks!