cancel
Showing results for 
Search instead for 
Did you mean: 
Reply
philcatterall
Frequent Visitor

How to deal with FluentUI React Toggle Button click event in a pcf control

Hi I'm quite new to Typescript/FluentUI/PCF components.

I'm creating a Toggle Button and I'm struggling to understand how to implement it using an export class pattern.

See code below. The first implementation is using code lifted from the fluentui/controls documentation and works fine.

But my other pcf controls use a Class pattern and I'd like to keep this consistent. But, due to my lack of experience, I don't know how to implement the onChange properly so it toggles.

Can anyone help me refactor the class so it works ?

Thanks

 

 

 

 

/* eslint-disable @typescript-eslint/no-empty-function */
/* eslint-disable prettier/prettier */
import * as React from "react";
import { DefaultButton, IBaseButtonState } from "@fluentui/react/lib/Button";
import { IIconProps, Toggle } from "@fluentui/react";
import { IUseBooleanCallbacks, useBoolean } from "@fluentui/react-hooks";

export interface IButtonElementProps {
  name?: string;
  disabled?: boolean;
  checked?: boolean;
}
//Implementation exporting a function - taken from FluidUI example
export const ButtonElement: React.FunctionComponent<IButtonElementProps> = (props) => {
  const { disabled, checked } = props;
  const icon: IIconProps = { iconName: "Accept" };
  const [muted, { toggle: setMuted }] = useBoolean(false);
  return (
    <DefaultButton
      toggle
      iconProps={icon}
      text={muted ? "Volume muted" : "Volume unmuted"}
      checked={muted || checked}
      onClick={setMuted}
    ></DefaultButton>
  );
};

//Implementation exporting class - this is the bit I can't get to work
export class ButtonControl extends React.Component<IButtonElementProps, IBaseButtonState> {
  constructor(props: IButtonElementProps) {
    super(props);
  }
  icon: IIconProps = { iconName: "AddIn" };
  //muted: [boolean, IUseBooleanCallbacks] = useBoolean(false); // This breaks it
  tmuted = [useBoolean(false)]; //so does this
  muted: IUseBooleanCallbacks = { // this runs but I don't know if its right or understand how to use it
    toggle() {
    }, setFalse() {

    }, setTrue() {
    },
  };

  public render(): React.ReactNode {
    // eslint-disable-next-line prettier/prettier
    return <DefaultButton
      toggle
      iconProps={this.icon}
      text={this.props.name}
      checked={true} //how do I make this so it takes the value of muted
      onClick={this.clicked}
    ></DefaultButton>;
  }

  private clicked(args: React.MouseEvent<HTMLAnchorElement>) {
    console.log("clicked");
    console.log(args);
    // is this the right place and what do I put here to set the property ?
  }
}

 

 

 

 

 

1 ACCEPTED SOLUTION

Accepted Solutions
iwaldman
Helper III
Helper III

Well, I am not a React dev or much less a real UI developer. However, this should give you some ideas:

 

Careful with the background color 😎

 

import React from 'react';
import { IStackStyles, Stack } from '@fluentui/react/lib/Stack';
import { DefaultButton, IBaseButtonState } from '@fluentui/react/lib/Button';
import { DefaultPalette } from '@fluentui/react';

export interface IButtonElementProps {
  name?: string;
  disabled?: boolean;
  checked?: boolean;
}

interface IButtonState extends IBaseButtonState {
  muted: boolean;
}

export class ButtonControl extends React.Component<IButtonElementProps, IButtonState> {
  constructor(props: IButtonElementProps) {
    super(props);
    this.state = { muted: false, menuHidden: true };
  }

  public render(): React.ReactNode {
    const { name, checked } = this.props;
    const { muted } = this.state;

    return (
      <DefaultButton
        toggle
        text={name}
        checked={muted || checked}
        onClick={() => this.setState((state) => ({ ...state, muted: !state.muted }))}
      ></DefaultButton>
    );
  }
}

const stackStyles: IStackStyles = {
  root: {
    background: DefaultPalette.purpleLight,
  },
};

export const App: React.FunctionComponent = () => {
  return (
    <Stack horizontalAlign="center" verticalAlign="center" verticalFill styles={stackStyles}>
      <ButtonControl name="React FTW!" checked={false} disabled={false} />
    </Stack>
  );
};

 

View solution in original post

3 REPLIES 3
iwaldman
Helper III
Helper III

@philcatterall 

You are trying to use hooks in a class component and this is not supported. 

See https://reactjs.org/docs/hooks-faq.html#should-i-use-hooks-classes-or-a-mix-of-both .

@iwaldman hmm I guess that just shows up my inexperience with React. That said, the template Microsoft provide using pac pcf init -fw react, creates a tsx file that uses the Class pattern. Whereas most of the fluentui code examples use the function pattern. 
Do you have any advice as to which one I should be using, or if one is better than the other - especially in the context of a pcf control. Or is it just code/style preference ? Thanks anyway for your response. I guess I’d better invest more time in learning React !!

cheers. 

iwaldman
Helper III
Helper III

Well, I am not a React dev or much less a real UI developer. However, this should give you some ideas:

 

Careful with the background color 😎

 

import React from 'react';
import { IStackStyles, Stack } from '@fluentui/react/lib/Stack';
import { DefaultButton, IBaseButtonState } from '@fluentui/react/lib/Button';
import { DefaultPalette } from '@fluentui/react';

export interface IButtonElementProps {
  name?: string;
  disabled?: boolean;
  checked?: boolean;
}

interface IButtonState extends IBaseButtonState {
  muted: boolean;
}

export class ButtonControl extends React.Component<IButtonElementProps, IButtonState> {
  constructor(props: IButtonElementProps) {
    super(props);
    this.state = { muted: false, menuHidden: true };
  }

  public render(): React.ReactNode {
    const { name, checked } = this.props;
    const { muted } = this.state;

    return (
      <DefaultButton
        toggle
        text={name}
        checked={muted || checked}
        onClick={() => this.setState((state) => ({ ...state, muted: !state.muted }))}
      ></DefaultButton>
    );
  }
}

const stackStyles: IStackStyles = {
  root: {
    background: DefaultPalette.purpleLight,
  },
};

export const App: React.FunctionComponent = () => {
  return (
    <Stack horizontalAlign="center" verticalAlign="center" verticalFill styles={stackStyles}>
      <ButtonControl name="React FTW!" checked={false} disabled={false} />
    </Stack>
  );
};

 

Helpful resources

Announcements
Power Apps News & Annoucements carousel

Power Apps News & Announcements

Keep up to date with current events and community announcements in the Power Apps community.

Community Call Conversations

Introducing the Community Calls Conversations

A great place where you can stay up to date with community calls and interact with the speakers.

Power Apps Community Blog Carousel

Power Apps Community Blog

Check out the latest Community Blog from the community!

Top Solution Authors
Users online (2,586)