For the following:
<ArrayInput source="slotCaps" label="Schedule Caps">
<SimpleFormIterator>
<Box display="flex">
<Box mr="0.5em">
<NumberInput source="cap" step={1}/>
</Box>
<Box ml="0.5em">
<SelectInput
source="period"
choices={[
{id: "0", name: "Day"},
{id: "1", name: "Week"},
{id: "2", name: "Month"}
]}
/>
</Box>
</Box>
</SimpleFormIterator>
</ArrayInput>
I get:
{
"name": "test 5",
"description": "test 5",
"slotCaps": [
{},
{}
],
"cap": 1,
"period": "0"
}
I was expecting:
{
"name": "test 5",
"description": "test 5",
"slotCaps": [
{"cap": 1, "period": "0"},
],
}
Any idea what I am doing wrong? Could someone please explain what I have to change to obtain the second variant?
Thank you.
Edit
Not sure why but for some reason this works:
<ArrayInput source="slotCaps" label="Schedule Caps">
<SimpleFormIterator>
<NumberInput source="cap" step={1}/>
<SelectInput
source="period"
choices={[
{id: 1, name: "Day"},
{id: 2, name: "Week"},
{id: 3, name: "Month"}
]}
optionValue={"name"}
/>
</SimpleFormIterator>
</ArrayInput>
If anyone knows how to make the first variant work please provide your input. I need the fields to be formatted properly and it looks like using the Box element is the best way to achieve that.
Thank you.
Input components must be the first-level children of SimpleFormIterator, not nested ones.
If you wish to use nested Input components, which is useful for displaying the form properly with material-ui Box elements, you need to use a FormDataConsumer, like below:
<ArrayInput source="slotCaps" label="Schedule Caps">
<SimpleFormIterator>
<FormDataConsumer>
{({ getSource, scopedFormData }) => {
return (
<Box display="flex">
<Box mr="0.5em">
<NumberInput
source={getSource("cap")}
record={scopedFormData}
step={1}
/>
</Box>
<Box ml="0.5em">
<SelectInput
source={getSource("period")}
record={scopedFormData}
choices={[
{ id: "0", name: "Day" },
{ id: "1", name: "Week" },
{ id: "2", name: "Month" },
]}
/>
</Box>
</Box>
);
}}
</FormDataConsumer>
</SimpleFormIterator>
</ArrayInput>
Then, for each Input component, all you need to do is add getSource in the source prop and scopedFormData to the record prop.
remove source from NumberInput and SelectInput
Related
I have 1 check box group and 9 radio button groups, and i need v-model for each group but i do not know how to put 9 differed data properties there.
My data looks like this:
data() {
return{
servicesId: [],
personId: '',
incomeId:'',
extraIncomeId: '',
pdvId: '',
paymentId: '',
clientId: '',
cashRegisterId: '',
eBankingId: '',
}
}
In template is like this:
<div v-for="data in formData" :key="data.id">
<h5>{{data.question_text}}</h5>
<div class="form-check" v-for="text_o in data.question_options" :key="text_o.id">
<input class="form-check-input"
:type="data.question_type.type"
:value="text_o.id" :id="text_o.id"
v-model="[HERE GOES "9 "data props"]">
<label class="form-check-label" :key="text_o.id" :for="text_o.id"> {{text_o.option_text}
</label>
</div>
</div>
Here is part of (because it is long, i can post everything from it if you want)formData array:
{
"id": 1,
"question_type_id": 1,
"title": "new ent",
"question_text": "Planirate da se bavite:",
"created_at": "2021-10-12T13:42:17.000000Z",
"updated_at": "2021-10-12T13:42:17.000000Z",
"question_options": [
{
"id": 1,
"question_id": 1,
"option_text": "Uslugama",
"price": 40,
"created_at": "2021-10-12T13:44:40.000000Z",
"updated_at": "2021-10-12T13:44:40.000000Z"
},
{
"id": 2,
"question_id": 1,
"option_text": "Trgovinom",
"price": 60,
"created_at": "2021-10-12T13:46:53.000000Z",
"updated_at": "2021-10-12T13:46:53.000000Z"
},
{
"id": 3,
"question_id": 1,
"option_text": "Proizvodnjom",
"price": 80,
"created_at": "2021-10-12T13:47:22.000000Z",
"updated_at": "2021-10-12T13:47:22.000000Z"
}
],
"question_type": {
"id": 1,
"type": "checkbox",
"created_at": "2021-10-12T13:40:17.000000Z",
"updated_at": "2021-10-12T13:40:17.000000Z"
}
}
Thanks.
If you want your values to be a part of data, you can create an object that will contain your form data, like this:
data() {
return {
formValue: {
servicesId: [],
personId: "",
incomeId: "",
extraIncomeId: "",
pdvId: "",
paymentId: "",
clientId: "",
cashRegisterId: "",
eBankingId: "",
},
}
}
after adding that object, just add a name to your form data object like this:
formData: [
{
id: 1,
question_type_id: 1,
title: "new ent",
question_text: "Planirate da se bavite:",
created_at: "2021-10-12T13:42:17.000000Z",
updated_at: "2021-10-12T13:42:17.000000Z",
name: "servicesId", <-- modified part
question_options: [...]
}
]
and now you can use that name to dynamically access your formValue object which is a part of data:
<div v-for="data in formData" :key="data.id">
<h5>{{ data.question_text }}</h5>
<div
class="form-check"
v-for="text_o in data.question_options"
:key="text_o.id"
>
<input
class="form-check-input"
:type="data.question_type.type"
:value="text_o.id"
:id="text_o.id"
v-model="formValue[data.name]" <-- modified part
/>
<label class="form-check-label" :key="text_o.id" :for="text_o.id">
{{ text_o.option_text }}
</label>
</div>
</div>
Hope this approach helps you, you will have your values in data, they won't be there as separate properties, but they will be a part of a wrapper object named formValue
I have form fn
code here
#update code. I initialization
query = {
field: '',
email: '',
}
not initialization url
export function HomePage() {
const [query, setQuery] = useState({
field: '',
email: '',
});
const handleChaneValue = (value) => {
// not received data on change
console.log('query', query);
setQuery({
...query,
[value.sender.name]: value.newValue
})
}
console.log('query2', query);
query2 received data on change
console.log('query2', query);
#Update code: I add
return (
<div>
<Container
padding={10}
platformConfig={{
desktop: {
maxWidth: 400,
}
}}
>
<FormPanel
padding={10}
shadow
defaults={{
errorTarget: 'under'
}}
margin="0 0 20 0"
title="Using Validators"
>
<Textfield
required
label="Required Field"
requiredMessage="This field is required."
errorTarget="under"
name="field"
onChange={handleChaneValue}
/>
<EmailField
label="Email"
validators="email"
errorTarget="under"
name="email"
onChange={(e) => handleChaneValue(e)}
/>
<Urlfield
label="URL"
validators={{
type: 'url',
message: 'Website url example http://'
}}
errorTarget="under"
name="url"
onChange={handleChaneValue}
/>
<Container layout="center">
<Button
ui="confirm"
text="BTN submit"
handler={handleClick}
style={{border: '1px solid black' }}/>
</Container>
</FormPanel>
</Container>
</div>
)
}
export default HomePage;
When I change value in TextField. Query is
query2: {field: 'abc'}
But i change value in Email field. Query is not give old value "{filed: 'abc'}" throught I use ES6 three dot.
query2 : {email: 'xyz'}
and Query in funciton always initialization
query: {}
image change value
#Update image: when I change value Url. fn handleChangeValue get initialization query
query: {
field: '',
email: '',
}
does not value query updated.
here issues were you did not initialize the value of textfield and emailfield I updated code pls check now
export function HomePage() {
const [query, setQuery] = useState({
field:'',
email:''
});
const handleChaneValue = (value) => {
// not received data on change
console.log("query", query);
setQuery({
...query,
[value.sender.name]: value.newValue,
});
};
console.log("query2", query);
return (
<div>
<Container
padding={10}
platformConfig={{
desktop: {
maxWidth: 400,
},
}}
>
<FormPanel
padding={10}
shadow
defaults={{
errorTarget: "under",
}}
margin="0 0 20 0"
title="Using Validators"
>
<Textfield
required
label="Required Field"
requiredMessage="This field is required."
errorTarget="under"
name="field"
onChange={handleChaneValue}
value={query.field}
/>
<EmailField
label="Email"
validators="email"
errorTarget="under"
name="email"
value={query.email}
onChange={handleChaneValue}
/>
<Container layout="center">
<Button
ui="confirm"
text="BTN submit"
handler={handleClick}
style={{ border: "1px solid black" }}
/>
</Container>
</FormPanel>
</Container>
</div>
);
}
export default HomePage;
I found the solution to the problem. I using framework ExtReact so when run function, states re-initialized initil value. To solve this problem you can useRef and refer here.
enter link description here
How can i count and output the length of an array field as a textfield or numberfield?
Code of the ArrayField that works and outputs a DataGrid
<ArrayField source="re_benutzers">
<Datagrid>
<TextField source="vorname" />
</Datagrid>
</ArrayField>
Source: (from Strapi)
{
"id": 5,
"name": "sdf",
"re_benutzers": [{
"id": 1,
"vorname": "Something",
},
^this can hold multiple entries and i want to output the count.
I think you can use a custom component for that instead of the DataGrid.
ArrayField will inject all ids retrieved in a list context.
So you can do something like:
const LengthField = (props) => {
const { ids, loaded } = useListContext(props);
return loaded ? ids.length : null;
};
// And then
<ArrayField source="re_benutzers">
<LengthField />
</ArrayField>
You can do this using the FunctionField component:
https://marmelab.com/react-admin/Fields.html#functionfield:
<FunctionField label="Count" render={record => `${record?.re_benutzers?.length ?? ""}`} />
I am new to react and trying to display nested json object. I want to iterate "hookah_tobacco" nested object and display tobacco types.
Json part:
{
"id": 1,
"hookah_name": "Smoke city",
"city": 131,
"street": "Osinnya, 33",
"website": "",
"phone": "0672222222",
"description": "Cool bar.",
"credit_card": true,
"hookah_type": [],
"hookah_tobacco": [
{
"hookah_tobacco": "Al-Fakher"
},
{
"hookah_tobacco": "Serbetli"
}
],
"summer_terrace": false,
"hookah_images": [
{
"id": 1,
"hookah_image": "http://127.0.0.1:8000/hookahImages/O4P02PtmT22nv8LwB85KDw-752x440.jpg"
},
{
"id": 2,
"hookah_image": "http://127.0.0.1:8000/hookahImages/kalyannaya-zmist-kiev-vxod-pushkinskoy-1024x768.jpeg"
}
]
}
React part:
class HookahDetail extends Component{
render(){
const obj = this.props.hookahDetail;
return(
// TODO move style to css
<div style = {{ color: "yellow", border: "1px solid yellow" }}>
<h4>{obj.hookah_name}</h4>
<h5>
<p>{obj.city}</p>
{obj.street}
<p>{obj.hookah_style}</p>
<p>{obj.phone}</p>
Tobacco:
<div>
</div>
<p>{obj.description}</p>
<p>{obj.credit_card}</p>
<p>{obj.summer_terrace}</p>
<div>
{/* here is some mistake */}
{obj.hookah_tobacco.map((t) => {
return (
<div>{t.hookah_tobacco}</div>
)
})}
</div>
</h5>
</div>
)
}
}
Error part:
TypeError: obj.hookah_tobacco is undefined
Console log part when {console.log(obj.hookah_tobacco)}():
0: Object { hookah_tobacco: "Al-Fakher" }
1: Object { hookah_tobacco: "Serbetli" }
I can't understand why map() function does not work.
Try to use it like this. This way can handle the undefined error
...
{obj.hookah_tobacco ? obj.hookah_tobacco.map((t) => {
return (
<div>{t.hookah_tobacco}</div>
)
}) : null}
I have an object that is being passed to the child component and I want to display those values in the child component template. However, the object contains properties that are arrays and objects so I need to do some parsing/manipulation on them before I set the value.
object:
{
"id": "111",
"ip": "10.192.1.112",
"profiles": [
"Japan",
"Japan222"
],
"network": [
{
"plan_id": "PLAN-UUID",
"plan_name": "1BCT"
},
{
"plan_id": "PLAN-UUID",
"plan_name": "1BCT2"
}
],
"status": "LOCKED",
"last_downloaded": "1547672769000"
}
template code in child:
<label label="id" :value=this.objectFromParent.id />
<label label="ip" :value=this.objectFromParent.ip />
<label label="ip" :value= calculateProfiles />
where calculateProfiles is the method to calculate it and return the string value? I'm not sure what's a good way to handle this.
Try this
<template>
<div>
<label label="id" :value="objectFromParent.id" />
<label label="ip" :value="objectFromParent.ip" />
<label label="ip" :value="calculateProfiles" />
</div>
</template>
<script>
export default {
props: {
objectFromParent: {
type: Object,
default() {
return {
id: '111',
ip: '10.192.1.112',
profiles: ['Japan', 'Japan222'],
network: [
{
plan_id: 'PLAN-UUID',
plan_name: '1BCT'
},
{
plan_id: 'PLAN-UUID',
plan_name: '1BCT2'
}
],
status: 'LOCKED',
last_downloaded: '1547672769000'
}
}
}
},
computed: {
calculateProfiles() {
return this.profiles.join(',')
}
}
}
</script>
To help him on the comment:
<label label="ip">
<md-icon v-if="objectFromParent.status==='LOCKED'">lock</md-icon>
{{calculateProfiles}}
</label>