Oct 12 2017 05:23 AM
I have a woking example where I map (rest) search results to an object like this:
export interface IReactGetItemsState{ items:[ { "EmployeeName": "", "EmployeeId": "", "Experience":"", "Location":"" }] } export default class ReactGetItems extends React.Component<IReactGetItemsProps, IReactGetItemsState> { public constructor(props: IReactGetItemsProps, state: IReactGetItemsState){ super(props); this.state = { items: [ { "EmployeeName": "", "EmployeeId": "", "Experience":"", "Location":"" } ] }; } ----------------------------------- jquery.ajax({ url: `${this.props.siteurl}/_api/web/lists/getbytitle('EmployeeList')/items`, type: "GET", headers:{'Accept': 'application/json; odata=verbose;'}, success: function(resultData) { reactHandler.setState({ ----> items: resultData.d.results
Now I want to do my own variant using an Ajax call using a querystring. So my result object is different
I try to map the results in this way:
items: resultData.d.query.PrimaryQueryResult.RelevantResults.Table.Rows.results.Cells
This is not working. My results remain empty.
I'm just beginning SPFX/React so I do not know how to solve this.
Can someone help me out?
Thanks, Mike
Oct 12 2017 07:14 AM - edited Oct 12 2017 07:21 AM
An example...
var reactModule = React.createClass({
getInitialState:function(){
},
render: function() {
return (
<div>
... content here
</div>
);
},
componentDidMount: function() {
var ajaxSuccess=this.ajaxSuccess;
$.ajax({
type: "POST",
url:`${this.props.siteurl}/_api/web/lists/getbytitle('EmployeeList')/items`,
more props here,
success: ajaxSuccess
});
},
ajaxSuccess:function(e){
//e is the result. update state here.
}
});
Oct 12 2017 07:26 AM
Thanks again @Maggan Wåhlin.
I'll give it a try.
Oct 12 2017 07:28 AM
Oct 12 2017 10:00 AM
Things are a bit more clear but my main issue is the mapping of my query results to the "Item" object.
I try:
items: resultData.d.query.PrimaryQueryResult.RelevantResults.Table.Rows.results.Cells
But I need to solve it some other way. Still do not know howto.... sorry.
An example would be great....
Oct 19 2017 01:03 PM
Can someone help me out on this? Still not able to solve it.
Thanks, Mike
Oct 19 2017 01:16 PM
Oct 19 2017 01:29 PM - edited Oct 19 2017 01:31 PM
Hi @Maggan Wåhlin (I should buy you a beer for your help, already).
import * as React from 'react'; import styles from './ReactGetItems.module.scss'; import { IReactGetItemsProps } from './IReactGetItemsProps'; import { escape } from '@microsoft/sp-lodash-subset'; import * as jquery from 'jquery'; export interface IReactGetItemsState{ items:[ { "RefinableString10": "", "CreatedBy": "", "Created":"" }] } export default class ReactGetItems extends React.Component<IReactGetItemsProps, IReactGetItemsState> { public constructor(props: IReactGetItemsProps, state: IReactGetItemsState){ super(props); this.state = { items: [ { "RefinableString10": "", "CreatedBy": "", "Created":"" } ] }; } public componentDidMount(){ var reactHandler = this; jquery.ajax({ url: "https://Blabla.sharepoint.com/sites/bla/_api/search/query?querytext='ContentType:Test_matters'&selectproperties='RefinableString10%2cCreatedBy%2cCreated'&rowlimit=500'", type: "GET", headers:{'Accept': 'application/json; odata=verbose;'}, success: function(resultData) { reactHandler.setState({ items: resultData.PrimaryQueryResult.RelevantResults.Table.Rows }); }, error : function(jqXHR, textStatus, errorThrown) { } }); } public render(): React.ReactElement<IReactGetItemsProps> { return ( <div className={styles.panelStyle} > <br></br> <br></br> <div className={styles.tableCaptionStyle} > Demo : Retrieve SharePoint List Items using SPFx , REST API & React JS </div> <br></br> <div className={styles.headerCaptionStyle} > Employee Details</div> <div className={styles.tableStyle} > <div className={styles.headerStyle} > <div className={styles.CellStyle}>Employee Name</div> <div className={styles.CellStyle}>Employee Id </div> <div className={styles.CellStyle}>Experience</div> </div> {this.state.items.map(function(item,key){ return (<div className={styles.rowStyle} key={key}> <div className={styles.CellStyle}>{item.RefinableString10}</div> <div className={styles.CellStyle}>{item.CreatedBy}</div> <div className={styles.CellStyle}>{item.Created}</div> </div>); })} </div> </div> ); } }
Oct 19 2017 02:22 PM
Oct 19 2017 02:34 PM
So now I did this:
items: resultData.PrimaryQueryResult.RelevantResults.Table.Rows
No errors and I get the number of rows I expect but..... the rows are empty.
<div className={styles.CellStyle}>{item.RefinableString10}</div>
"item.RefinableString10" does not seem to have any value....
Oct 19 2017 02:59 PM
Oct 19 2017 10:08 PM
Oct 19 2017 11:42 PM
Thanks again,
I'll dive into this today and will post my results. I hope I can clarify my issue.
Oct 23 2017 01:11 AM - edited Oct 23 2017 04:41 AM
I did some testing. The query (from my working example gives the following xml (in postman):
<?xml version="1.0" encoding="utf-8"?> <feed xml:base="https://blabla.sharepoint.com/sites/bla/_api/" xmlns="http://www.w3.org/2005/Atom" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns:georss="http://www.georss.org/georss" xmlns:gml="http://www.opengis.net/gml"> <id>98c9b15e-6fc6-4a6e-b44b-8b8fe0b7d210</id> <title /> <updated>2017-10-23T07:48:54Z</updated> <entry m:etag=""1""> <id>a393667a-4c26-4832-bc85-9c26bf682b75</id> <category term="SP.Data.EmployeeListListItem" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" /> <link rel="edit" href="Web/Lists(guid'5437d1aa-85cd-4c1c-973c-135d5ecf3952')/Items(1)" /> <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/FirstUniqueAncestorSecurableObject" type="application/atom+xml;type=entry" title="FirstUniqueAncestorSecurableObject" href="Web/Lists(guid'5437d1aa-85cd-4c1c-973c-135d5ecf3952')/Items(1)/FirstUniqueAncestorSecurableObject" /> <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/RoleAssignments" type="application/atom+xml;type=feed" title="RoleAssignments" href="Web/Lists(guid'5437d1aa-85cd-4c1c-973c-135d5ecf3952')/Items(1)/RoleAssignments" /> <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Activities" type="application/atom+xml;type=feed" title="Activities" href="Web/Lists(guid'5437d1aa-85cd-4c1c-973c-135d5ecf3952')/Items(1)/Activities" /> <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/AttachmentFiles" type="application/atom+xml;type=feed" title="AttachmentFiles" href="Web/Lists(guid'5437d1aa-85cd-4c1c-973c-135d5ecf3952')/Items(1)/AttachmentFiles" /> <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ContentType" type="application/atom+xml;type=entry" title="ContentType" href="Web/Lists(guid'5437d1aa-85cd-4c1c-973c-135d5ecf3952')/Items(1)/ContentType" /> <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/GetDlpPolicyTip" type="application/atom+xml;type=entry" title="GetDlpPolicyTip" href="Web/Lists(guid'5437d1aa-85cd-4c1c-973c-135d5ecf3952')/Items(1)/GetDlpPolicyTip" /> <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/FieldValuesAsHtml" type="application/atom+xml;type=entry" title="FieldValuesAsHtml" href="Web/Lists(guid'5437d1aa-85cd-4c1c-973c-135d5ecf3952')/Items(1)/FieldValuesAsHtml" /> <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/FieldValuesAsText" type="application/atom+xml;type=entry" title="FieldValuesAsText" href="Web/Lists(guid'5437d1aa-85cd-4c1c-973c-135d5ecf3952')/Items(1)/FieldValuesAsText" /> <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/FieldValuesForEdit" type="application/atom+xml;type=entry" title="FieldValuesForEdit" href="Web/Lists(guid'5437d1aa-85cd-4c1c-973c-135d5ecf3952')/Items(1)/FieldValuesForEdit" /> <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/File" type="application/atom+xml;type=entry" title="File" href="Web/Lists(guid'5437d1aa-85cd-4c1c-973c-135d5ecf3952')/Items(1)/File" /> <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Folder" type="application/atom+xml;type=entry" title="Folder" href="Web/Lists(guid'5437d1aa-85cd-4c1c-973c-135d5ecf3952')/Items(1)/Folder" /> <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ParentList" type="application/atom+xml;type=entry" title="ParentList" href="Web/Lists(guid'5437d1aa-85cd-4c1c-973c-135d5ecf3952')/Items(1)/ParentList" /> <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Properties" type="application/atom+xml;type=entry" title="Properties" href="Web/Lists(guid'5437d1aa-85cd-4c1c-973c-135d5ecf3952')/Items(1)/Properties" /> <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Versions" type="application/atom+xml;type=feed" title="Versions" href="Web/Lists(guid'5437d1aa-85cd-4c1c-973c-135d5ecf3952')/Items(1)/Versions" /> <title /> <updated>2017-10-23T07:48:54Z</updated> <author> <name /> </author> etc......
When I change the output to json I get:
Unexpected '<'
However, this json error does not seem to matter because the application is returning the expected results.
When I run MY query in postman I get:
<?xml version="1.0" encoding="utf-8"?> <d:query xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns:georss="http://www.georss.org/georss" xmlns:gml="http://www.opengis.net/gml" m:type="Microsoft.Office.Server.Search.REST.SearchResult"> <d:ElapsedTime m:type="Edm.Int32">270</d:ElapsedTime> <d:PrimaryQueryResult m:type="Microsoft.Office.Server.Search.REST.QueryResult"> <d:CustomResults m:type="Collection(Microsoft.Office.Server.Search.REST.CustomResult)" /> <d:QueryId>d683c430-ba34-4db3-bd8c-c70feca21de5</d:QueryId> <d:QueryRuleId m:type="Edm.Guid">00000000-0000-0000-0000-000000000000</d:QueryRuleId> <d:RefinementResults m:null="true" /> <d:RelevantResults m:type="Microsoft.Office.Server.Search.REST.RelevantResults"> <d:GroupTemplateId m:null="true" /> <d:ItemTemplateId m:null="true" /> <d:Properties m:type="Collection(SP.KeyValue)"> <d:element> <d:Key>GenerationId</d:Key> <d:Value>9223372036854775806</d:Value> <d:ValueType>Edm.Int64</d:ValueType> </d:element> <d:element> <d:Key>indexSystem</d:Key> <d:Value></d:Value> <d:ValueType>Edm.String</d:ValueType> </d:element> <d:element> <d:Key>ExecutionTimeMs</d:Key> <d:Value>47</d:Value> <d:ValueType>Edm.Int32</d:ValueType> </d:element> <d:element> <d:Key>QueryModification</d:Key> <d:Value>ContentType:ILSS_matters -ContentClass=urn:content-class:SPSPeople</d:Value> <d:ValueType>Edm.String</d:ValueType> </d:element> <d:element> <d:Key>RenderTemplateId</d:Key> <d:Value>~sitecollection/_catalogs/masterpage/Display Templates/Search/Group_Default.js</d:Value> <d:ValueType>Edm.String</d:ValueType> </d:element> <d:element> <d:Key>StartRecord</d:Key> <d:Value>0</d:Value> <d:ValueType>Edm.Int32</d:ValueType> </d:element> <d:element> <d:Key>IsLastBlockInSubstrate</d:Key> <d:Value>true</d:Value> <d:ValueType>Edm.Boolean</d:ValueType> </d:element> <d:element> <d:Key>IsFirstBlockInSubstrate</d:Key> <d:Value>false</d:Value> <d:ValueType>Edm.Boolean</d:ValueType> </d:element> <d:element> <d:Key>IsFirstPinnedResultBlock</d:Key> <d:Value>false</d:Value> <d:ValueType>Edm.Boolean</d:ValueType> </d:element> <d:element> <d:Key>IsLastPinnedResultBlock</d:Key> <d:Value>false</d:Value> <d:ValueType>Edm.Boolean</d:ValueType> </d:element> <d:element> <d:Key>IsFirstRankedResultBlock</d:Key> <d:Value>true</d:Value> <d:ValueType>Edm.Boolean</d:ValueType> </d:element> <d:element> <d:Key>IsLastRankedResultBlock</d:Key> <d:Value>true</d:Value> <d:ValueType>Edm.Boolean</d:ValueType> </d:element> </d:Properties> <d:ResultTitle m:null="true" /> <d:ResultTitleUrl m:null="true" /> <d:RowCount m:type="Edm.Int32">63</d:RowCount> <d:Table m:type="SP.SimpleDataTable"> <d:Rows> <d:element m:type="SP.SimpleDataRow"> <d:Cells> <d:element m:type="SP.KeyValue"> <d:Key>Rank</d:Key> <d:Value>16.2882633209229</d:Value> <d:ValueType>Edm.Double</d:ValueType> </d:element> <d:element m:type="SP.KeyValue"> <d:Key>DocId</d:Key> <d:Value>458931375</d:Value> <d:ValueType>Edm.Int64</d:ValueType> </d:element> <d:element m:type="SP.KeyValue"> <d:Key>RefinableString10</d:Key> <d:Value>42914 Research and Conservation Project</d:Value> <d:ValueType>Edm.String</d:ValueType> </d:element> Etc....
When I change the output to json I also get:
Unexpected '<'
So my query returns the expected results but the format is different. I guess that is why the mapping is not working but I don't have a clue how to solve this.
When checking the json I notice that the type of the results is [object(Array)] and in my working example it is "[[object Object].object Object]]"
I hope this explains my problem a bit more.
Oct 23 2017 05:19 AM
I think, I'm getting closer.
My object is like this:
export interface IReactGetItemsState{ items:[ { "RefinableString10": "", "CreatedBy": "", "Created":"" }] }
I map it to my returned json like this:
reactHandler.setState({ items: resultData.PrimaryQueryResult.RelevantResults.Table.Rows });
To retrieve the values I do:
{this.state.items.map(function(item,key){ return (<div className={styles.rowStyle} key={key}> <div className={styles.CellStyle}>{item.RefinableString10}</div> <div className={styles.CellStyle}>{item.CreatedBy}</div> <div className={styles.CellStyle}>{item.Created}</div>
This is not working because the values are "deeper" away in the object. What I would like to do is this:
{this.state.items.map(function(item,key){ return (<div className={styles.rowStyle} key={key}> <div className={styles.CellStyle}>{item.Cells[2].value}</div> <div className={styles.CellStyle}>{item.Cells[3].value}</div> <div className={styles.CellStyle}>{item.Cells[4].value}</div>
I'm not allowed to do that because "Cells does not exist on type....."
I think I must define my object in another way or something.
Oct 23 2017 05:55 AM
Hi,
Look at my example data below. If you run the query with header Accept: application/json, you get a different structure. You should then be able to get the Cells directly from the item.
A question, do you need the Rows? You could map your items directly to the Cells.
reactHandler.setState({ items: resultData.PrimaryQueryResult.RelevantResults.Table.Rows.Cells });
Oct 23 2017 06:26 AM - edited Oct 23 2017 06:37 AM
No, I do not need the rows. So I did:
reactHandler.setState({ items: resultData.PrimaryQueryResult.RelevantResults.Table.Rows.Cells });
But that gives me the error: "Unable to get property 'map' of undefined or null reference"
This is my Json:
Is there something wrong here?
export interface IReactGetItemsState{ items:[ { "RefinableString10": "", "CreatedBy": "", "Created":"" }] } export default class ReactGetItems extends React.Component<IReactGetItemsProps, IReactGetItemsState> { public constructor(props: IReactGetItemsProps, state: IReactGetItemsState){ super(props); this.state = { items: [ { "RefinableString10": "", "CreatedBy": "", "Created":"" } ] }; }
Oct 23 2017 07:20 AM - edited Oct 23 2017 07:21 AM
Make sure that you have the data in this.state before you try to render it. This is how I get the data (not using ajax):
private loadDocuments(): Promise<any> { var url = "your rest url"; return this.props.spHttpClient.get(url, SPHttpClient.configurations.v1).then((response: SPHttpClientResponse) => { if (response.ok) { return response.json(); } else { console.log("WARNING - failed to hit URL " + url + ". Error = " + response.statusText); return null; } }); }
componentDidMount() { this.loadDocuments().then((response) => { this.setState({ items: response.value }); }); } }
Oct 23 2017 11:21 AM
I rebuild my application using your example.
I think I make a small error in the URL:
var url = "https://Bla.sharepoint.com/sites/bla/_api/search/query?querytext='ContentType:TEST_matters'&selectproperties='RefinableString10%2cCreatedBy%2cCreated'&rowlimit=500'";
I receive an error which tells me the query is wrong.
Oct 23 2017 01:12 PM - edited Oct 23 2017 01:13 PM
SolutionI had to create my own version of the web part to test the code. This works for me :)
import * as React from 'react'; import styles from './HelloWorld.module.scss'; import { IHelloWorldProps } from './IHelloWorldProps'; import { escape } from '@microsoft/sp-lodash-subset'; import { SPHttpClient, SPHttpClientConfiguration, SPHttpClientResponse, ODataVersion, ISPHttpClientConfiguration } from '@microsoft/sp-http'; export default class HelloWorld extends React.Component<IHelloWorldProps, any> { constructor(props) { super(props); this.state = { items: [], }; } private search(): Promise<any> { const spSearchConfig: ISPHttpClientConfiguration = { defaultODataVersion: ODataVersion.v3 }; const clientConfigODataV3: SPHttpClientConfiguration = SPHttpClient.configurations.v1.overrideWith(spSearchConfig); var url = "https://xxx.sharepoint.com/sites/vmf-lab/_api/search/query?querytext='ContentType:Kvalitetsdokument'&selectproperties='Title,RefinableString05,CreatedBy,Created'&rowlimit=500"; //this.properties.siteUrl + "/_api/web/lists"; return this.props.context.spHttpClient.get(`${url}`, clientConfigODataV3).then((response: SPHttpClientResponse) => { if (response.ok) { return response.json(); } else { console.log("WARNING - failed to hit URL " + url + ". Error = " + response.statusText); return null; } }); } componentDidMount() { this.search().then((response) => { this.setState({ items: response.PrimaryQueryResult.RelevantResults.Table.Rows }); }); } public render(): React.ReactElement<IHelloWorldProps> { return ( <div className={styles.helloWorld}> <div className={styles.container}> {this.state.items.map(row => <div className={`ms-Grid-row ${styles.row}`}> <div className={`ms-Grid-col`}> {row.Cells.map(col => <div>{col.Key} - {col.Value}</div> )} </div> </div> )} </div> </div> ); } }
Hope it works.