Where did the Placeholder class move to?

Brass Contributor

Just updated the @Pernille-Eskebo/sp-webpart-base NPM package to 1.1.1 and now it seems that the Placeholder control is either obsolet or moved to another place.

 

Can anyone help me out?

 

The changelog raises just more questions:

## 1.1.1
Thu, 08 Jun 2017 19:39:03 GMT

*Changes not tracked*

11 Replies

sp-application-base

 

import {
  BaseApplicationCustomizer,
  Placeholder
} from '@Pernille-Eskebo/sp-application-base';
 
Thanks mate. But now I got the problem that the Placeholder is missing the render function so it can't be used as a JSX element any more.
Am I missing something?

I would probably create a new project and pick up the latest version of the solution with :

yo @microsoft/sharepoint

It looks like you might have some old versions mixed up with new version of things.

 

I created a new project with Yeoman. Still got the same problem. I'm not able to use the Placeholder any more. Could you try and confirm it please? It's really strange.

I went through the examples this morning. and the code below works for me:

 

import { override } from '@microsoft/decorators';
import { Log } from '@microsoft/sp-core-library';
import {
  BaseApplicationCustomizer,
  Placeholder
} from '@microsoft/sp-application-base';

import * as strings from 'helloWorldStrings';

import styles from './AppCustomizer.module.scss';
import { escape } from '@microsoft/sp-lodash-subset'; 

const LOG_SOURCE: string = 'HelloWorldApplicationCustomizer';

/**
 * 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 IHelloWorldApplicationCustomizerProperties {
  // This is an example; replace with your own property
//  testMessage: string;
//}

export interface IHelloWorldApplicationCustomizerProperties {
  Header: string;
  Footer: string;
}

/** A Custom Action which can be run during execution of a Client Side Application */
export default class HelloWorldApplicationCustomizer
  extends BaseApplicationCustomizer<IHelloWorldApplicationCustomizerProperties> {

// These have been added
  private _headerPlaceholder: Placeholder;
  private _footerPlaceholder: Placeholder;

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

  @override
  public onRender(): void {
    console.log('CustomHeader.onRender()');
    console.log('Available placeholders: ',
      this.context.placeholders.placeholderNames.join(', '));

    // Handling the header placeholder
    if (!this._headerPlaceholder) {
      this._headerPlaceholder = this.context.placeholders.tryAttach(
        'PageHeader',
        {
          onDispose: this._onDispose
        });

      // The extension should not assume that the expected placeholder is available.
      if (!this._headerPlaceholder) {
        console.error('The expected placeholder (PageHeader) was not found.');
        return;
      }

      if (this.properties) {
        let headerString: string = this.properties.Header;
        if (!headerString) {
          headerString = '(Header property was not defined.)';
        }

        if (this._headerPlaceholder.domElement) {
          this._headerPlaceholder.domElement.innerHTML = `
                <div class="${styles.app}">
                  <div class="ms-bgColor-themeDark ms-fontColor-white ${styles.header}">
                    <i class="ms-Icon ms-Icon--Info" aria-hidden="true"></i> ${escape(headerString)}
                  </div>
                </div>`;
        }
      }
    }

    // Handling the footer placeholder
    if (!this._footerPlaceholder) {
      this._footerPlaceholder = this.context.placeholders.tryAttach(
        'PageFooter',
        {
          onDispose: this._onDispose
        });

      // The extension should not assume that the expected placeholder is available.
      if (!this._footerPlaceholder) {
        console.error('The expected placeholder (PageFooter) was not found.');
        return;
      }

      if (this.properties) {
        let footerString: string = this.properties.Footer;
        if (!footerString) {
          footerString = '(Footer property was not defined.)';
        }

        if (this._footerPlaceholder.domElement) {
          this._footerPlaceholder.domElement.innerHTML = `
                <div class="${styles.app}">
                  <div class="ms-bgColor-themeDark ms-fontColor-white ${styles.footer}">
                    <i class="ms-Icon ms-Icon--Info" aria-hidden="true"></i> ${escape(footerString)}
                  </div>
                </div>`;
        }
      }
    }
  }

  private _onDispose(): void {
    console.log('[CustomHeader._onDispose] Disposed custom header.');
  }
  

}
Probably we are talking about a different Placeholder. I got the same usage case like here: https://github.com/SharePoint/sp-dev-fx-webparts/blob/f4c100081d84a8e5fd71caa493cdc610bb4cf990/sampl...

Hi Robin,

 

I'm also getting the same issue.  The Placeholder class which previously existed in the sp-webpart-base and was used when generating webpart instances has gone.

 

The Placeholder class that Pieter mentions in the sp-application-base looks to be aimed at the new extensions.

 

Regards
Pete

 

Hi Pete,
yes I agree. The Placeholder mentioned by Pieter is linked to the new extensions stuff.

But where is the "old" Placeholder control? I really don't get it. Has it been completely removed? Our deployed SPFx app does not work anymore like expected. With the last update they just changed the API on the whole SharePoint Online.
And it's not even mentioned on the change log. This is a no go IMHO.

Hi @Robin Güldenpfennig, @Peter Cuttriss,

 

I wonder if things were moved and this sample wasn't considered.

 

It might be worth adding an issue to the issue list.

 

 

The Placeholder control has been indeed removed. Older examples use it because they refer to an older version of SPFx. If you're interested in using the control, for the time being you would have to recreate it yourself.