sharepointsharepoint-onlinespfxspfx-extension

SPFx Application Customizer


I need help, I am trying out to create an SPFx Application customizer. Its pretty simple, I just wanted to call a components from the main components.

Here is my code

src\extensions\emergencyBanner\EmergencyBannerApplicationCustomizer.ts

import { Log } from '@microsoft/sp-core-library';
// import * as React from 'react';
// import * as ReactDom from "react-dom";


import {
  BaseApplicationCustomizer,
  PlaceholderContent,
  PlaceholderName,
} from "@microsoft/sp-application-base";
import { Dialog } from '@microsoft/sp-dialog';

import * as strings from 'EmergencyBannerApplicationCustomizerStrings';
import * as React from 'react';

import { IMainComponentProps } from "./components/IMainComponentProps";
import MainComponent from "./components/MainComponent";

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

// import { IMainComponentProps } from "./components/IMainComponentProps";
// import MainComponent from "./components/MainComponent";



const LOG_SOURCE: string = 'EmergencyBannerApplicationCustomizer';

/**
 * If your command set uses the ClientSideComponentProperties JSON input,
 * it will be deserialized into the BaseExtension.properties object.
 * You can define an interface to describe it.
 */
export interface IEmergencyBannerApplicationCustomizerProperties {
  // This is an example; replace with your own property
  testMessage: string;
}

/** A Custom Action which can be run during execution of a Client Side Application */
export default class EmergencyBannerApplicationCustomizer
  extends BaseApplicationCustomizer<IEmergencyBannerApplicationCustomizerProperties> {
  private static _topPlaceholder: PlaceholderContent | undefined;

  public onDispose() {
    if (
      EmergencyBannerApplicationCustomizer._topPlaceholder &&
      EmergencyBannerApplicationCustomizer._topPlaceholder.domElement
    ) {
      // ReactDom.unmountComponentAtNode(
      //   EmergencyBannerApplicationCustomizer._topPlaceholder.domElement
      // );
    }
  }

  private render() {
    if (
      this.context.placeholderProvider.placeholderNames.indexOf(
        PlaceholderName.Top
      ) !== -1
    ) {
      if (
        !EmergencyBannerApplicationCustomizer._topPlaceholder ||
        !EmergencyBannerApplicationCustomizer._topPlaceholder.domElement
      ) {
        EmergencyBannerApplicationCustomizer._topPlaceholder =
          this.context.placeholderProvider.tryCreateContent(
            PlaceholderName.Top,
            {
              onDispose: this.onDispose,
            }
          );
      }

      this.startReactRender();
    } else {
      console.log(
        `The following placeholder names are available`,
        this.context.placeholderProvider.placeholderNames
      );
    }
  }

  /**
  * Start the React rendering of your components
  */
  private startReactRender(): void {
    if (
      !EmergencyBannerApplicationCustomizer._topPlaceholder ||
      !EmergencyBannerApplicationCustomizer._topPlaceholder.domElement
    ) {
      EmergencyBannerApplicationCustomizer._topPlaceholder =
        this.context.placeholderProvider.tryCreateContent(
          PlaceholderName.Top,
          {
            onDispose: this.onDispose,
          }
        );
    }

    if (
      EmergencyBannerApplicationCustomizer._topPlaceholder &&
      EmergencyBannerApplicationCustomizer._topPlaceholder.domElement
    ) {
      const element: React.ReactElement<IMainComponentProps> =
        React.createElement(MainComponent, {
          description: "Test"
        });

      if (this.properties) {
        let topString: string = this.properties.testMessage;
        if (!topString) {
          topString = "(Top property was not defined.)";
        }

        if (EmergencyBannerApplicationCustomizer._topPlaceholder.domElement) {
          EmergencyBannerApplicationCustomizer._topPlaceholder.domElement.innerHTML = `
        <div>
          <div>
            <i class="ms-Icon ms-Icon--Info" aria-hidden="true"></i> ${escape(
            topString
          )}
          </div>
        </div>`;
        }
      }
    } else {
      console.log(
        "DOM element of the header is undefined. Start to re-render."
      );
      this.render();
    }
  }




  public onInit(): Promise<void> {
    Log.info(LOG_SOURCE, `Initialized ${strings.Title}`);

    let message: string = this.properties.testMessage;
    if (!message) {
      message = '(No properties were provided.)';
    }

    this.context.application.navigatedEvent.add(this, () => {
      this.startReactRender();
    });

    Dialog.alert(`Hello from ${strings.Title}:\n\n${message}`).catch(() => {
      /* handle error */
    });

    return Promise.resolve();
  }
}

and here is my src\extensions\emergencyBanner\components\MainComponent.tsx

import * as React from "react";
import { IMainComponentProps } from "./IMainComponentProps";


const MainComponent: React.FunctionComponent<IMainComponentProps> = ({
    description
}) => {



    return (<div>{description}</div>)
};

export default MainComponent;

Here is my interface from my MainComponent

import { ApplicationCustomizerContext } from "@microsoft/sp-application-base";
import { SPFI } from "@pnp/sp";

export interface IMainComponentProps {
    // context: ApplicationCustomizerContext;
    // spfi: SPFI;
    description: string;
}

But somehow in my gulp serve, in my browser I am getting this error in console

sp-pages-assembly_en-us_3edfa0c17b40c4b8bbbaae5e3a144e6a.js:207 Could not load emergency-banner-application-customizer in require. TypeError: Cannot read properties of undefined (reading 'id')


Solution

  • Downgrade to this version. Clean the package-lock and node modules. Should work fine

    npm i react@17.0.1 react-dom@17.0.1 --save