Search code examples
reactjstypescriptoffice-ui-fabric

SpinButton: public property 'value' is undefined and public method 'focus()' is not a function


I have recently started with reactjs, typescript and Office UI Fabric. But I'm already struggling with one of the components from fabric. In this example I have a simple Product component with a SpinButton and a DefaultButton. When the DefaultButton is clicked I want to get the value of the SpinButton and set the focus on it. In order to get the ISpinButton interface members I'm using a ref of React.RefObject. My code looks like this:

import * as React from 'react';

import { DefaultButton } from 'office-ui-fabric-react/lib/Button';
import { SpinButton } from 'office-ui-fabric-react/lib/SpinButton';

class Product extends React.Component<{}, {}> {

    private spbStockRef: React.RefObject<SpinButton> = React.createRef<SpinButton>();

    public render(): JSX.Element {
        return (
            <React.Fragment>
                <SpinButton
                    ref={this.spbStockRef}
                    defaultValue="0"
                    label={'Stock '}
                    min={0}
                    max={99999}
                    step={1}
                    onFocus={() => console.log('onFocus called')}
                    onBlur={() => console.log('onBlur called')} />
                <DefaultButton onClick={this.onButtonClick} />
            </React.Fragment>)
    }

    private onButtonClick = (e: React.MouseEvent<HTMLButtonElement>) => {
        const node = this.spbStockRef.current!;

        if (node) {
            console.log(node.value);
            node.focus();
        }
    }
}
export default Product;

Inside onButtonClick the intellisense of Visual Studio suggests both 'value' and 'focus()' on the node variable so the actual ISpinButton members should be accessable.

But when the button is clicked the console.log(node.value) outputs undefined and a TypeError is raised on node.focus(): TypeError: node.focus is not a function. I also want to mention that console.log(node) outputs a proper instantiated object so the ref is working properly.

Any idea what I'm doing wrong here? In the examples of the SpinButton component there's also nothing that points out how to make this work.

https://developer.microsoft.com/en-us/fabric?example=#/components/spinbutton

Thank you


Solution

  • Inspired on Boy With Silver Wings his answer I have found a workaround. Instead of using a specific type for the RefObject I just declared it as any and then I was able to use the componentRef. So basically I had to override the required type (component?: ISpinButton | null) => void of the componentRef to make it work. I don't know if this should be reported as a bug.

    import * as React from 'react';
    
    import { DefaultButton } from 'office-ui-fabric-react/lib/Button';
    import { SpinButton } from 'office-ui-fabric-react/lib/SpinButton';
    
    class Product extends React.Component<{}, {}> {
    
        private spbStockRef: any = React.createRef();
    
        public render(): JSX.Element {
            return (
                <React.Fragment>
                    <SpinButton
                        componentRef={this.spbStockRef}
                        defaultValue="0"
                        label={'Stock '}
                        min={0}
                        max={99999}
                        step={1}
                        onFocus={() => console.log('onFocus called')}
                        onBlur={() => console.log('onBlur called')} />
                    <DefaultButton onClick={this.onButtonClick} />
                </React.Fragment>)
        }
    
        private onButtonClick = (e: React.MouseEvent<HTMLButtonElement>) => {
            const node = this.spbStockRef.current!;
    
            if (node) {
                console.log(node.value);
                node.focus();
            }
        }
    }
    export default Product;