From 5e6d2f518bdf20b77c8081b1e8a8c4b9e5a3a1e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sedat=20=C3=96ZT=C3=9CRK?= <76204082+iamsedatozturk@users.noreply.github.com> Date: Mon, 1 Jun 2026 17:19:49 +0300 Subject: [PATCH] =?UTF-8?q?FormDevexpress=20Default=20Value=20de=C4=9Ferle?= =?UTF-8?q?ri=20d=C3=BCzenlendi?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ui/src/views/form/FormDevExpress.tsx | 110 ++++++++++++++++++--------- ui/src/views/form/FormNew.tsx | 62 ++++++++++++--- 2 files changed, 127 insertions(+), 45 deletions(-) diff --git a/ui/src/views/form/FormDevExpress.tsx b/ui/src/views/form/FormDevExpress.tsx index 650c80a..88906f9 100644 --- a/ui/src/views/form/FormDevExpress.tsx +++ b/ui/src/views/form/FormDevExpress.tsx @@ -156,6 +156,7 @@ const FormDevExpress = (props: { const formDataRef = useRef(formData) const formItemsRef = useRef(formItems) const formInstanceRef = useRef() + const lastContentReadyScriptKeyRef = useRef() useEffect(() => { formDataRef.current = formData @@ -224,13 +225,77 @@ const FormDevExpress = (props: { updateCascadeDisabledStates() }, [formData, mode]) + const runReadOnlyScripts = (form: any) => { + if (!form) return + + const currentFormData = { + ...(formDataRef.current || {}), + ...(form?.option?.('formData') || {}), + } + formDataRef.current = currentFormData + + formItemsRef.current + .flatMap((group) => flattenFormItems([group])) + .filter((formItem) => shouldRunEditorScriptOnContentReady(formItem.editorScript)) + .forEach((formItem) => { + try { + const editor = { + dataField: formItem.dataField, + component: form, + } + const formData = currentFormData + const e = { + component: form, + dataField: formItem.dataField, + value: getValueByField(currentFormData, formItem.dataField), + } + const runtimeSetEditorReadOnly = (field: string, readOnly: boolean) => + setFormEditorReadOnly(form, field, readOnly) + + eval(formItem.editorScript!) + } catch (err) { + console.error('Script execution failed on contentReady for', formItem.name, err) + } + }) + } + + useEffect(() => { + const form = formInstanceRef.current + if (!form || mode === 'view' || !formData || !formItems?.length) { + return + } + + const scriptFields = formItemsRef.current + .flatMap((group) => flattenFormItems([group])) + .filter((formItem) => shouldRunEditorScriptOnContentReady(formItem.editorScript)) + .map((formItem) => formItem.dataField) + .join('|') + + if (!scriptFields) { + return + } + + const scriptKey = `${mode}|${scriptFields}|${JSON.stringify(formData)}` + if (lastContentReadyScriptKeyRef.current === scriptKey) { + return + } + + lastContentReadyScriptKeyRef.current = scriptKey + setTimeout(() => runReadOnlyScripts(form), 0) + }, [formData, formItems, mode]) + return ( { - const newFormData = { ...formData, [e.dataField!]: e.value } + if (!e.dataField) { + return + } + + const newFormData = { ...formData, [e.dataField]: e.value } + let hasChanges = !Object.is(formData?.[e.dataField], e.value) // Cascading child field'leri temizle (parent field değiştiğinde) const allItems = formItemsRef.current.flatMap((group) => flattenFormItems([group])) @@ -241,10 +306,15 @@ const FormDevExpress = (props: { // Parent field değiştiğinde child field'leri temizle cascadingChildren.forEach((child) => { - newFormData[child.dataField!] = null + if (!Object.is(newFormData[child.dataField!], null)) { + newFormData[child.dataField!] = null + hasChanges = true + } }) - setFormData(newFormData) + if (hasChanges) { + setFormData(newFormData) + } // Cascade disabled durumlarını güncelle (setTimeout ile editor güncellemesinden sonra çalışsın) setTimeout(() => { @@ -285,40 +355,8 @@ const FormDevExpress = (props: { formInstanceRef.current = e.component const form = e.component - const runtimeSetEditorReadOnly = (field: string, readOnly: boolean) => - setFormEditorReadOnly(form, field, readOnly) - const runReadOnlyScripts = () => { - const currentFormData = { - ...(formDataRef.current || {}), - ...(form?.option?.('formData') || {}), - } - formDataRef.current = currentFormData - - formItemsRef.current - .flatMap((group) => flattenFormItems([group])) - .filter((formItem) => shouldRunEditorScriptOnContentReady(formItem.editorScript)) - .forEach((formItem) => { - try { - const editor = { - dataField: formItem.dataField, - component: form, - } - const formData = currentFormData - const e = { - component: form, - dataField: formItem.dataField, - value: getValueByField(currentFormData, formItem.dataField), - } - - eval(formItem.editorScript!) - } catch (err) { - console.error('Script execution failed on contentReady for', formItem.name, err) - } - }) - } - - runReadOnlyScripts() + runReadOnlyScripts(form) const groupItems = e.component.option('items') as any[] const firstItem = groupItems?.[0]?.items?.[0] diff --git a/ui/src/views/form/FormNew.tsx b/ui/src/views/form/FormNew.tsx index 343d0df..3ffac4d 100644 --- a/ui/src/views/form/FormNew.tsx +++ b/ui/src/views/form/FormNew.tsx @@ -2,7 +2,7 @@ import { Container, Loading } from '@/components/shared' import { useLocalization } from '@/utils/hooks/useLocalization' import { DataType } from 'devextreme/common' import { SimpleItem } from 'devextreme/ui/form' -import { useEffect, useState } from 'react' +import { useEffect, useRef, useState } from 'react' import { Helmet } from 'react-helmet' import { useNavigate, useParams, useSearchParams } from 'react-router-dom' import FormButtons from './FormButtons' @@ -12,6 +12,9 @@ import { useGridData } from './useFormData' import { useCurrentMenuIcon } from '@/utils/hooks/useCurrentMenuIcon' import { Badge } from '@/components/ui' import { APP_NAME } from '@/constants/app.constant' +import { FieldCustomValueTypeEnum } from '@/proxy/form/models' +import { getNextSequenceValue } from '@/services/form.service' +import { autoNumber } from '../list/Utils' const FormNew = ( props: FormProps = { @@ -26,6 +29,7 @@ const FormNew = ( const { translate } = useLocalization() const MenuIcon = useCurrentMenuIcon('w-5 h-5') const navigate = useNavigate() + const initializedListFormCodeRef = useRef() const { fetchData, @@ -58,16 +62,34 @@ const FormNew = ( }, [searchParams, sParams]) useEffect(() => { - if (!formItems) { + initializedListFormCodeRef.current = undefined + }, [listFormCode]) + + useEffect(() => { + if (!formItems?.length || !gridDto?.columnFormats) { return } - // Sadece formData yoksa (ilk yüklemede) initial data oluştur - // Kullanıcının girdiği bilgileri korumak için mevcut formData varsa setleme - if (!formData) { - setFormData(createInitialFormData()) + if (initializedListFormCodeRef.current === listFormCode) { + return } - }, [formItems]) + + initializedListFormCodeRef.current = listFormCode + let isActive = true + + const initializeFormData = async () => { + const initialFormData = await createInitialFormData() + if (isActive) { + setFormData(initialFormData) + } + } + + initializeFormData() + + return () => { + isActive = false + } + }, [listFormCode, formItems?.length, gridDto?.columnFormats]) // newParams değiştiğinde sadece newParams'tan gelen alanları güncelle useEffect(() => { @@ -146,7 +168,7 @@ const FormNew = ( } }, [formItems, newParams, gridDto?.columnFormats]) - function createInitialFormData() { + async function createInitialFormData() { const data: any = {} if (!formItems?.length) { return data @@ -173,7 +195,29 @@ const FormNew = ( continue } - if (colFormat.defaultValue != null) { + if (colFormat.defaultValue !== null && colFormat.defaultValue !== undefined) { + if ( + typeof colFormat.defaultValue === 'string' && + colFormat.defaultValue === '@AUTONUMBER' + ) { + data[colFormat.fieldName] = autoNumber() + continue + } + + if (colFormat.defaultValueType === FieldCustomValueTypeEnum.Sequence) { + try { + const response = await getNextSequenceValue(String(colFormat.defaultValue)) + data[colFormat.fieldName] = response.data + } catch (error) { + console.error('Sequence default value alınamadı:', { + fieldName: colFormat.fieldName, + defaultValue: colFormat.defaultValue, + error, + }) + } + continue + } + data[colFormat.fieldName] = colFormat.defaultValue } }