How to change Select value in a Form?

Hi,

I try to have a Form with Selects where options and initial value of one Select can be changed by the value of another one.

I managed to change options but not the initial value. Below, I post a sample code where I do not change options but only try to change the value by clicking on a button.

I think that the problem is that we must use an uncontrolled component into the form (as explained in the documentation).
I think that could be solved by using reset or setValue but they are not available in the Form API.

Does anyone have an idea?

grafana-inputControl-value-pb

Code of above gif:

import React from 'react';
import { PanelProps } from '@grafana/data';
import { SimpleOptions } from 'types';
import { css, cx } from 'emotion';
// Trick to make Input happy with css. See issue #26512 on Grafana's github
import {} from '@emotion/core';
import { stylesFactory, Form, Field, Button, Select, InputControl } from '@grafana/ui';

interface FormDTO {
  cat: string;
  cat2: string;
}

function onSubmit(formData: FormDTO) {
  console.log('formData', formData);
}

const catOptions = [
  {
    label: 'Red',
    value: 'red',
  },
  {
    label: 'Blue',
    value: 'blue',
  },
];

const FormContext = React.createContext({});

interface Props extends PanelProps<SimpleOptions> {}

export const SimplePanel: React.FC<Props> = ({ options, data, width, height }) => {
  const styles = getStyles();
  const [catIndex, setCatIndex] = React.useState(0);
  const toggleCatIndex = React.useCallback(function() {
    setCatIndex(i => (i === 0 ? 1 : 0));
  }, []);
  return (
    <div
      className={cx(
        styles.wrapper,
        css`
          width: ${width}px;
          height: ${height}px;
        `
      )}
    >
      <Form onSubmit={(formData: FormDTO) => onSubmit(formData)}>
        {({ register, control, errors, watch }) => (
          <>
            <FormContext.Provider value={{ register, control, errors }}>
              <Field
                label="InputControl with value"
                /* By default Form component assumes form elements are uncontrolled .
      There are some components like RadioButton or Select that are controlled-only and require some extra work.
      To make them work with the form, you need to render those using InputControl component */
              >
                <InputControl
                  /* Render InputControl as controlled input (Select) */
                  as={Select}
                  /* Pass control exposed from Form render prop */
                  control={control}
                  name="cat"
                  options={catOptions}
                  disabled={true}
                  value={catOptions[catIndex]}
                />
              </Field>
              <Field
                label="InputControl with defaultValue"
                /* By default Form component assumes form elements are uncontrolled .
      There are some components like RadioButton or Select that are controlled-only and require some extra work.
      To make them work with the form, you need to render those using InputControl component */
              >
                <InputControl
                  /* Render InputControl as controlled input (Select) */
                  as={Select}
                  /* Pass control exposed from Form render prop */
                  control={control}
                  name="cat1"
                  options={catOptions}
                  disabled={true}
                  defaultValue={catOptions[catIndex]}
                />
              </Field>
              <Field label="Select with value">
                <Select
                  options={catOptions}
                  value={catOptions[catIndex]}
                  disabled={true}
                  onChange={v => console.log(v)}
                />
              </Field>
              <Button variant="primary">Save</Button>
            </FormContext.Provider>
            <Button variant="secondary" onClick={toggleCatIndex}>
              Toggle
            </Button>
          </>
        )}
      </Form>
    </div>
  );
};

const getStyles = stylesFactory(() => {
  return {
    wrapper: css`
      position: relative;
    `,
  };
});

Not 100% sure what’s you’re trying to achieve here, but maybe you could look into using watch to update the form elements dynamically on field changes? https://github.com/grafana/grafana/blob/master/packages/grafana-ui/src/components/Forms/Form.tsx#L27

My problem is not to receive udpates, as I said changing options works (albeit I didn’t put the corresponding code into my example).

My problem is really about to set the value.

You can use control.setValue to manually set the value inside InputControl onChange handler, but first make sure you’re passing correct value from the select, check the InputControl example: https://react-hook-form.com/v5/api#Controller

@alexkhomenko Thank you. I didn’t figure out from the doc that setValue was a method of control.