Skip to content

Commit 520adc1

Browse files
committed
fix(nest-formBind): rerender only once
1 parent dad36cc commit 520adc1

File tree

8 files changed

+58
-49
lines changed

8 files changed

+58
-49
lines changed

examples/simple-form/src/layouts/Layout.astro

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ interface Props {
66
}
77
88
const { title } = Astro.props;
9+
10+
export const astroFiles = import.meta.glob('../pages/*.astro', { eager: true });
911
---
1012

1113
<!doctype html>
@@ -19,6 +21,9 @@ const { title } = Astro.props;
1921
<title>{title}</title>
2022
</head>
2123
<body>
24+
<div class="menu">
25+
{Object.values(astroFiles).map((x: any) => <a href={x.url}>{x.url.slice(1)}</a>)}
26+
</div>
2227
<WebForms>
2328
<slot />
2429
</WebForms>
@@ -28,4 +33,12 @@ const { title } = Astro.props;
2833
html {
2934
background: aliceblue;
3035
}
36+
37+
.menu {
38+
display: flex;
39+
flex-wrap: wrap;
40+
gap:20px;
41+
justify-content: center;
42+
padding: 40px 0;
43+
}
3144
</style>

examples/simple-form/src/pages/counter.astro

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
import { BButton, BindForm } from "@astro-utils/forms/forms.js";
2+
import { BButton, Bind, BindForm } from "@astro-utils/forms/forms.js";
33
import { Button } from 'reactstrap';
44
import Layout from "../layouts/Layout.astro";
55
@@ -15,4 +15,4 @@ function increaseCounter() {
1515
<BButton as={Button} props={{color: 'info'}} onClick={increaseCounter}>++</BButton>
1616
{session.counter}
1717
</BindForm>
18-
<Layout/>
18+
</Layout>

examples/simple-form/src/pages/default-submit.astro

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,16 @@ import Layout from '../layouts/Layout.astro';
44
55
const bind = Bind();
66
7+
let message = '';
78
function handleSubmit() {
89
console.log(bind);
10+
message = 'Default submit works!';
911
}
1012
---
1113

1214
<Layout title='forms'>
1315
<BindForm bind={bind}>
16+
<p>{message}</p>
1417
<BInput type='text' name='query' placeholder='Enter text'/>
1518
<BInput type='text' name='query2' placeholder='Input 2'/>
1619
<BButton onClick={() => console.log('Do nothing')}>Do noting</BButton>

examples/simple-form/src/pages/multi-forms.astro

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@
22
import { BButton, BInput, Bind, BindForm } from '@astro-utils/forms/forms.js';
33
import Layout from '../layouts/Layout.astro';
44
5-
const bind1 = Bind({bind: 1, num: 1});
6-
const bind2 = Bind({bind: 2, num: 2});
5+
const bind1 = Bind({ bind: 1, num: 1 });
6+
const bind2 = Bind({ bind: 2, num: 2 });
77
8-
function submit(){
8+
function submit() {
99
this.extra.num++;
10-
this.style = `background-color: #${Math.floor(Math.random()*16777215).toString(16)}`
10+
this.style = `background-color: #${Math.floor(Math.random() * 16777215).toString(16)}`;
11+
12+
console.log(this.extra.bind);
1113
}
1214
---
1315

@@ -18,7 +20,9 @@ function submit(){
1820

1921
<BindForm bind={bind2}>
2022
<BInput type='int' name='num' />
21-
<BButton onClick={submit} extra={bind2}>Increase</BButton>
23+
<BButton onClick={submit} extra={bind2}>
24+
Increase
25+
</BButton>
2226
</BindForm>
2327
</BindForm>
2428
</Layout>

packages/forms/src/components-control/props-utils.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
/**
22
* Returns the difference between two objects
33
*/
4-
export function diffProps(object1: any, object2: any) {
4+
export function diffProps(object1: any, object2: any, skipKeys: string[] = []) {
55
const diff = {};
66
for (const [key, value] of Object.entries(object2)) {
7+
if(skipKeys.includes(key)) continue;
78
if (JSON.stringify(object1[key]) !== JSON.stringify(value)) {
89
diff[key] = value;
910
}

packages/forms/src/components/WebForms.astro

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,7 @@ const context = {
1010
webFormsSettings: { haveFileUpload: false },
1111
tempValues: {},
1212
viewStates: {
13-
counterHash: new Map<any, number>(),
14-
lastCounter: 0,
15-
incCounter(ref: any){
16-
const haveCounter = context.viewStates.counterHash.get(ref);
17-
if(haveCounter) {
18-
return haveCounter;
19-
}
20-
21-
context.viewStates.counterHash.set(ref, context.viewStates.lastCounter);
22-
return context.viewStates.lastCounter++;
23-
}
13+
counter: 0,
2414
},
2515
};
2616

packages/forms/src/components/form/BButton.astro

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ export interface Props<T extends keyof JSX.IntrinsicElements | React.JSXElementC
1515
}
1616
1717
const {as: asComponent = 'button', props: componentProps, onClick, whenFormOK, connectId, ...props} = Astro.props;
18+
componentProps && Object.assign(props, componentProps);
19+
1820
const {bind, executeAfter, elementsState, tempValues, tempBindValues, method, buttonIds, settings, bindCounter = ''} = getContext(Astro, '@astro-utils/forms');
1921
const tempCounter = tempBindValues || tempValues;
2022
const elementPropsState = elementsState || tempValues;
@@ -28,7 +30,7 @@ if (!connectId) {
2830
buttonUniqueId = `${bindCounter + idBaseFunction}-${counter}`;
2931
}
3032
31-
const allProps = {...props, ...componentProps, ...elementPropsState[buttonUniqueId]};
33+
const allProps = {...props, ...elementPropsState[buttonUniqueId]};
3234
3335
// add this button to list of button for the default submit action
3436
if(buttonIds && !allProps.disabled) {
@@ -44,15 +46,13 @@ async function executeFormAction(callback: Function = onClick) {
4446
4547
const checkFormValidation = (whenFormOK && !bind?.errors.length) || !whenFormOK;
4648
if (checkFormValidation && validAction) {
47-
const copyProps = structuredClone({...props, ...componentProps});
48-
copyProps.extra = props.extra;
49+
const originalProps = structuredClone(props);
4950
50-
if(!copyProps.disabled){
51-
await callback.call(copyProps);
51+
if(!allProps.disabled){
52+
await callback.call(allProps);
5253
}
53-
delete copyProps.extra;
54-
55-
elementPropsState[buttonUniqueId] = diffProps(allProps, copyProps);
54+
55+
elementPropsState[buttonUniqueId] = diffProps(originalProps, allProps, ["extra"]);
5656
}
5757
}
5858
@@ -67,7 +67,7 @@ if (executeAfter) {
6767
6868
const {innerText, innerHTML, remove: doNotWriteHTML, ...changedProps}: any = allProps;
6969
delete changedProps.extra;
70-
delete changedProps.state;
70+
delete changedProps.state;
7171
7272
const Component = asComponent as any;
7373
const slotData = innerHTML ?? (Astro.slots.has('default') ? await Astro.slots.render('default') : '');

packages/forms/src/components/form/BindForm.astro

Lines changed: 19 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,11 @@ export interface Props {
1111
defaultSubmitClick?: string | false;
1212
}
1313
14-
const { viewStates, bindCounter: parantBindCounter = '' } = getContext(Astro, '@astro-utils/forms');
14+
const { viewStates, lastRender: parantLastRender, bindCounter: parantBindCounter = '' } = getContext(Astro, '@astro-utils/forms');
15+
if(parantLastRender === false) {
16+
return;
17+
}
18+
1519
const { bind = Bind(), defaultSubmitClick } = Astro.props;
1620
const context = {
1721
executeAfter: [],
@@ -21,54 +25,48 @@ const context = {
2125
elementsState: {} as any,
2226
onSubmitClickGlobal: defaultSubmitClick,
2327
buttonIds: [] as [string, string | null, boolean][],
24-
settings: {showValidationErrors: false},
25-
bindCounter: viewStates.incCounter(bind)
28+
settings: { showValidationErrors: false},
29+
bindCounter: viewStates.counter++,
30+
lastRender: false
2631
};
2732
2833
const viewState = new ViewStateManager(bind, context.elementsState, Astro, context.bindCounter);
2934
const haveState = await viewState.loadState();
30-
3135
await bind.on.stateLoaded?.();
32-
3336
if (!haveState) {
3437
await bind.on.newState?.();
3538
} else {
3639
await bind.on.pagePostBack?.();
3740
}
3841
3942
// Get information about the form
40-
await asyncContext(() => Astro.slots.render('default'), Astro, { name: '@astro-utils/forms', context, lock: 'bindForm' + parantBindCounter });
41-
42-
// resert the form execution
43-
context.tempBindValues = {};
44-
context.executeAfter = [];
45-
46-
// first 'GET' render
4743
context.method = Astro.request.method;
48-
let htmlSolt = await asyncContext(() => Astro.slots.render('default'), Astro, { name: '@astro-utils/forms', context, lock: 'bindForm' + parantBindCounter });
44+
await asyncContext(() => Astro.slots.render('default'), Astro, { name: '@astro-utils/forms', context, lock: 'bindForm' + parantBindCounter });
4945
bind.__finishFormValidation();
5046
51-
for (const func of context.executeAfter) {
52-
await (func as any)();
53-
}
54-
5547
if (context.method == 'POST') {
48+
for (const func of context.executeAfter) {
49+
await (func as any)();
50+
}
51+
5652
context.method = 'GET';
5753
context.tempBindValues = {};
58-
htmlSolt = await asyncContext(() => Astro.slots.render('default'), Astro, { name: '@astro-utils/forms', context, lock: 'bindForm' + parantBindCounter });
54+
context.buttonIds = [];
55+
await asyncContext(() => Astro.slots.render('default'), Astro, { name: '@astro-utils/forms', context, lock: 'bindForm' + parantBindCounter });
5956
}
6057
6158
// Edit form render, add default submit button
6259
if (context.onSubmitClickGlobal == null && context.buttonIds.length > 0) {
63-
const [buttonFormId, HTMLButtonId] = context.buttonIds.findLast(([,,whenFormOk]) => whenFormOk) ?? context.buttonIds.at(-1)!;
60+
const [buttonFormId, HTMLButtonId] = context.buttonIds.findLast(([, , whenFormOk]) => whenFormOk) ?? context.buttonIds.at(-1)!;
6461
const state = (context.elementsState[buttonFormId] ??= {});
6562
6663
state.id = HTMLButtonId ?? `_${buttonFormId}`;
6764
context.onSubmitClickGlobal = state.id;
68-
6965
context.tempBindValues = {};
70-
htmlSolt = await asyncContext(() => Astro.slots.render('default'), Astro, { name: '@astro-utils/forms', context, lock: 'bindForm' + parantBindCounter });
7166
}
67+
68+
context.lastRender = true;
69+
const htmlSolt = await asyncContext(() => Astro.slots.render('default'), Astro, { name: '@astro-utils/forms', context, lock: 'bindForm' + parantBindCounter });
7270
---
7371

7472
{viewState.useState ? <input type='hidden' name={viewState.filedName} value={await viewState.createViewState()} /> : null}

0 commit comments

Comments
 (0)