Pexels Sora Shimazaki 5926380

Consume Lookup Multi Select Fields SPFx with Models and Hooks

April 4, 2024 By pH7x Systems

First when you set up lookup columns in a list or library, Microsoft restricts you to 12 columns of that type in a single view. The reason behind this limitation is that lookup columns retrieve data from another list or source. If you surpass this limit and try to add a 13th column, you’ll encounter an error message. It seems that 13 isn’t a lucky number in this case!

But if for your use case makes sense, here it is a solutions using the SharePoint Framework SPFx, not to bypass but use.

See my previous posts about Models and Hooks

https://www.titolivio.eu/wordpress/2023/04/19/working-with-models-in-spfx-and-consume-some-field-types

Use Models

/* Model to MAP */
export interface IMyModelToMap {
    MyId: number;
    MyText: string;
    MyMultiSelectLookup: IMylMultiSelectResponse[];
}

/* IMyMainResponse Response */
export interface IMyMainResponse {
    Id: number;
    Title: string;
    MyMultiSelectLookup: IMylMultiSelectResponse[];
}

/* IMylMultiSelectResponse Response */
export interface IMylMultiSelectResponse {
    Id: number;
    Title: string;
}

Your Custom Hook

import { Logger, LogLevel } from "@pnp/logging";
import { spfi, SPFI } from "@pnp/sp";
import { useEffect, useState } from "react";
// Interfaces
import { IMyMainResponse, IMyModelToMap } from "../interfaces/MyModel"
//pnpjs
import { getSP } from "../pnpjsConfig";
import { Caching } from "@pnp/queryable";

const useTranings = () => {

    const LOG_SOURCE = "PnPLog";
    const LIBRARY_NAME = "Your List Name"

    const [myItems, setMyItems] = useState<IMyModelToMap[]>([]);
    const [isError, setError] = useState<boolean>(false);

    const _sp: SPFI = getSP();
        //Side Effect
        useEffect(() => {
            (async () => {
                try {
                    const spCache = spfi(_sp).using(Caching({ store: "session" }))
    
                    const response: IMyMainResponse[] = await spCache.web.lists
                        .getByTitle(LIBRARY_NAME)
                        .items.select("Id", 
                                      "Title", 
                                      "MyMultiSelectLookup/Id",
                                      "MyMultiSelectLookup/Title")
                        .expand("MyMultiSelectLookup")();

                        const items: IMyModelToMap[] = response.map((item: IMyMainResponse) => {
                            return {
                             MyId: item.Id || 0,
                             MyText: item.Title || "undefined",
                             MyMultiSelectLookup: item.MyMultiSelectLookup || []
                            };
                        });

                    setMyItems(items);
                } catch (err) {
                    console.log(err);
                    setError(true);
                    Logger.write(
                        `${LOG_SOURCE} (getting files useEffect setMyItems) - ${JSON.stringify(err)} - `, LogLevel.Error
                    );
                }
            })();
        }, []);

        return [myItems, isError] as const
}

export default useYourCustomHook

Our React Control

//* Omitted for abbreviation */

//Custom Hook
import useYourCustomHook from '../../../hooks/useYourCustomHook';

const YourControl: React.FC<IYourControlProps> = (props) => {
  const {
    hasTeamsContext
} = props;

const [myItems, isError] = useYourCustomHook();

<section className={`${styles.mainProgress} ${hasTeamsContext ? styles.teams : ''}`}>
if (!isError) {
    return (
          {myItems.map((tr, idx) => {
            return (
                 console.log(tr) 
                 console.log(tr.MyText)  
              <>
                 {tr.MyMultiSelectLookup.map((it) => {
                    return (
                      console.log(it) 
                      console.log(it.Title)       
                    )
                 })}
              </>
            );
          })}
        </section>
      </>
    );
  } else {
    return <p>Error</p>;
  }
}

export default YourControl

Hope that helps you