-1

I want to read the values of a specific list element by ID and show it on a SharePoint site.

The problem is that I tried to use the PNP Framework, but some of the components are not working any longer. Here is my code so far. I hope you can help me.

import * as React from 'react';
import styles from './Webpartprojectsw.module.scss';
import { IWebpartprojectswProps } from './IWebpartprojectswProps';
import { escape } from '@microsoft/sp-lodash-subset';
import * as jquery from 'jquery';
import { IItemAddResult, DateTimeFieldFormatType } from "@pnp/sp/presets/all";
import { spfi, SPFI, SPFx } from "@pnp/sp";
import "@pnp/sp/webs";
 import "@pnp/sp/lists";
import "@pnp/sp/items";

export interface ISolypProjectListItemsState{
    Title: string,
    ID: number,
    StartDate: string,
    EndDate:string,
    ProjectPhase: string,
    TrafficLight:string,
    message: string
  }

  export default class Webpartprojectsw extends     

 React.Component<IWebpartprojectswProps,ISolypProjectListItemsState> {

public static siteurl: string="";
public constructor(props:IWebpartprojectswProps, state: ISolypProjectListItemsState){
   super(props);
   this.state={
         Title:"",
         ID:0,
        StartDate:"",
        EndDate:"",
        ProjectPhase:"",
        TrafficLight:"",
        message:""
   };
   Webpartprojectsw.siteurl= this.props.websiteurl;
 }

 public componentDidMount()  {

    this._ReadItem();
 }



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


  return (
   <div>
    {this.state.message}
    {this.state.Title}
   </div>      
      
  );
}
 private async _ReadItem(){
 // get a specific item by id
const item: any = await sp.web.lists.getByTitle("ProjectStatusList").items.getById(1).get();
console.log(item);
 this.setState({message:"Last Item Created Title:--> " + item.Title + item.TrafficLight});

  }
  }

Thank you very much!

Matthias

Matthias
  • 9
  • 1
  • 6

1 Answers1

0

working with pnp js v.3 can be tricky, but here is what I have worked so far and it helped.

First of all create a service layer. For example lets call it ItemsService.ts

import { spfi, SPFI, SPFx } from "@pnp/sp";

export class ItemsService{
  private _sp: SPFI;

  constructor(private context: WebPartContext) {
    this._sp = spfi().using(SPFx(this.context));
  }
}


In your IWebpartprojectswProps add another property as context:WebPartContext.

In the React component that you want to use it, instantiate it like so...

import {ItemsService} from "../your/path/to/the/service/layer";

export interface ISolypProjectListItemsState{
    Title: string,
    ID: number,
    StartDate: string,
    EndDate:string,
    ProjectPhase: string,
    TrafficLight:string,
    message: string
  }

export default class Webpartprojectsw extends React.Component<IWebpartprojectswProps,ISolypProjectListItemsState> {

private itemService:ItemsService = null;

public constructor(props:IWebpartprojectswProps, state: ISolypProjectListItemsState){
   super(props);
   this.state={
         Title:"",
         ID:0,
        StartDate:"",
        EndDate:"",
        ProjectPhase:"",
        TrafficLight:"",
        message:""
   };
   itemService = new ItemsService(this.props.context)
   Webpartprojectsw.siteurl= this.props.websiteurl;
 }

}

Before I go any further, please remember that in your spfx solution inside your webparts folder, there is a main {yourProject}WebPart.ts file, where the WebPartContext is incorporated. Assuming you want to use the context in your own class, then you have to injectit from there, since its that place where the magic begins. The following example will give you an idea.

export default class YourProjectWebPart extends BaseClientSideWebPart<YourProjecWebPartProps> {

public render(): void {
    const element: React.ReactElement<IWebpartprojectswProps> =
      React.createElement(Webpartprojectsw , {
        context:this.context,
        //whatever other props you have to pass here
             
      });

    ReactDom.render(element, this.domElement);
  }


}

Now you can use your service. Let's go ahead and create a getElement function in the ItemsService.ts file. I found two ways to get a more detailed item and your average call to get some data for an element.

import { spfi, SPFI, SPFx } from "@pnp/sp";

export class ItemsService{
  private _sp: SPFI;

  constructor(private context: WebPartContext) {
    this._sp = spfi().using(SPFx(this.context));
  }

  //This is going to bring you many details of an element.
  public async getDetailedListElement(list:string, id:number){
    let singleItemQuery = `<View><Query>
      <Where>
         <Eq>
            <FieldRef Name='ID' />
            <Value Type='Counter'>${id}</Value>
         </Eq>
      </Where>
   </Query></View>`;
    let singleElement = await (
      await this._sp.web.lists
        .getByTitle(list)
        .renderListDataAsStream({ ViewXml: singleItemQuery })
    ).Row[0];
    return singleElement;
  }
  
  //This is going to bring you just the data that the pnp method is calling.
  public async getListElement(list:string, id:number){
    let singleElement = await this._sp.web.lists
      .getByTitle(list)
      .items.getById(id)();

     return singleElement;
  }

}

Now if you go back to your original class to use it, in your private async ReadItem, you would use it like so

private async _ReadItem(){
 // get a specific item by id
const item = await itemService.getSingleElement("ProjectStatusList",1);
 this.setState({message:"Last Item Created Title:--> " + item.Title + item.TrafficLight});

  }

Try to code your pnp calls to sharepoint in a service layer and then call whatever you want to call and render it to your needs.

Also read thoroughly the transition documentation between v.2 and v.3 of pnp.js Pnp.js v.3 transitionguide

Happy debugging!!!

SoftDev30_15
  • 463
  • 7
  • 20