Help with updating a field in a Sanity document using customComponent and useDocumentOperation
24 replies
Last updated: Apr 24, 2023
Y
Hi everyone, I need a help with customComponent I am trying to change another field from the same document by
but the value of the target field is not changing, What am I missing?
const { patch } = useDocumentOperation(props.id, props.schemaType.name); patch.execute([{ set: { path: pathSegments, value: 'testValue' } }])
Apr 23, 2023, 8:49 PM
L
similar question to mine! I've just done some digging, and found
you can use this as such to get the document ID:
Now, if the document is a draft, it will be prefixed with
e.g:
Had to do a
useFormValuein the docs (https://www.sanity.io/docs/studio-react-hooks#5cb6622b6381 )
you can use this as such to get the document ID:
const documentId = useFormValue(["_id"]);
draft.So that needs to be removed in order to pass it into
useDocumentOperation
e.g:
const documentId = useFormValue(["_id"]); const docId = typeof documentId === "string" ? documentId.replace("drafts.", "") : props.id;
typeofin front of the replace in my case, as Typescript kept complaining it was a Type
unknown, and I'm still relatively new to TS in general!
Apr 23, 2023, 9:05 PM
L
props.idin this case returns the name of the field that you set in your schema, so ultimately I think it doesn't do anything to update the document as a whole. Otherwise would be a lot easier!
Apr 23, 2023, 9:06 PM
Y
useFormValueis ok when I need to change current field, in my case I need to change different field
Apr 24, 2023, 8:28 AM
Y
here is the example what I am building
Apr 24, 2023, 8:29 AM
Y
I want ‘Translate All’ fill all non-english terms to be changed
Apr 24, 2023, 8:29 AM
L
Yeah, the
useFormValueallows you to get the document ID to update different fields in the same document
Apr 24, 2023, 8:36 AM
Y
indeed, last question why its not setting new value
patch.execute([{ 'set': { path: pathSegments, value: 'testValue' } }])
Apr 24, 2023, 8:47 AM
Y
so I have
const { patch } = useDocumentOperation(docId!, props.schemaType.name); //<https://translation.googleapis.com/language/translate/v2?q=super> puper text that needs translation&target=uk&format=text&source=en&model=base&key= async function translateText() { if (source !== undefined || source !== 'undefined' || source !== '' || source !== null) { const res = await <http://axios.post|axios.post><TranslateRespose>( `<https://translation.googleapis.com/language/translate/v2?q=${source}&target=${locale}&format=text&source=en&model=base&key=${key}>` ); const translatedText = res.data.data.translations[0].translatedText; onChange(PatchEvent.from(set(translatedText))) } } async function translateAllChildrenText() { languages.map(async (lang) => { var pathSegments = [...props.path]; pathSegments[pathSegments.length - 1] = lang.id; patch.execute([{ 'set': { path: pathSegments, value: 'testValue' } }]) }) }
Apr 24, 2023, 8:48 AM
L
The set object should look something like this:
Not sure what your schema fields are called, so try setting
patch.execute([ { set: { SCHEMA_FIELD_NAME: NEW_VALUE, } } ])
SCHEMA_FIELD_NAME: 'testValue'
Apr 24, 2023, 8:58 AM
Y
sorry for stupid question but I have this structure
Apr 24, 2023, 9:09 AM
Y
I was trying to use SCHEMA_FILED_NAME `name.uk ’
name[uk]
Apr 24, 2023, 9:09 AM
Y
but its not settings up values
Apr 24, 2023, 9:09 AM
L
can you share the document schema you're updating?
Apr 24, 2023, 9:10 AM
Y
sure
import {MdLibraryMusic as icon} from 'react-icons/md' import {MdYoutubeSearchedFor as seoIcon} from 'react-icons/md' import {defineField, defineType} from 'sanity' import DurationInputComponent from '../components/DurationInputComponent' import TranslateStringInputComponent from '../components/TranslateStringInputComponent' export default defineType({ name: 'track', title: 'Track', type: 'document', icon, groups: [ { name: 'seo', title: 'SEO', icon: seoIcon, }, { name: 'codes', title: 'Codes', }, { name: 'metadata', title: 'Metadata', }, { name: 'statistics', title: 'Stats', }, ], fields: [ defineField({ name: 'name', title: 'Name', type: 'localeString', group: 'metadata', options: { languageFilter: true, }, validation: (Rule) => Rule.required(), }), defineField({ name: 'description', title: 'description', type: 'localeString', group: 'metadata', options: { languageFilter: true, }, validation: (Rule) => Rule.required(), }), defineField({ name: 'isFeatured', title: 'Is Featured', type: 'boolean', validation: (Rule) => Rule.required(), }), defineField({ name: 'tags', title: 'Tags', type: 'array', // validation: (Rule) => Rule.required(), of: [{type: 'reference', to: [{type: 'searchTag'}]}], }), defineField({ name: 'image', title: 'Poster Image', type: 'image', group: 'metadata', validation: (Rule) => Rule.required(), options: { hotspot: true, }, }), defineField({ name: 'file', title: 'File', type: 'file', validation: (Rule) => Rule.required(), }), defineField({ name: 'slug', title: 'Slug', type: 'slug', options: { source: 'name', maxLength: 100, }, }), defineField({ name: 'tempo', title: 'Tempo', type: 'number', group: 'metadata', initialValue: 100, validation: (Rule) => Rule.precision(0).positive() && Rule.max(200) && Rule.min(50) && Rule.required(), }), defineField({ name: 'duration', title: 'Duration (seconds)', type: 'number', group: 'metadata', readOnly: true, components: { input: DurationInputComponent, }, }), defineField({ name: 'visitCount', title: 'Visit', type: 'number', group: 'statistics', }), defineField({ name: 'playCount', title: 'Play', type: 'number', group: 'statistics', }), defineField({ name: 'downloadCount', title: 'Download', type: 'number', group: 'statistics', }), defineField({ name: 'buyCount', title: 'Buy', type: 'number', group: 'statistics', }), defineField({ name: 'upc', title: 'UPC', type: 'string', validation: (Rule) => Rule.required(), group: 'codes', }), defineField({ name: 'isrc', title: 'ISRC', type: 'string', validation: (Rule) => Rule.required(), group: 'codes', }), defineField({ name: 'iswc', title: 'ISWC', type: 'string', validation: (Rule) => Rule.required(), group: 'codes', }), defineField({ name: 'recordLabel', title: 'Record Label', type: 'string', validation: (Rule) => Rule.required(), }), defineField({ name: 'artists', title: 'Artists', type: 'array', validation: (Rule) => Rule.required(), of: [{type: 'reference', to: [{type: 'artist'}]}], }), defineField({ name: 'composers', title: 'Composers', type: 'array', validation: (Rule) => Rule.required(), of: [{type: 'reference', to: [{type: 'composer'}]}], }), defineField({ name: 'sources', title: 'Sources', type: 'array', of: [{type: 'streamingService'}], }), defineField({ name: 'moods', title: 'Moods', type: 'array', validation: (Rule) => Rule.required(), of: [{type: 'reference', to: [{type: 'mood'}]}], }), defineField({ name: 'ganres', title: 'Ganres', type: 'array', validation: (Rule) => Rule.required(), of: [{type: 'reference', to: [{type: 'ganre'}]}], }), defineField({ name: 'seo', title: 'SEO', type: 'pageSeo', group: 'seo', // validation: (Rule) => Rule.required(), }), ], preview: { select: { name: 'name', media: 'image', isFeatured: 'isFeatured', }, prepare(selection) { const {name, media, isFeatured} = selection return { title: name['en'], media, subtitle: isFeatured ? '⭐️ Featured' : '', } }, }, initialValue: { isFeatured: false, recordLabel: 'lesfreemusic', sources: [ {name: 'Patreon', icon: 'mdi:patreon'}, {name: 'Spotify', icon: 'mdi:spotify'}, {name: 'Apple Music', icon: 'cib:apple-music'}, {name: 'iTunes', icon: 'simple-icons:itunes'}, {name: 'Youtube', icon: 'uil:youtube'}, {name: 'Youtube Music', icon: 'arcticons:youtube-music'}, {name: 'Amazon Music', icon: 'arcticons:amazon-music'}, {name: 'Amazon', icon: 'simple-icons:amazon'}, {name: 'TikTok', icon: 'ic:baseline-tiktok'}, {name: 'Instagram', icon: 'mdi:instagram'}, {name: 'SoundCloud', icon: 'mdi:soundcloud'}, {name: 'Deezer', icon: 'tabler:brand-deezer'}, ], composers: [{_ref: '45688ba9-a315-400b-98b3-b8c1442b9aa4'}], }, })
Apr 24, 2023, 9:14 AM
Y
import {defineType} from 'sanity' import TranslateStringInputComponent from '../../components/TranslateStringInputComponent' import {languages} from '../../supportedLanguages' // const languages = [ // {id: 'en', title: 'English', isDefault: true}, // {id: 'uk', title: 'Ukrainian'}, // {id: 'cs', title: 'Czech'}, // {id: 'da', title: 'Danish'}, // {id: 'de', title: 'German'}, // {id: 'es', title: 'Spanish'}, // {id: 'fr', title: 'French'}, // {id: 'it', title: 'Italian'}, // {id: 'hu', title: 'Hungarian'}, // {id: 'nl', title: 'Dutch'}, // {id: 'pl', title: 'Polish'}, // {id: 'pt', title: 'Portuguese'}, // {id: 'pt_BR', title: 'Portuguese (Brazil)'}, // {id: 'fi', title: 'Finnish'}, // {id: 'sv', title: 'Swedish'}, // {id: 'tr', title: 'Turkish'}, // {id: 'ru', title: 'Russian'}, // {id: 'th', title: 'Thai'}, // {id: 'ko', title: 'Korean'}, // {id: 'ja', title: 'Japanese'}, // {id: 'zh_CN', title: 'Chinese (Simplified)'}, // {id: 'zh_TW', title: 'Chinese (Traditional)'}, // {id: 'ar', title: 'Arabic'}, // {id: 'he', title: 'Hebrew'}, // {id: 'hi', title: 'Hindi'}, // {id: 'id', title: 'Indonesian'}, // {id: 'fil', title: 'Filipino'}, // {id: 'vi', title: 'Vietnamese'}, // ] export default defineType({ name: 'localeString', title: 'Locale String', type: 'object', fieldsets: [ { title: 'Translations', name: 'translations', options: {collapsible: true, collapsed: true}, }, ], // @ts-ignore fields: languages.map((lang) => ({ name: lang.id, title: lang.title, type: 'string', // or `text`, etc fieldset: lang.isDefault ? null : 'translations', components: { input: TranslateStringInputComponent, }, })), })`
Apr 24, 2023, 9:15 AM
L
Just to make sure I'm reading that right, only name and description are using your localeString type, and that's where the translations should be populating?
Apr 24, 2023, 9:19 AM
Y
yes
Apr 24, 2023, 9:21 AM
L
so I'm guessing a little bit here, would the following work?
patch.execute([ { set: { name: { uk: 'test value', } } } ])
Apr 24, 2023, 9:25 AM
Y
you made my day, if you need music for videos let me know I will give you a license for using over 900 tracks from my library
Apr 24, 2023, 9:26 AM
L
awesome, glad it worked out! 😄
Apr 24, 2023, 9:27 AM
Y
user H
be my saver today I cant apply all patches I am trying to execute thisconst translations = await Promise.all(languages.map(async (lang) => { var pathSegments = [...props.path]; pathSegments[pathSegments.length - 1] = lang.id; const path = pathSegments.join('.'); const translation = lang.id === 'en' ? source : await translate(source, `${lang.id}`); console.log('test: ', path); const patch = { set: { name: { [lang.id]: translation } } }; patches.push(patch); return translation; })); console.log('translations: ', translations); console.log('patches: ', patches); const res = patch.execute(patches)
Apr 24, 2023, 10:55 AM
Y
even when I am trying to do this
const res = patch.execute([ { set: { name: { uk: 'ukr' } } }, { set: { name: { en: source } } }, { set: { name: { de: 'de value' } } }, ])
Apr 24, 2023, 10:55 AM
Y
I’ve got only de filed updated and en is earased
Apr 24, 2023, 10:56 AM
L
I guess it would depend how you're doing the translations? Does it only translate one file at a time?
I'd say maybe populate and object as follows:
and then run your set as:
and see if that works to update multiple fields?
Then you could populate the object with all the keys + translations, and pass it through as one patch?
I'd say maybe populate and object as follows:
const nameTranslation = { uk: 'uk name', en: 'en name', de: 'de name', }
set: { name: nameTranslation }
Then you could populate the object with all the keys + translations, and pass it through as one patch?
Apr 24, 2023, 11:48 AM
Sanity– build remarkable experiences at scale
Sanity is a modern headless CMS that treats content as data to power your digital business. Free to get started, and pay-as-you-go on all plans.