Working with Models in SPFx and Consume Some Field Types
April 19, 2023This article will give you some insights to work with models in the SharePoint Framework SPFx and consume information from some Field Types
FIELDS
- URL
- CHOICE
- PERSON
Why to use Models?
TypeScript is a superset of JavaScript that adds optional static typing and other features to JavaScript. It provides a way to catch errors early through static type checking and can help you write more maintainable code by providing features such as classes, interfaces, and modules. TypeScript also supports the latest JavaScript features on our code.
In summary, some benefits of using TypeScript include:
- Early error detection through static type checking
- Improved code maintainability through features such as classes, interfaces, and modules
- Support for the latest JavaScript features
Source: Conversation with Bing, 4/19/2023
In TypeScript, models are used to describe some form of information. They can describe varying shapes of data, ranging from simple constructs like strings, arrays, and objects. Interfaces, types are only virtual structures that don’t transpile to any JavaScript; they just help the compiler make our life easier.
In summary, models are used in TypeScript to describe data structures and help make our code more maintainable and easier to understand.
Modeling
First you will need a Response Model, await
resolves proimises making your code act syncronous, ergo Promise<IResponseModel[]> becomes IModel[], and the you can use map to convert IResponseModel[] into our internal object IModel[]
If you have any problem, keep calm, this link from the Microsoft Learning will guide you on the //…. Omitted for abbreviation
areas.
Let’s create our Response Model IResponseModel[] Names must match the List Internal Names
//Create response. Names must match the List Internal Names
export interface IResponseModel {
Id: number;
Title: string;
MyHyperlinkFiledInternalName: string;
MyChoiceInternalName: string;
MyPersonInternalName: string;
}
Then you will need your IModel[]
to be mapped, but as you can see you have to create more models to be inherit from you Fields Properties, so your Properties must match again with the internal names for the List, namely in IHyperlinkResponse
and IPersonResponse
for example.
In your Base Model you can give friendly names to be mapped like Hyperlink, MyChoice, Person
and so on.
//Your base Model
export interface IModel {
Id: number;
Title: string;
Hyperlink: IHyperlinkResponse;
MyChoice: string;
Person: IPersonResponse;
}
For the Hyperlink Field you can create like this
//Create the Url from the Hyperlink Field
export interface IHyperlinkResponse {
Description: string;
Url: string;
}
For the Choice field, if you don’t want to give a Key
you will only need a string
MyChoice: string;
For the Person Field, I’m giving you an example to get FirstName
, LastName
and EMail
. the EMail property have a capital M, you have more properties.
//Create the Person Field
export interface IPersonResponse {
FirstName: string;
LastName: string;
EMail: string;
}
Now let’s consume and map your Models in the WebPart. I’m not using Services because it’s not the scope for this article. I’m using the PnPjs because it’s an amazing PnP Project
// .... Omitted for abbreviation
//Import all Interfaces
import { IModelResponse, IModel } from "../../../interfaces/models";
import { getSP } from "../../../pnpJsConfig";
import { SPFI } from "@pnp/sp";
import { Logger, LogLevel } from "@pnp/logging";
// .... Omitted for abreviation
constructor(props: IWebPartProps) {
super(props);
// set initial state
this.state = {
items: [],
errors: []
};
this._sp = getSP();
}
// .... Omitted for abbreviation
Now our Function to consume all information
private _readYourData = async (): Promise<void> => {
try {
const response: IModelResponse[] = await this._sp.web.lists
.getByTitle(this.LIST_SOURCE)
.items
.select("Id", "Title", "MyHyperlinkFiledInternalName", "MyChoiceInternalName", "MyPersonInternalName")();
// use map to convert IModelResponse[] into our internal object IModel[]
const items: IModel[] = response.map((item: IModelResponse) => {
return {
Id: item.Id,
Title: item.Title || "Unknown",
Hyperlink: item.MyHyperlinkFiledInternalName.Url || "Unknown",
MyChoice: item.MyChoiceInternalName|| "Unknown",
Person: item.MyPersonInternalName.FirstName|| "Unknown"
};
});
// Add the items to the state
console.log(response);
this.setState({ items });
} catch (err) {
Logger.write(`${this.LOG_SOURCE} (_readTimeline) - ${JSON.stringify(err)} - `, LogLevel.Error);
}
}
Let’s get you a Mapping
public render(): React.ReactElement<IYourWebPartProps> {
try {
const {
// .... Omitted for abbreviation
} = this.props;
return (
// .... Omitted for abbreviation
{this.state.items.map((item, idx) => {
return (
// .... Omitted for abbreviation
);
})}
// .... Omitted for abbreviation
);
} catch (err) {
Logger.write(`${this.LOG_SOURCE} (render) - ${JSON.stringify(err)} - `, LogLevel.Error);
}
return null;
}
CONCLUSION
Data modeling makes it easier for developers, and other stakeholders to view and understand relationships among the data in a SharePoint List or making your call easier when having Expanded Fields. In addition, it can reduce errors in software and Lists development.