Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -83,13 +83,16 @@ const DropdownTmpComp = (function () {
key: option.label + " - " + index,
disabled: option.disabled,
icon: hasIcon && <span>{option.prefixIcon}</span>,
onEvent: option.onEvent,
index,
}));

const menu = (
<Menu
items={items}
onClick={({ key }) => items.find((o) => o.key === key)?.onEvent("click")}
onClick={({ key }) => {
const item = items.find((o) => o.key === key);
item && props.options[item.index]?.onEvent("click");
}}
/>
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,10 @@ export function ListView(props: Props) {
return <div key={itemIdx} style={{ flex: "auto" }}></div>;
}
const containerProps = containerFn(
{ [itemIndexName]: itemIdx, [itemDataName]: getCurrentItemParams(data, itemIdx) },
{
[itemIndexName]: itemIdx,
[itemDataName]: getCurrentItemParams(data, itemIdx)
},
String(itemIdx)
).getView();
const unMountFn = () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
} from "comps/controls/codeControl";
import { styleControl } from "comps/controls/styleControl";
import { ListViewStyle } from "comps/controls/styleControlConstants";
import { UICompBuilder, withDefault, withPropertyViewFn, withViewFn } from "comps/generators";
import { UICompBuilder, stateComp, valueComp, withDefault, withPropertyViewFn, withViewFn } from "comps/generators";
import {
CompDepsConfig,
depsConfig,
Expand Down Expand Up @@ -37,6 +37,7 @@ import { ContextContainerComp } from "./contextContainerComp";
import { ListView } from "./listView";
import { listPropertyView } from "./listViewPropertyView";
import { getData } from "./listViewUtils";
import { withMethodExposing } from "comps/generators/withMethodExposing";

const childrenMap = {
noOfRows: withIsLoadingMethod(NumberOrJSONObjectArrayControl), // FIXME: migrate "noOfRows" to "data"
Expand Down Expand Up @@ -80,10 +81,10 @@ export class ListViewImplComp extends ListViewTmpComp implements IContainer {
}
override reduce(action: CompAction): this {
// console.info("listView reduce. action: ", action);

let comp = reduceInContext({ inEventContext: true }, () => super.reduce(action));

if (action.type === CompActionTypes.UPDATE_NODES_V2) {
const { itemCount } = getData(comp.children.noOfRows.getView());
const { itemCount} = getData(comp.children.noOfRows.getView());
const pagination = comp.children.pagination.getView();
const total = pagination.total || itemCount;
const offset = (pagination.current - 1) * pagination.pageSize;
Expand Down Expand Up @@ -151,11 +152,11 @@ export class ListViewImplComp extends ListViewTmpComp implements IContainer {

const ListViewRenderComp = withViewFn(ListViewImplComp, (comp) => <ListView comp={comp} />);
const ListPropertyView = listPropertyView("listView");
const ListViewPropertyComp = withPropertyViewFn(ListViewRenderComp, (comp) => {
let ListViewPropertyComp = withPropertyViewFn(ListViewRenderComp, (comp) => {
return <ListPropertyView comp={comp} />;
});

export const ListViewComp = withExposingConfigs(ListViewPropertyComp, [
ListViewPropertyComp = withExposingConfigs(ListViewPropertyComp, [
new CompDepsConfig(
"items",
(comp) => ({ data: comp.itemsNode() }),
Expand All @@ -171,9 +172,31 @@ export const ListViewComp = withExposingConfigs(ListViewPropertyComp, [
return data;
},
}),
// new CompDepsConfig(
// "index",
// (comp) => ({index: comp.children.itemIndexName.node() }),
// (input) => input.index.value,
// "index", // trans("listView.itemsDesc")
// ),
NameConfigHidden,
]);

export const ListViewComp = withMethodExposing(ListViewPropertyComp, [
{
method: {
name: "setPage",
description: "",
params: [{ name: "page", type: "number" }],
},
execute: (comp, values) => {
const page = values[0] as number;
if (page && page > 0) {
comp.children.pagination.children.pageNo.dispatchChangeValueAction(page);
}
},
},
])

export function defaultListViewData(compName: string, nameGenerator: NameGenerator) {
return {
noOfRows:
Expand Down Expand Up @@ -232,7 +255,7 @@ export function defaultListViewData(compName: string, nameGenerator: NameGenerat
compType: "rating",
name: nameGenerator.genItemName("rating"),
comp: {
value: "{{currentItem.rate / 2}}",
defaultValue: "{{currentItem.rate / 2}}",
max: "5",
label: {
text: "",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
import { BoolControl } from "comps/controls/boolControl";
import { dropdownControl } from "comps/controls/dropdownControl";
import { LabelControl } from "comps/controls/labelControl";
import { numberExposingStateControl } from "comps/controls/codeStateControl";
import { numberExposingStateControl, stringExposingStateControl } from "comps/controls/codeStateControl";
import NP from "number-precision";

import {
Expand Down Expand Up @@ -234,6 +234,7 @@ const UndefinedNumberControl = codeControl<number | undefined>((value: any) => {
});

const childrenMap = {
defaultValue: stringExposingStateControl("defaultValue"), // It is more convenient for string to handle various states, save raw input here
value: numberExposingStateControl("value"), // It is more convenient for string to handle various states, save raw input here
placeholder: StringControl,
disabled: BoolCodeControl,
Expand Down Expand Up @@ -261,6 +262,17 @@ const childrenMap = {

const CustomInputNumber = (props: RecordConstructorToView<typeof childrenMap>) => {
const ref = useRef<HTMLInputElement | null>(null);
const defaultValue = props.defaultValue.value;

useEffect(() => {
let value = 0;
if (defaultValue === 'null' && props.allowNull) {
value = NaN;
} else if (!isNaN(Number(defaultValue))) {
value = Number(defaultValue);
}
props.value.onChange(value);
}, [defaultValue]);

const formatFn = (value: number) =>
format(value, props.allowNull, props.formatter, props.precision, props.thousandsSeparator);
Expand All @@ -271,7 +283,9 @@ const CustomInputNumber = (props: RecordConstructorToView<typeof childrenMap>) =
const oldValue = props.value.value;
const newValue = parseNumber(tmpValue, props.allowNull);
props.value.onChange(newValue);
oldValue !== newValue && props.onEvent("change");
if((oldValue !== newValue)) {
props.onEvent("change");
}
};

useEffect(() => {
Expand Down Expand Up @@ -363,7 +377,7 @@ const NumberInputTmpComp = (function () {
.setPropertyViewFn((children) => (
<>
<Section name={sectionNames.basic}>
{children.value.propertyView({ label: trans("prop.defaultValue") })}
{children.defaultValue.propertyView({ label: trans("prop.defaultValue") })}
{placeholderPropertyView(children)}
{children.formatter.propertyView({ label: trans("numberInput.formatter") })}
</Section>
Expand Down
22 changes: 19 additions & 3 deletions client/packages/lowcoder/src/comps/comps/ratingComp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { migrateOldData } from "comps/generators/simpleGenerators";
import { disabledPropertyView, hiddenPropertyView } from "comps/utils/propertyUtils";
import { trans } from "i18n";

import { useContext } from "react";
import { useContext, useEffect, useRef } from "react";
import { EditorContext } from "comps/editorState";

const EventOptions = [changeEvent] as const;
Expand All @@ -36,6 +36,7 @@ function fixOldData(oldData: any) {

const RatingBasicComp = (function () {
const childrenMap = {
defaultValue: numberExposingStateControl("defaultValue"),
value: numberExposingStateControl("value"),
max: withDefault(NumberControl, "5"),
label: LabelControl,
Expand All @@ -46,6 +47,21 @@ const RatingBasicComp = (function () {
...formDataChildren,
};
return new UICompBuilder(childrenMap, (props) => {
const defaultValue = { ...props.defaultValue }.value;
const value = { ...props.value }.value;
const changeRef = useRef(false)

useEffect(() => {
props.value.onChange(defaultValue);
}, [defaultValue]);

useEffect(() => {
if (!changeRef.current) return;

props.onEvent("change");
changeRef.current = false;
}, [value]);

return props.label({
style: props.style,
children: (
Expand All @@ -54,7 +70,7 @@ const RatingBasicComp = (function () {
value={props.value.value}
onChange={(e) => {
props.value.onChange(e);
props.onEvent("change");
changeRef.current = true;
}}
allowHalf={props.allowHalf}
disabled={props.disabled}
Expand All @@ -67,7 +83,7 @@ const RatingBasicComp = (function () {
return (
<>
<Section name={sectionNames.basic}>
{children.value.propertyView({ label: trans("prop.defaultValue") })}
{children.defaultValue.propertyView({ label: trans("prop.defaultValue") })}
{children.max.propertyView({
label: trans("rating.max"),
})}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,8 @@ const CheckboxGroup = styled(AntdCheckboxGroup)<{

const CheckboxBasicComp = (function () {
const childrenMap = {
value: arrayStringExposingStateControl("value", ["1"]),
defaultValue: arrayStringExposingStateControl("defaultValue"),
value: arrayStringExposingStateControl("value"),
label: LabelControl,
disabled: BoolCodeControl,
onEvent: ChangeEventHandlerControl,
Expand All @@ -115,7 +116,10 @@ const CheckboxBasicComp = (function () {
...formDataChildren,
};
return new UICompBuilder(childrenMap, (props) => {
const [validateState, handleValidate] = useSelectInputValidate(props);
const [
validateState,
handleChange,
] = useSelectInputValidate(props);
return props.label({
required: props.required,
style: props.style,
Expand All @@ -134,9 +138,7 @@ const CheckboxBasicComp = (function () {
disabled: option.disabled,
}))}
onChange={(values) => {
handleValidate(values as string[]);
props.value.onChange(values as string[]);
props.onEvent("change");
handleChange(values as string[]);
}}
/>
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,24 @@ import { SelectInputInvalidConfig, useSelectInputValidate } from "./selectInputC

import { PaddingControl } from "../../controls/paddingControl";
import { MarginControl } from "../../controls/marginControl";
import { useEffect, useRef } from "react";

const MultiSelectBasicComp = (function () {
const childrenMap = {
...SelectChildrenMap,
value: arrayStringExposingStateControl("value", ["1", "2"]),
defaultValue: arrayStringExposingStateControl("defaultValue", ["1", "2"]),
value: arrayStringExposingStateControl("value"),
style: styleControl(MultiSelectStyle),
margin: MarginControl,
padding: PaddingControl,
};
return new UICompBuilder(childrenMap, (props, dispatch) => {
const valueSet = new Set<any>(props.options.map((o) => o.value)); // Filter illegal default values entered by the user
const [validateState, handleValidate] = useSelectInputValidate(props);
const [
validateState,
handleChange,
] = useSelectInputValidate(props);

return props.label({
required: props.required,
style: props.style,
Expand All @@ -34,11 +40,7 @@ const MultiSelectBasicComp = (function () {
{...props}
mode={"multiple"}
value={props.value.value.filter?.((v) => valueSet.has(v))}
onChange={(value) => {
handleValidate(value);
props.value.onChange(value);
props.onEvent("change");
}}
onChange={handleChange}
dispatch={dispatch}
/>
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,10 @@ const Radio = styled(AntdRadioGroup)<{

const RadioBasicComp = (function () {
return new UICompBuilder(RadioChildrenMap, (props) => {
const [validateState, handleValidate] = useSelectInputValidate(props);
const [
validateState,
handleChange,
] = useSelectInputValidate(props);
return props.label({
required: props.required,
style: props.style,
Expand All @@ -95,9 +98,7 @@ const RadioBasicComp = (function () {
$style={props.style}
$layout={props.layout}
onChange={(e) => {
handleValidate(e.target.value);
props.value.onChange(e.target.value);
props.onEvent("change");
handleChange(e.target.value);
}}
options={props.options
.filter((option) => option.value !== undefined && !option.hidden)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export const RadioLayoutOptions = [
] as const;

export const RadioChildrenMap = {
defaultValue: stringExposingStateControl("value"),
value: stringExposingStateControl("value"),
label: LabelControl,
disabled: BoolCodeControl,
Expand All @@ -46,6 +47,9 @@ export const RadioChildrenMap = {
export const RadioPropertyView = (
children: RecordConstructorToComp<
typeof RadioChildrenMap & { hidden: typeof BoolCodeControl } & {
defaultValue:
| ReturnType<typeof stringExposingStateControl>
| ReturnType<typeof arrayStringExposingStateControl>;
value:
| ReturnType<typeof stringExposingStateControl>
| ReturnType<typeof arrayStringExposingStateControl>;
Expand All @@ -55,7 +59,7 @@ export const RadioPropertyView = (
<>
<Section name={sectionNames.basic}>
{children.options.propertyView({})}
{children.value.propertyView({ label: trans("prop.defaultValue") })}
{children.defaultValue.propertyView({ label: trans("prop.defaultValue") })}
</Section>

{["logic", "both"].includes(useContext(EditorContext).editorModeStatus) && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ const Segmented = styled(AntdSegmented)<{ $style: SegmentStyleType }>`
`;

const SegmentChildrenMap = {
defaultValue: stringExposingStateControl("value"),
value: stringExposingStateControl("value"),
label: LabelControl,
disabled: BoolCodeControl,
Expand All @@ -76,7 +77,11 @@ const SegmentChildrenMap = {

const SegmentedControlBasicComp = (function () {
return new UICompBuilder(SegmentChildrenMap, (props) => {
const [validateState, handleValidate] = useSelectInputValidate(props);
const [
validateState,
handleValidate,
handleChange,
] = useSelectInputValidate(props);
return props.label({
required: props.required,
style: props.style,
Expand All @@ -88,9 +93,7 @@ const SegmentedControlBasicComp = (function () {
value={props.value.value}
$style={props.style}
onChange={(value) => {
handleValidate(value.toString());
props.value.onChange(value.toString());
props.onEvent("change");
handleChange(value.toString());
}}
options={props.options
.filter((option) => option.value !== undefined && !option.hidden)
Expand All @@ -109,7 +112,7 @@ const SegmentedControlBasicComp = (function () {
<>
<Section name={sectionNames.basic}>
{children.options.propertyView({})}
{children.value.propertyView({ label: trans("prop.defaultValue") })}
{children.defaultValue.propertyView({ label: trans("prop.defaultValue") })}
</Section>

{["logic", "both"].includes(useContext(EditorContext).editorModeStatus) && (
Expand Down
Loading