1

I try to use a good pattern to use the Callout, for instance when hovering over a Persona element. Currently I do the following:

  • _clientPersonaElement is a reference to the Element the Callout uses as location: Callout.target
  • state.clientCalloutVisible is set by _onShowClientCallout to show the Callout. It is reset by _onClientCalloutDismiss

Here the code:

export default class ILoggerListItem extends React.Component<IILoggerListItemProps,IILoggerListItemState> {
    private _clientPersonaElement: HTMLElement;

    constructor(props: IILoggerListItemProps) {
        super(props);

        this._onShowClientCallout = this._onShowClientCallout.bind(this);
        this._onClientCalloutDismiss = this._onClientCalloutDismiss.bind(this);

        this.state = {
          clientCalloutVisible: false
        };
    }

    private _onShowClientCallout(person: IInteractionLogPerson, event: React.MouseEvent<Persona>) {
        if(! this.state.clientCalloutVisible)
        {
            this.setState(
            { 
                clientCalloutVisible: true,
            });
        }
    }

    private _onClientCalloutDismiss() {
        if( this.state.clientCalloutVisible)
        {
            this.setState({
                clientCalloutVisible: false
            });
        }
    }

My render looks like:

public render(): JSX.Element {

return (
  <div
    role='row'
    className={ classILoggerItem }
    data-is-focusable={ true } >
    <FocusZone direction={ FocusZoneDirection.horizontal }>
      <div className={ css(styles.itemTaskRow, 'ms-Grid-row') }>

        <div className= {css( 'ms-Grid-col', 'ms-u-sm4')}
          ref={ (targetElement) => this._clientPersonaElement = targetElement } >
          <Persona 
            onMouseOver= {(event) => this._onShowClientCallout(person, event)}
            size= { PersonaSize.regular }
            imageUrl= { person.Picture }
            primaryText= { person.Title }
            secondaryText= { person.MobilePhone }
          />
        </div>

      </div>
    </FocusZone>
    { this.state.clientCalloutVisible && (
      <Callout
        className={ css(styles.iLoggerClientCallout ) }
        gapSpace={ 0 }
        onDismiss={ this._onClientCalloutDismiss }
        target={this._clientPersonaElement}
        setInitialFocus={ true }
      >
        <div className={ css(styles.iLoggerClientCalloutHeader) }>
          <p className={ css(styles.iLoggerClientCalloutTitle, 'ms-font-l') }>
            { this.props.item.Client.Title }
          </p>
        </div>
        <div className={ css(styles.iLoggerClientCalloutInner) }>
          <div className={ css(styles.iLoggerClientCalloutContent) }>
            <p className={ css(styles.iLoggerClientCalloutSubText, 'ms-font-m') }>
              { this.props.item.Client.MobilePhone } <br />
              { this.props.item.Client.EMail }
            </p>
          </div>
          <div className={ css(styles.iLoggerClientCalloutActions) }>
            <Link className={ css(styles.iLoggerClientCalloutLink) } href='http://microsoft.com'>Go to profile</Link>
          </div>
        </div>
      </Callout>
    ) }
  </div>
);
}

I wrap the Persona element in a Div element, so I can get a reference used for the target property of the Callout:

I couldn't get ref=.. on the PersonA to work, because it's not an HtmlElement.

  • target of the Callout can be a MouseEvent, but I couldn't figure out, how to get the Persona.onMouseOver as a MouseEvent.
  • target can be a querySelector string of a valid HTMLElement . Is it possible to reference the Persona element via a querySelector?

Is this a good pattern with the additional div element and ref=.. ? Or would using MouseEvent or querySelector better?

Every feedback is valued and appreciated :-)

  • 1
    Is there any error logs on your browser console? Start by putting a debugger on _onShowClientCallout function and check if it is invoking or not. – ThinkB4Code Jul 6 '17 at 5:36
  • The above code is working. I don't know how to use the MouseEvent for the Callout.target. I tried using the React.MouseEvent<Persona> passed to the onMouseEnter handler, but it failed, because it is not of type MouseEvent. Is the <div> wrapper the best approach for this? – Dennis Kuhn Jul 6 '17 at 6:18
  • Yes, as a workaround and for testing purpose attaching it to wrapper div mouse event is good approach. – ThinkB4Code Jul 6 '17 at 6:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.