0

The below is my code

import * as React from 'react';
import styles from './PostTest.module.scss';
import { IPostTestProps } from './IPostTestProps';
import { escape } from '@microsoft/sp-lodash-subset';
import { TextField } from 'office-ui-fabric-react/lib/TextField';  
import { IButtonProps, DefaultButton } from 'office-ui-fabric-react/lib/Button';  

import { SPHttpClient, SPHttpClientResponse, ISPHttpClientOptions } from '@microsoft/sp-http';


import {
 Environment,
 EnvironmentType
} from '@microsoft/sp-core-library';

export interface IComponentState{
  title: string;
}

export default class PostTest extends React.Component<IPostTestProps, IComponentState> {

  constructor(props: IPostTestProps, state: IComponentState){
    super(props);
    this.state = ({
      title: ''
    });

    this._saveClicked = this._saveClicked.bind(this);
  }

  public render(): React.ReactElement<IPostTestProps> {
    return (
      <div className={ styles.postTest }>
        <div className={ styles.container }>
          <div className={ styles.row }>
            <div className={ styles.column }>
              <span className={ styles.title }>Welcome to SharePoint!</span>
              <p className={ styles.subTitle }>Customize SharePoint experiences using Web Parts.</p>
              <p className={ styles.description }>{escape(this.props.description)}</p>
              <a href="https://aka.ms/spfx" className={ styles.button }>
                <span className={ styles.label }>Learn more</span>
              </a>
              <TextField 
                label="Standard" 
                value={this.state.title}
                onChanged={e => this.setState({ title: e })} 
              />
              <DefaultButton
                onClick={this._saveClicked}
              >
              Save
              </DefaultButton>
            </div>
          </div>
        </div>
      </div>
    );
  }

  private _saveClicked(): void {  
    alert('Hello ' + this.state.title);
    let requestlistItem: string = JSON.stringify({
      '__metadata': { "type": "SP.Data.ShipListItem" },
      "Title": this.state.title,
      "RequesterId":10
      });
    requestlistItem = requestlistItem.substring(1, requestlistItem .length-1);
    requestlistItem = '{' + requestlistItem +'}';
    console.log(requestlistItem);

    this.context.spHttpClient.post(`${this.context.pageContext.web.absoluteUrl}/_api/web/lists/getbytitle('Ship')/items`, SPHttpClient.configurations.v1, {
      headers: {
      'Accept': 'application/json;odata=nometadata',
      'Content-type': 'application/json;odata=verbose',
      'odata-version': ''
      },
      body: requestlistItem
      })
      .then((response: SPHttpClientResponse) => {
        // Access properties of the response object. 
        console.log(`Status code: ${response.status}`);
        console.log(`Status text: ${response.statusText}`);

        //response.json() returns a promise so you get access to the json in the resolve callback.
        response.json().then((responseJSON: JSON) => {
          console.log(responseJSON);
        });
      });
  }   
}

For this, whenever I click "Save" button, I am getting a very strange error:

"Uncaught TypeError: Cannot read property 'post' of undefined".

I assume the problem is with the imports, but I have just followed everything as it is in the documentation.

I already have a sharepoint list called "Ship". I tried to do https://gist.github.com/vman/9f706f9779308f068120ffe212306456, and got the same error.

Update 1: The problem comes when I use "React framework" for SPFx development. If I use "No framework" option to generate the webpart and code something similar, it works without any error. Find the working code below:

import { Version } from '@microsoft/sp-core-library';
import {
  BaseClientSideWebPart,
  IPropertyPaneConfiguration,
  PropertyPaneTextField,
} from '@microsoft/sp-webpart-base';
import { escape } from '@microsoft/sp-lodash-subset';

import styles from './Test1WebPart.module.scss';
import * as strings from 'Test1WebPartStrings';

import {
  SPHttpClient,
  SPHttpClientResponse,
  ISPHttpClientOptions
} from '@microsoft/sp-http';
import {
 Environment,
 EnvironmentType
} from '@microsoft/sp-core-library';


export interface ITest1WebPartProps {
  description: string;
}

export default class Test1WebPart extends BaseClientSideWebPart<ITest1WebPartProps> {

  public render(): void {
      this._postData();
  }

  protected get dataVersion(): Version {
    return Version.parse('1.0');
  }

  protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
    return {
      pages: [
        {
          header: {
            description: strings.PropertyPaneDescription
          },
          groups: [
            {
              groupName: strings.BasicGroupName,
              groupFields: [
                PropertyPaneTextField('description', {
                  label: strings.DescriptionFieldLabel
                })
              ]
            }
          ]
        }
      ]
    };
  }

  private _postData(): void {  
    let requestlistItem: string = JSON.stringify({
      '__metadata': { "type": "SP.Data.ShipListItem" },
      "Title": "TItanic"
      });
    requestlistItem = requestlistItem.substring(1, requestlistItem .length-1);
    requestlistItem = '{' + requestlistItem +'}';
    console.log(requestlistItem);

    this.context.spHttpClient.post(`${this.context.pageContext.web.absoluteUrl}/_api/web/lists/getbytitle('Ship')/items`, SPHttpClient.configurations.v1, {
      headers: {
      'Accept': 'application/json;odata=nometadata',
      'Content-type': 'application/json;odata=verbose',
      'odata-version': ''
      },
      body: requestlistItem
      })
      .then((response: SPHttpClientResponse) => {
        // Access properties of the response object. 
        console.log(`Status code: ${response.status}`);
        console.log(`Status text: ${response.statusText}`);

        //response.json() returns a promise so you get access to the json in the resolve callback.
        response.json().then((responseJSON: JSON) => {
          console.log(responseJSON);
        });
      });
  }
}
0

Posting an answer as I cannot comment.

What I propose here is more of a workaround and an explanation as to why spHttpClient is undefined is warranted.

In the debugger, verify that spHttpClient object exists on the context object of the base web part (the class that extends BaseClientSideWebPart). If so, pass the context object from the base web part as a prop to your component. Then it would be:

this.props.context.spHttpClient.post

instead of

this.context.spHttpClient.post
  • I have just found that index-internal.d.ts does not have HTTPClient or SPHTTPClient, how to add them there? can I manually edit it? – Zi Fit Jan 24 at 3:54
  • You could manually edit, but those edits will be overwritten if you ever upgrade the package. However, just adding the typings will not fix the issue. The object reference will still be undefined. – FourthGenZ28 Jan 24 at 16:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.