How to render another List when rowClick show - react-admin

I was kind of dropped into a Project that uses react-admin and I am supposed to do the following ....
In App.js we have a Ressource products. Now I am supposed to add another Ressource Manufacturers, specifically for one Manufacturer, e.g. Example Manufacturer.
App.js
<Resource name="products" list={ProductsList} show={ProductsEdit} />
<Resource name="manufacturers/ExampleManufacturer/products" list={ManufacturerProductsList} />
So when I click on the Resource it opens the ManufacturerProductsList and fetches via getList from the API. The Data has the following format (basically)
data = [{id: '2020-01', count: 1}, {id: '2020-02', count: 5}]
So for every month it shows a count. Now when I click on a row, I want it to display a List of the selected month! From that List I want to be able to Select Items and use an Action, filter, or open the Product. This is where I am encountering my Problem.
I cannot figure out how to pass the Data to a List that does not end in an error of some kind.
I tried to write a CustomRoute, useListContext, RessourceContextProvider and more ...
My most recent (and most promising) Try is the following.
const { loading, total, data, error } = useQuery({
type: 'getList',
resource: 'manufacturers/ExampleManufacturer/products/2021-02',
payload: {
pagination: { page: 1, perPage: 10 },
sort: { field: 'id', order: 'ASC' },
filter: {}
}
});
if (loading) return <Loading />
if (error) return <p>Error: {error}</p>
return (
<ResourceContextProvider value="manufacturers">
<ListContextProvider value={{
basePath: '/manufacturers',
data: keyBy(data, 'id'),
ids: data.map(({ id }) => id),
currentSort: { field: 'id', order: 'ASC' },
selectedIds: []
}}>
<Datagrid rowClick="show">
<TextField source="id" />
<TextField source="type" />
</Datagrid>
<Pagination
page={1}
perPage={50}
setPage={(numb) => console.log(numb)}
total={total}
/>
</ListContextProvider>
</ResourceContextProvider>
);
The data receives the data and everything, but I get the following hard crash error.
Datagrid.js:79 Uncaught TypeError: Cannot read property 'field' of undefined
at Datagrid.js:79
at renderWithHooks (react-dom.development.js:14803)
at updateForwardRef (react-dom.development.js:16816)
at beginWork (react-dom.development.js:18645)
at HTMLUnknownElement.callCallback (react-dom.development.js:188)
at Object.invokeGuardedCallbackDev (react-dom.development.js:237)
at invokeGuardedCallback (react-dom.development.js:292)
at beginWork$1 (react-dom.development.js:23203)
at performUnitOfWork (react-dom.development.js:22154)
at workLoopSync (react-dom.development.js:22130)
at performSyncWorkOnRoot (react-dom.development.js:21756)
at react-dom.development.js:11089
at unstable_runWithPriority (scheduler.development.js:653)
at runWithPriority$1 (react-dom.development.js:11039)
at flushSyncCallbackQueueImpl (react-dom.development.js:11084)
at flushSyncCallbackQueue (react-dom.development.js:11072)
at scheduleUpdateOnFiber (react-dom.development.js:21199)
at dispatchAction (react-dom.development.js:15660)
at hooks.js:13
at useQuery.js:126

Related

Filter Vue list based on select option value

I try to filter my list with 2 select lists based on the selected value. It seems like my computed filter is not working?
You should be able to filter the list on 'Price from' and 'Price to'
List.vue
My computed filter property:
filteredData() {
const LowerCaseSearch = this.search.toLowerCase();
return this.products.filter(
product =>
(product.name.toLowerCase().includes(LowerCaseSearch) ||
product.category.toLowerCase().includes(LowerCaseSearch)) &&
(!this.checked.length || this.checked.includes(product.category)) &&
(!this.selectedFrom.length || this.selectedFrom.includes(product.price)) &&
(!this.selectedTo.length || this.selectedTo.includes(product.price))
);
},
In my registered component I use v-model to bind to the computed property selectedFrom
<Price v-model="selectedFrom" />
How do I bind to the other property selectedTo in one v-model and what's wrong with my filter?
I also use a prefix 'From' and 'To' to put in front of the options.
data: () => {
return {
selectedFrom: '0,00',
priceFrom: [
{ prefix: 'From', text: '0,00', value: '0,00' },
{ prefix: 'From', text: '200,00', value: '200,00' },
{ prefix: 'From', text: '400,00', value: '400,00' }
],
selectedTo: 'No max',
priceTo: [
{ prefix: 'To', text: '400,00', value: '400,00' },
{ prefix: 'To', text: '600,00', value: '600,00' },
{ prefix: 'To', text: '800,00', value: '800,00' },
{ text: 'No max', value: 'No max' }
]
}
},
Is there a more elegant and D.R.Y way to do this?
Here is a sandbox what I have so far.
You should bind an object to your v-model on the <price> component.
This way you can pass multiple values to and from your component, without having to use multiple props.
I would also suggest you convert your value in your selects to numbers, so it's easier to use them to compare to your prices.
You've also defined data properties and computed properties in the sandbox (<price> component) with the same name, this is not possible. So you should remove the data properties and stick to the computed ones to handle your data.
Fork of your sandbox with my suggested changes.

ReferenceArrayInput usage with relationships on React Admin

I have followed the doc for the ReferenceArrayInput (https://marmelab.com/react-admin/Inputs.html#common-input-props) but it does not seem to be working with relationship fields.
For example, I have this many-to-many relation for my Users (serialized version) :
Coming from (raw response from my API):
I have setup the ReferenceArrayInput as followed :
<ReferenceArrayInput source="profiles" reference="profiles" >
<SelectArrayInput optionText="label" />
</ReferenceArrayInput>
I think it's making the appropriate calls :
But here is my result :
Any idea what I'm doing wrong ?
Thanks in advance for your help !
On docs, ReferenceArrayInput is said to expect a source prop pointing to an array os ids, array of primitive types, and not array of objects with id. Looks like you are already transforming your raw response from api, so if you could transform a bit more, mapping [{id}] to [id], it could work.
If other parts of your app expects profiles to be an array of objects, just create a new object entry like profilesIds or _profiles.
As gstvg said, ReferenceArrayInput expects an array of primitive type, not array of objects.
If your current record is like below:
{
"id": 1,
"tags": [
{ id: 'programming', name: 'Programming' },
{ id: 'lifestyle', name: 'Lifestyle' }
]
}
And you have a resource /tags, which returns all tags like:
[
{ id: 'programming', name: 'Programming' },
{ id: 'lifestyle', name: 'Lifestyle' },
{ id: 'photography', name: 'Photography' }
]
Then you can do something like this (it will select the tags of current record)
<ReferenceArrayInput
reference="tags"
source="tags"
parse={(value) => value && value.map((v) => ({ id: v }))}
format={(value) => value && value.map((v) => v.id)}
>
<AutocompleteArrayInput />
</ReferenceArrayInput>

How to make a searchable droplist in react native to open an specific screen?

I'm trying to make a search bar with a list,dropdown list,
how to make a search list lik this code:
onPress={() =>this.props.navigation.navigate('LinhaDiurno03')
when an item is pressed?
....I want that each item in the list open a different screen in the application....
How can i to it?
here is the my teste:
Code to dropDown List
here some code:
var items = [
//name key is must.It is to show the text in front
{id: 1, name: 'ANA RECH', prestadora: 'UNIDOS', pos: 'P01'},
{id: 2, name: 'ARROIO DAS MARRECAS', prestadora: 'UNIDOS', pos: 'P01'},
{id: 3, name: 'VILA SECA', prestadora: 'UNIDOS', pos: 'P01'},];
onItemSelect={item => Alert.alert(" ", JSON.stringify(item.prestadora + ", LINHA: " + item.pos), [{ text: "open the especifc screen", onPress: () =>('some code here')},{ text: "bacvk", onPress: () => console.log("OK Pressed")}],{ cancelable: true })}
//onItemSelect called after the selection from the dropdown
I read the library API, you can set the navigation keys in the item, then in the onItemSelect to go to the special screen. the example code is below.
// in the item every element add a router key
const item = [
...
{
id: 8,
name: 'Swift',
key:"the navigation params" //like the example LinhaDiurno03
},
...
]
<SearchableDropdown
multi={true}
selectedItems={this.state.selectedItems}
onItemSelect={(item) => {
his.props.navigation.navigate(item.key)
}}
/>
Here is the final code, you just need to make the route before in your app...
the full code

How to find if element exists in an array in react-native

I am trying to render an element after checking whether there is a string e.g. "abc" present in an array. I have tried using various different functions like array.find(), array.includes(), array.some() While I do so, it gives me an error -
TypeError: null is not an object(evaluating 'o.includes')
Below is the piece of code that I am using inside render function. "abc" is the array where I am trying to check whether string "a" exists in that array, if it does then display that ExpandedHeader element.
PS: I am new to react-native.
<View>
{abc.includes("a") && <ExpandedHeader title={"Got it"}
expanded={this.state.riskRatingExpanded}
onPress={() => {this.setState({
riskRatingExpanded :!this.state.riskRatingExpanded,
basicDetailsExpanded : false,
envProfileExpanded : false,
nwswProfileExpanded : false,
additionalInfoExpanded : false,
scoresExpanded : false,
});
}}
/>}
</View>
But instead, if I do the below it works -
<View>
{abc != null && <ExpandedHeader title={abc[0]}
expanded={this.state.riskRatingExpanded}
onPress={() => {this.setState({
riskRatingExpanded :!this.state.riskRatingExpanded,
basicDetailsExpanded : false,
envProfileExpanded : false,
nwswProfileExpanded : false,
additionalInfoExpanded : false,
scoresExpanded : false,
});
}}
/>}
</View>
Your render function runs before your array data is present and initially your array data is null,
make sure you initialise your abc state as array first,
state = {
abc: []
}
with this, your first code should work.

Why is my POST faling in this simple VueJS form?

This is for a vueJS form. I have a nested value named "medications" I'm trying to submit for a form....I have this code in my template and data area that is related to medications. after I select the medication from the select box and enter the remaining fields and submit I get an error telling me I'm not submitting all my values...here are snips from my code...
NOTE: I'm not showing the entire form...only the part related with medication form field.
<template>
...
<div class="col-sm-2">
<b-form-select v-model="medication">
<option selected :value="null">Medication</option>
<option value="name" v-for="catMed in catMedications">{{catMed.medication.name}}</option>
</b-form-select>
</div>
...
</template>
data(){
...
duration: '',
frequency: '',
name: '',
medication: {name: '', duration: '', frequency: '', dosage: '', notes: ''},
...
(also, here is my POST function..if it helps)
postFeedings(catID, catName) {
const vm = this;
axios.post(`/api/v1/carelogs/`,{
cat: {id: catID, name: catName},
weight_unit_measure: 'G',
weight_before_food: this.weight_before_food,
food_unit_measure: 'G',
amount_of_food_taken: this.amount_of_food_taken,
food_type: this.food_type,
weight_after_food: this.weight_after_food,
stimulated: this.stimulated,
stimulation_type: this.stimulation_type,
medication: {name: vm.name, duration: vm.duration, frequency: vm.frequency, dosage: vm.dosage, notes: vm.notes},
medication_dosage_unit: 'ML',
medication_dosage_given: this.medication_dosage_given,
notes: this.notes
})
.then(response => {
console.log(response);
response.status === 201 ? this.showSwal('success-message','Carelog added') : null;
this.getFeedings(catName);
})
.catch(error => {
console.log(catID, catName);
console.log(error);
this.showSwal('auto-close', error);
})
}
ERROR: This is the error I get back ....
{"medication":{"frequency":["This field may not be blank."],"name":["This field may not be blank."]}}
ALL THE OTHER PARAMS ARE BEING SENT...but the ones for medication are not...
What am I doing wrong?
EDIT: updated axios post as Husam Ibrahim suggested
Like Husam says, In a function definition, this refers to the "owner" of the function. So when u access this in the axios function, this refers to the axios function, not to the vue instance.
Also - what i like to do is, create the object in the data of the vue instance, and use that for your post. Makes much cleaner code, and vue can access the object and properties.
Like this:
data () {
myObject: {
data1: 'abc',
data2: 'def',
data3: 123,
data4: false
}
}
and the axxios function like this:
const vm = this;
axios
.post('url.here', vm.myObject)
.then(response => {
// Handle response..
});
In vue you can use v-model="myObject.data1" to access the properties. This way you can use axxios get and assign the result to vm.myObject and vue will render the new data.
The key was in how I was getting "name" in my template. So I changed it up to this...
<div class="col-sm-2">
<b-form-select v-model="medication">
<option selected :value="null">Medication</option>
<option :value=catMed.medication.name v-for="catMed in catMedications">{{catMed.medication.name}}</option>
</b-form-select>
</div>
NOTE: see how :value=catMed.medication.name is configured? That's the key. now when I inspect my params in the browser I can see that I'm setting Medication.name to the value I intend.
And inside my axios.post I change the medication line to this...
...
medication: {name: this.medication, duration: this.duration, frequency: this.medication_dosage_given, dosage: this.dosage, notes: this.notes},
...
Now the two values are posting params ^_^