Update form fields at runtime

Hi All,

I am very new to Tina CMS and just started exploring forms.

May I know whether there is any way for me to update form fields at runtime, say by querying an api? I guess i’m looking for a setSate equivalent for form fields. I tried directly setting the values as follows, but it didn’t work. I am guessing what I am missing is a state change trigger

  const formConfig = {
    id: article.slug,
    label: 'Edit Article',
    fields: [
      {
        name: 'title',
        label: 'Title',
        component: 'text',
      },
      {
        name: 'summary',
        label: 'summary',
        component: 'text',
      },
      {
        name: 'description',
        label: 'description',
        component: 'markdown',
      },
    ],
    initialValues: {
      title: "",
      summary: "",
      description: "",
    },
    onSubmit: async (formData) => {
	// save data !!!!!
    },
  }

 // create and connect form
 
  const [modifiedValues, form] = useForm(formConfig)

  usePlugin(form)

// and later the code, try to update form with latest values from an external source

  useEffect( () => {
    axios.get(`http://localhost:5000/article/${slug}`).then((response) => {
      modifiedValues.title = response.data.title
      modifiedValues.summary = response.data.summary
      modifiedValues.description = response.data.description
    });
  }, []);

Any help towards a solution is much appreciated and thank you all for the Tina !!!

Hey, you can pass options to watch to useForm as the second argument:

useForm(formConfig, { fields: formConfig.fields })

It’s not my favourite API but it does the trick.

Here are the docs on watched variables in forms

HI ncphi, thank you verymuch for the quick response.

I tried passing the optional second parameter as suggested by you, but it dosent seems to have any effect (line 70). Then I tried to manually force a re-rendering by updating a different state (line 80) and saw the values appearing in component, but still not in the editor ui.

The interesting observation was in both cases, if I set focus on any of the editor fields in the editor, all values will show up in the editor. Following is the updated code and much appreciate if you could advice me what I am doing wrong

Lines of interest would be 70 and 76 to 80

import React, { useEffect, useState } from 'react';
import { Link, graphql } from "gatsby"

import Layout from "../components/layout"
import SEO from "../components/seo"
import { rhythm, scale } from "../utils/typography"

import { useForm, usePlugin, useCMS  } from 'tinacms'

import axios from "axios";

const BlogPostTemplate = ({ data, pageContext }) => {
  const slug = pageContext.slug;
  const siteTitle = data.site.siteMetadata.title
  const { previous, next } = pageContext
  
  const previousLink = `/${previous?.slug}`;
  const nextLink = `/${next?.slug}`;

  const [article, setArticle] = useState({
    slug: slug,
    title: "",
    summary: "",
    description: ""
  });

  const cms = useCMS();

  const formConfig = {
    id: article.slug,
    label: 'Edit Article',
    fields: [
      {
        name: 'title',
        label: 'Title',
        component: 'text',
      },
      {
        name: 'summary',
        label: 'summary',
        component: 'text',
      },
      {
        name: 'description',
        label: 'description',
        component: 'markdown',
      },
    ],
    initialValues: {
      title: article.title,
      summary: article.summary,
      description: article.description,
    },
    onSubmit: async (formData) => {
      const payload = {
        ...formData,
        slug: article.slug
      }

      const response = await axios.put(`http://localhost:5000/article/${payload.slug}`, payload)

      if (response.status === 200){
        cms.alerts.success('Saved!')
      }else{
        cms.alerts.error('failed!')
      }
    },
  }

  const [modifiedValues, form] = useForm(formConfig, { fields: formConfig.fields })

  usePlugin(form)

  useEffect( () => {
    axios.get(`http://localhost:5000/article/${slug}`).then((response) => {
      modifiedValues.title = response.data.title
      modifiedValues.summary = response.data.summary
      modifiedValues.description = response.data.description

      setArticle(response.data)
    });
  }, []);

  return (
    <Layout location={pageContext} title={siteTitle}>
      <SEO
        title={modifiedValues.title}
        description={modifiedValues.description}
      />
      <article itemScope itemType="http://schema.org/Article">
        <header>
          <h1
            itemProp="headline"
            style={{
              marginTop: rhythm(1),
              marginBottom: 0,
            }}
          >
            {modifiedValues.title}
          </h1>
          <p
            style={{
              ...scale(-1 / 5),
              display: `block`,
              marginBottom: rhythm(1),
            }}
          >
            {modifiedValues.summary}
          </p>
        </header>
        <section
          dangerouslySetInnerHTML={{ __html: modifiedValues.description }}
          itemProp="articleBody"
        />
        <hr
          style={{
            marginBottom: rhythm(1),
          }}
        />
      </article>


      <nav>
        <ul
          style={{
            display: `flex`,
            flexWrap: `wrap`,
            justifyContent: `space-between`,
            listStyle: `none`,
            padding: 0,
          }}
        >
          <li>
            {previous && (
              <Link to={previousLink}>
                ← {previous.title}
              </Link>
            )}
          </li>
          <li>
            {next && (
              <Link to={nextLink}>
                {next.title} →
              </Link>
            )}
          </li>
        </ul>
      </nav>
    </Layout>
  )
}

export default BlogPostTemplate

export const pageQuery = graphql`
  query ArticlesBySlug {
    site {
      siteMetadata {
        title
      }
    }
  }
`

Hi Nolan, I used loadInitialValues to load values from the api. That, coupled with useForm(formConfig, { fields: formConfig.fields }) as suggested by which fixed set-state issue.

But, I would still like to know the best way to manually set form variables any time during the workflow, specifically why the above fails to work

Cheers