0

I'm trying to follow the Microsoft docs here, but it seems outdated. They are using these two lines to render to the page:

const listContainer: Element = this.domElement.querySelector('#spListContainer');

listContainer.innerHTML = html;

I prefer not using innerHTML and domElement.

I am calling the _renderListAsync() method that checks whether the environment is local or SharePoint, then if it's local, it runs the _renderList() method to get the mock data.

Inside the _renderList() method, my console logs show that the correct data is being outputted, but I don't know how to correctly return the mock data and render it to the page.

Webpart.tsx

import styles from './Onsite.module.scss';
import { IOnsiteProps } from './IOnsiteProps';
import { escape } from '@microsoft/sp-lodash-subset';
import MockHttpClient from '../MockHttpClient';
import { ISPList, ISPLists } from '../OnsiteWebPart';
import {
  SPHttpClient,
  SPHttpClientResponse
} from '@microsoft/sp-http';
import {
  Environment,
  EnvironmentType
} from '@microsoft/sp-core-library';

export default class Onsite extends React.Component<IOnsiteProps, {}> {

  private _renderList(items: ISPList[]): void {
    console.log("render list")
    let listItems: string = '';
    items.map((item: ISPList) => {
      console.log(item.Title); // returns mock data
      listItems += `<li>${item.Title}</li>`;
      console.log(listItems); // returns combined mock data
    });
  }

  private _renderListAsync(): any {
    console.log("render list async")
    // Local 
    if (Environment.type === EnvironmentType.Local) {
      this._getMockListData().then((response) => {
        this._renderList(response.value);
        // console.log(this._renderList(response.value)) // returns mock data
      });
    }
    // SharePoint
    else if (Environment.type == EnvironmentType.SharePoint ||
      Environment.type == EnvironmentType.ClassicSharePoint) {
      this._getListData()
        .then((response) => {
          this._renderList(response.value);
        });
    }
  }

  public render(): React.ReactElement<IOnsiteProps> {

    return (
      <div className={styles.onsite}>
        <div className={styles.container}>
          <div className={styles.row}>
            <div className={styles.column}>
              <span className={styles.title}>Welcome to Onsite!</span>
              <p className={styles.subTitle}>An event registration app.</p>
              <p className={styles.description}>{escape(this.props.barcode.toString())}</p>
              <p className={styles.description}>{escape(this.props.firstName)} {escape(this.props.lastName)}</p>
              <p className={styles.description}>{escape(this.props.jobTitle)}</p>
              <p className={styles.description}>{escape(this.props.company)}</p>
              <p className={styles.description}>Loading from {escape(this.props.pageContext.web.title)}</p>
            </div>
          </div>
          <div className={styles.row}>
            <div className={styles.column}>
              {this._renderListAsync()}
              {"Mock data should be returned here"}
            </div>
          </div>
        </div>
      </div>
    );
  }

  private _getMockListData(): Promise<ISPLists> {
    return MockHttpClient.get()
      .then((data: ISPList[]) => {
        var listData: ISPLists = { value: data };
        return listData;
      }) as Promise<ISPLists>;
  }

  private _getListData(): Promise<ISPLists> {
    return this.context.spHttpClient.get(this.context.pageContext.web.absoluteUrl + `/_api/web/lists?$filter=Hidden eq false`, SPHttpClient.configurations.v1)
      .then((response: SPHttpClientResponse) => {
        return response.json();
      });
  }
}

MockHttpClient.ts


export default class MockHttpClient  {

  private static _items: ISPList[] = [{ Id: '1', Title: 'Mock List' },
                                      { Id: '2', Title: 'Mock List 2' },
                                      { Id: '3', Title: 'Mock List 3' }];

  public static get(): Promise<ISPList[]> {
    return new Promise<ISPList[]>((resolve) => {
      resolve(MockHttpClient._items);
    });
  }
}

3 Answers 3

1

I solved my problem. The Microsoft documentation clearly wasn't using React framework for its example, so I set my state to the list data and used componentDidMount() to run a custom method, then mapped over the list items.

Depending on the environment (Local/SharePoint), it successfully returns the mock data or the site contents from SharePoint.

import * as React from 'react';
import styles from './Onsite.module.scss';
import { IOnsiteProps } from './IOnsiteProps';
import { escape } from '@microsoft/sp-lodash-subset';
import MockHttpClient from '../MockHttpClient';
import { ISPList } from '../OnsiteWebPart';
import {
  SPHttpClient
} from '@microsoft/sp-http';
import {
  Environment,
  EnvironmentType
} from '@microsoft/sp-core-library';

export default class Onsite extends React.Component<IOnsiteProps, {}> {

  state: { listItems: ISPList[] } = { listItems: [] };

  private async _fetchList() {
    if (Environment.type === EnvironmentType.Local) {
      const list = await MockHttpClient.get();
      this.setState({ ...this.state, listItems: list });
    } else if (Environment.type == EnvironmentType.SharePoint || Environment.type == EnvironmentType.ClassicSharePoint) {
      const list = await this.props.context.spHttpClient.get(this.props.context.pageContext.web.absoluteUrl + `/_api/web/lists?$filter=Hidden eq false`, SPHttpClient.configurations.v1);
      const listData = await list.json()
      this.setState({ ...this.state, listItems: listData.value });
    }
  }

  componentDidMount() {
    this._fetchList();
  }

  public render(): React.ReactElement<IOnsiteProps> {

    return (

      <div className={styles.onsite}>
        <div className={styles.container}>
          <div className={styles.row}>
            <div className={styles.column}>
              <span className={styles.title}>Welcome to Onsite!</span>
              <p className={styles.subTitle}>An event registration app.</p>
              <p className={styles.description}>{escape(this.props.barcode)}</p>
              <p className={styles.description}>{escape(this.props.firstName)} {escape(this.props.lastName)}</p>
              <p className={styles.description}>{escape(this.props.jobTitle)}</p>
              <p className={styles.description}>{escape(this.props.company)}</p>
              <p className={styles.description}>Loading from {escape(this.props.context.pageContext.web.title)}</p>
            </div>
          </div>
          <div className={styles.row}>
            <div className={styles.column}>
              <ul>
                {this.state.listItems.map(item => {
                  return <li key={item.Id}>{item.Title}</li>
                })}
              </ul>
            </div>
          </div>
        </div>
      </div>
    );

  }
}

0

You just console.log your data, there is no binding logic.

If you don't want to use innerHTML, you could create a project based on React framework so you could update the state to bind your data.

You could check this simple demo or more in Github

0

Using separation of concerns (SoC) design principle, the industry standard way to implement mock data using react in SPFX will be using ServiceKey and ServiceScope.

Brief overall steps:

  1. Create a new services folder and a class.
  2. Use ServiceKey and ServiceScope classes in consume() method in the required service.
  3. Define the mock data in MockDataService.ts file and export them using ServiceKey and ServiceScope.
  4. Pull the mock data into the web part (the main .tsx) - let serviceScope:....

Reference: I greatly appreciate article written by Nanddeep Nachan to expand my understanding of SPFX.

https://www.c-sharpcorner.com/article/sharepoint-framework-implementing-separation-of-concerns-soc/#:~:text=Separation%20of%20Concerns%20is%20a,user%20interface%2C%20etc.).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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