How to sent the formData which created by material UI and submit to the backend with api part

So when I create a mahjong game rule page first I use
rw g scaffold gameRule

and I remember in the Post tutorial, the PostForm was actually used by New and Edit , and because one of field in the scaffold mode it didn’t work properly (or I guarantee don’t know how to do that because I totally new for frontend part…) so I using MUI and design the form like following: (That is how it looks like right now in GameRuleForm.tsx)

However I don’t know how to link it together with the submit… So currently the onSubmit it just log the formData and I confirm it works… but how I can send that to backend?

Also when I click EDIT it only show the blank screen as above, but not the data pre-populate it… is it something that I missing?

Here is the code right now

import React, { useState } from 'react'

import {
  Grid,
  TextField,
  FormControl,
  FormControlLabel,
  RadioGroup,
  Radio,
  Checkbox,
  Button,
  FormLabel,
  TableContainer,
  Paper,
  Table,
  TableHead,
  TableCell,
  TableBody,
  TableRow,
} from '@mui/material'
import type { EditGameRuleById, UpdateGameRuleInput } from 'types/graphql'

import type { RWGqlError } from '@redwoodjs/forms'

type FormGameRule = NonNullable<EditGameRuleById['gameRule']>

interface GameRuleFormProps {
  gameRule?: EditGameRuleById['gameRule']
  onSave: (data: UpdateGameRuleInput, id?: FormGameRule['id']) => void
  error: RWGqlError
  loading: boolean
}

const GameRuleForm = (props: GameRuleFormProps) => {
  const [gameType, setGameType] = useState('')
  const [name, setName] = useState('')
  const [startingScore, setStartingScore] = useState('')
  const [notenPenalty, setNotenPenalty] = useState('')
  const [honbaScore, setHonbaScore] = useState('')
  const [tiebreaker, setTiebreaker] = useState('')
  const [oka, setOka] = useState('')
  const [chomboPenalty, setChomboPenalty] = useState('')
  const [multiRonEnabled, setMultiRonEnabled] = useState(false)
  const [kiriageManganEnabled, setKiriageManganEnabled] = useState(false)
  const [multipleYakumanEnabled, setMultipleYakumanEnabled] = useState(false)
  const [stackYakumanEnabled, setStackYakumanEnabled] = useState(false)
  const [tiebreakerType, setTiebreakerType] = useState('')

  const umaValues = [
    [0, 0, 0, 0],
    [0, 0, 0, 0],
    [0, 0, 0, 0],
    [0, 0, 0, 0],
    [0, 0, 0, 0],
  ]

  function setUmaValues(row, column, value) {
    console.log(
      'Try to change the value for constant in umaValues[' +
        row +
        '][' +
        column +
        '] with value: ' +
        value
    )
    umaValues[row][column] = value
    return umaValues
  }

  const handleUma0SinkFirstChange = (event) => {
    setUmaValues(0, 0, event.target.value)
  }

  const handleUma0SinkSecondChange = (event) => {
    setUmaValues(0, 1, event.target.value)
  }
  const handleUma0SinkThirdChange = (event) => {
    setUmaValues(0, 2, event.target.value)
  }
  const handleUma0SinkFourthChange = (event) => {
    setUmaValues(0, 3, event.target.value)
  }

  const handleUma1SinkFirstChange = (event) => {
    setUmaValues(1, 0, event.target.value)
  }

  const handleUma1SinkSecondChange = (event) => {
    setUmaValues(1, 1, event.target.value)
  }
  const handleUma1SinkThirdChange = (event) => {
    setUmaValues(1, 2, event.target.value)
  }
  const handleUma1SinkFourthChange = (event) => {
    setUmaValues(1, 3, event.target.value)
  }

  const handleUma2SinkFirstChange = (event) => {
    setUmaValues(2, 0, event.target.value)
  }

  const handleUma2SinkSecondChange = (event) => {
    setUmaValues(2, 1, event.target.value)
  }
  const handleUma2SinkThirdChange = (event) => {
    setUmaValues(2, 2, event.target.value)
  }
  const handleUma2SinkFourthChange = (event) => {
    setUmaValues(2, 3, event.target.value)
  }

  const handleUma3SinkFirstChange = (event) => {
    setUmaValues(3, 0, event.target.value)
  }

  const handleUma3SinkSecondChange = (event) => {
    setUmaValues(3, 1, event.target.value)
  }
  const handleUma3SinkThirdChange = (event) => {
    setUmaValues(3, 2, event.target.value)
  }
  const handleUma3SinkFourthChange = (event) => {
    setUmaValues(3, 3, event.target.value)
  }

  const handleUma4SinkFirstChange = (event) => {
    setUmaValues(4, 0, event.target.value)
  }

  const handleUma4SinkSecondChange = (event) => {
    setUmaValues(4, 1, event.target.value)
  }
  const handleUma4SinkThirdChange = (event) => {
    setUmaValues(4, 2, event.target.value)
  }
  const handleUma4SinkFourthChange = (event) => {
    setUmaValues(4, 3, event.target.value)
  }

  const handleGameTypeChange = (event) => {
    setGameType(event.target.value)
  }

  const handleNameChange = (event) => {
    setName(event.target.value)
  }

  const handleStartingScoreChange = (event) => {
    setStartingScore(event.target.value)
  }

  const handleNotenPenaltyChange = (event) => {
    setNotenPenalty(event.target.value)
  }

  const handleHonbaScoreChange = (event) => {
    setHonbaScore(event.target.value)
  }

  const handleTiebreakerChange = (event) => {
    setTiebreaker(event.target.value)
  }

  const handleOkaChange = (event) => {
    setOka(event.target.value)
  }

  const handleChomboPenaltyChange = (event) => {
    setChomboPenalty(event.target.value)
  }

  const handleMultiRonEnabledChange = (event) => {
    setMultiRonEnabled(event.target.checked)
  }

  const handleKiriageManganEnabledChange = (event) => {
    setKiriageManganEnabled(event.target.checked)
  }

  const handleMultipleYakumanEnabledChange = (event) => {
    setMultipleYakumanEnabled(event.target.checked)
  }

  const handleStackYakumanEnabledChange = (event) => {
    setStackYakumanEnabled(event.target.checked)
  }

  const handleTiebreakerTypeChange = (event) => {
    setTiebreakerType(event.target.value)
  }

  const handleSubmit = (event) => {
    event.preventDefault()

    // Form data submission logic here
    const formData = {
      gameType,
      name,
      startingScore,
      notenPenalty,
      honbaScore,
      tiebreaker,
      umaValues,
      oka,
      chomboPenalty,
      multiRonEnabled,
      kiriageManganEnabled,
      multipleYakumanEnabled,
      stackYakumanEnabled,
      tiebreakerType,
    }
    console.log(formData)

    props.gameRule.uma0Over = umaValues[4]
    props.gameRule.uma1Over = umaValues[3]
    props.gameRule.uma2Over = umaValues[2]
    props.gameRule.uma3Over = umaValues[1]

    props.onSave(props, props?.gameRule?.id);

  }

  return (
    <form onSubmit={handleSubmit}>
      <Grid container spacing={2}>
        <Grid item xs={12}>
          <FormControl component="fieldset">
            <FormLabel>Game Type</FormLabel>
            <RadioGroup
              name="gameType"
              value={gameType}
              onChange={handleGameTypeChange}
            >
              <FormControlLabel
                value="YONMA"
                control={<Radio />}
                label="YONMA"
              />
              <FormControlLabel
                value="SANMA"
                control={<Radio />}
                label="SANMA"
              />
            </RadioGroup>
          </FormControl>
        </Grid>
        <Grid item xs={12}>
          <FormControl>
            <FormLabel>Name</FormLabel>
            <TextField
              variant="outlined"
              type="text"
              value={name}
              onChange={handleNameChange}
            />
          </FormControl>
        </Grid>
        <Grid item xs={12}>
          <FormControl>
            <FormLabel>Starting Score</FormLabel>
            <TextField
              variant="outlined"
              type="number"
              value={startingScore}
              onChange={handleStartingScoreChange}
            />
          </FormControl>
        </Grid>
        <Grid item xs={12}>
          <FormControl>
            <FormLabel>Noten Penalty</FormLabel>
            <TextField
              variant="outlined"
              type="number"
              value={notenPenalty}
              onChange={handleNotenPenaltyChange}
            />
          </FormControl>
        </Grid>
        <Grid item xs={12}>
          <FormControl>
            <FormLabel>Honba Score</FormLabel>
            <TextField
              variant="outlined"
              type="number"
              value={honbaScore}
              onChange={handleHonbaScoreChange}
            />
          </FormControl>
        </Grid>
        <Grid item xs={12}>
          <FormControl component="fieldset">
            <FormLabel>Tiebreaker</FormLabel>
            <RadioGroup
              name="tiebreaker"
              value={tiebreaker}
              onChange={handleTiebreakerChange}
            >
              <FormControlLabel
                value="DIVIDE_EQUALLY"
                control={<Radio />}
                label="Divide Equally"
              />
              <FormControlLabel
                value="WIND_ORDER"
                control={<Radio />}
                label="Wind Order"
              />
            </RadioGroup>
          </FormControl>
        </Grid>
        <Grid item xs={12}>
          <TableContainer component={Paper}>
            <Table sx={{ minWidth: 650 }} aria-label="simple table">
              <TableHead>
                <TableCell>Uma\With sink the sea</TableCell>
                <TableCell>1st Place</TableCell>
                <TableCell>2st Place</TableCell>
                <TableCell>3st Place</TableCell>
                <TableCell>4st Place</TableCell>
              </TableHead>
              <TableBody>
                <TableRow
                  sx={{ '&:last-child td, &:last-child th': { border: 0 } }}
                >
                  <TableCell>Uma 0 Sink</TableCell>
                  <TableCell>
                    <TextField onChange={handleUma0SinkFirstChange} />
                  </TableCell>
                  <TableCell>
                    <TextField onChange={handleUma0SinkSecondChange} />
                  </TableCell>
                  <TableCell>
                    <TextField onChange={handleUma0SinkThirdChange} />
                  </TableCell>
                  <TableCell>
                    <TextField onChange={handleUma0SinkFourthChange} />
                  </TableCell>
                </TableRow>
                <TableRow
                  sx={{ '&:last-child td, &:last-child th': { border: 0 } }}
                >
                  <TableCell>Uma 1 Sink</TableCell>
                  <TableCell>
                    <TextField onChange={handleUma1SinkFirstChange}></TextField>
                  </TableCell>
                  <TableCell>
                    <TextField
                      onChange={handleUma1SinkSecondChange}
                    ></TextField>
                  </TableCell>
                  <TableCell>
                    <TextField onChange={handleUma1SinkThirdChange}></TextField>
                  </TableCell>
                  <TableCell>
                    <TextField
                      onChange={handleUma1SinkFourthChange}
                    ></TextField>
                  </TableCell>
                </TableRow>
                <TableRow
                  sx={{ '&:last-child td, &:last-child th': { border: 0 } }}
                >
                  <TableCell>Uma 2 Sink</TableCell>
                  <TableCell>
                    <TextField onChange={handleUma2SinkFirstChange}></TextField>
                  </TableCell>
                  <TableCell>
                    <TextField
                      onChange={handleUma2SinkSecondChange}
                    ></TextField>
                  </TableCell>
                  <TableCell>
                    <TextField onChange={handleUma2SinkThirdChange}></TextField>
                  </TableCell>
                  <TableCell>
                    <TextField
                      onChange={handleUma2SinkFourthChange}
                    ></TextField>
                  </TableCell>
                </TableRow>
                <TableRow
                  sx={{ '&:last-child td, &:last-child th': { border: 0 } }}
                >
                  <TableCell>Uma 3 Sink</TableCell>
                  <TableCell>
                    <TextField onChange={handleUma3SinkFirstChange}></TextField>
                  </TableCell>
                  <TableCell>
                    <TextField
                      onChange={handleUma3SinkSecondChange}
                    ></TextField>
                  </TableCell>
                  <TableCell>
                    <TextField onChange={handleUma3SinkThirdChange}></TextField>
                  </TableCell>
                  <TableCell>
                    <TextField
                      onChange={handleUma3SinkFourthChange}
                    ></TextField>
                  </TableCell>
                </TableRow>
                <TableRow
                  sx={{ '&:last-child td, &:last-child th': { border: 0 } }}
                >
                  <TableCell>Uma 4 Sink</TableCell>
                  <TableCell>
                    <TextField onChange={handleUma4SinkFirstChange}></TextField>
                  </TableCell>
                  <TableCell>
                    <TextField
                      onChange={handleUma4SinkSecondChange}
                    ></TextField>
                  </TableCell>
                  <TableCell>
                    <TextField onChange={handleUma4SinkThirdChange}></TextField>
                  </TableCell>
                  <TableCell>
                    <TextField
                      onChange={handleUma4SinkFourthChange}
                    ></TextField>
                  </TableCell>
                </TableRow>
              </TableBody>
            </Table>
          </TableContainer>
        </Grid>
        <Grid item xs={12}>
          <FormControl>
            <FormLabel>Oka</FormLabel>
            <TextField
              variant="outlined"
              type="number"
              value={oka}
              onChange={handleOkaChange}
            />
          </FormControl>
        </Grid>
        <Grid item xs={12}>
          <FormControl>
            <FormLabel>Chombo Penalty</FormLabel>
            <TextField
              variant="outlined"
              type="number"
              value={chomboPenalty}
              onChange={handleChomboPenaltyChange}
            />
          </FormControl>
        </Grid>
        <Grid item xs={12}>
          <FormControlLabel
            control={
              <Checkbox
                checked={multiRonEnabled}
                onChange={handleMultiRonEnabledChange}
              />
            }
            label="Multi Ron Enabled"
          />
        </Grid>
        <Grid item xs={12}>
          <FormControlLabel
            control={
              <Checkbox
                checked={kiriageManganEnabled}
                onChange={handleKiriageManganEnabledChange}
              />
            }
            label="Kiriage Mangan Enable"
          />
        </Grid>
        <Grid item xs={12}>
          <FormControlLabel
            control={
              <Checkbox
                checked={multipleYakumanEnabled}
                onChange={handleMultipleYakumanEnabledChange}
              />
            }
            label="Multiple Yakuman Enable"
          />
        </Grid>
        <Grid item xs={12}>
          <FormControlLabel
            control={
              <Checkbox
                checked={stackYakumanEnabled}
                onChange={handleStackYakumanEnabledChange}
              />
            }
            label="Stack Yakuman Enable"
          />
        </Grid>
        <Grid item xs={12}>
          <FormControl component="fieldset">
            <FormLabel>Tiebreaker</FormLabel>
            <RadioGroup
              name="tiebreakerType"
              value={tiebreakerType}
              onChange={handleTiebreakerTypeChange}
            >
              <FormControlLabel
                value="LOST_FOREVER"
                control={<Radio />}
                label="Lost Forever"
              />
              <FormControlLabel
                value="FIRST_PLACE"
                control={<Radio />}
                label="First Place"
              />
            </RadioGroup>
          </FormControl>
        </Grid>
        <Grid item xs={12}>
          <Button variant="contained" type="submit" color="primary">
            Submit
          </Button>
        </Grid>
      </Grid>
    </form>
  )
}

export default GameRuleForm

:wave: Hey @vincentz - you will need to submit your data to the database using a mutation. This part of Redwood is a stumbling block for many, so please feel free to come back with any follow up as you work through it. If you generate the SDL/Services on the Model then you will get a lot of the mutations you need. However, depending on the complexity of your models, you may have to customize them to set up relationships or other things. If you do customize them, be careful not to regen the sdl/service which could overwrite your changes.

@arimendelow gave a nice, brief summary of mutating data on the DB which is:

if you want a mutation for only that field, what you’ll need to do is as follows:

on the api side:

  1. define the mutation type to accept whatever parameters are needed to update that field, ie the post id and field value
  2. create the corresponding mutation resolver in the model’s service

on the web side:

  1. create a form that uses this mutation

reread chapter 3 for more detailed examples and information: Saving Data | RedwoodJS Docs

To add to this, Chapter 6 - Adding Comments to the Schema goes through building SDL/Services manually.

1 Like