React Select Async options not showing - javascript

I have an API call which is returning data and the best I can see I am returning the options in the correct way but for some reason I can't get React Select to show the options. Is there something that I am missing?
searchGroups(searchString){
if(!searchString) return Promise.resolve({ options: [] });
UserGroups.getUserGroups(searchString).then((res) => {
let groups = [];
groups = res.groups.map((d) => ({
value: d.group_ID,
label: d.group_name
}))
return {options: groups};
}, (e) => {
this.setState({
searchError: e.message
})
})
}
From what I can see the groups array is (upon a search) returning as
[
{value: 1, label: "Admins"}
{value: 22, label: "Asset Group"}
{value: 2, label: "Read-only"}
]
However the search box is being suspended with a "loading..." message and the load spinner stays. I can see the API has returned but no options are being displayed.
This is how I implement the Select is there an option I am missing? I have tried both valueKey and labelKey but neither have worked for me either.
<Select.Async
multi={true}
onChange={this.onChange}
loadOptions={this.searchGroups}
value={this.state.value}
/>
I'm sure it is how I'm returning the data but not sure where this is going wrong and what formatting I need to correct. Any help would be greatly appreciated.

The problem was a missing return before UserGroups.getUserGroups(... This caused the async code to get executed and show up in the network log, but the results wouldn't reach Select.Async. It would be nice if react-select would give an error if calling loadOptions returns undefined, but in that case it assumes a callback will be used to provide the result.

Related

How to use spread operator in setstate react class component

I am developing a component where I will get the data from a call back function. Initially the state of the component will be empty [], later once the callback function is called I need to update the values into the state. At a time I'll recive only one array, meaning user can add one item at a time that item will consists of nested objects and array values. I have added the logic for the same to handle the scenario, but when I am testing in jest when I am trying to add another set of item from mock meaning the user can select next item when the done with selecting and submitting the first item at that time my logic is getting failed, I am not getting where I went wrong, could any one help me to resolve this issue, thanks in advance! I have added the mock data structure and logic and jest test below.
Mock:
const items = {
itemList: {
itemOne: [{
id: "01",
category: "It-A",
isCreated:"true"
}],
itemDesc:[{
id:"01",
type:"A-1",
isCreated:"true"
}]
}
ItemID:'123'
}
Code:
class ItemComp extends React.Component{
this.state = {
processingItems:[]
onAddItemHandle = (processingItem) => {
this.setState(prevState => ({
processingItems: [...prevState.processingItems, processingItem]
}))
}
JEST:
describe('handleonAddItem', () => {
it('should allow to add multiple items based on prevState', () => {
const compView = mountWithIntl(
<compView
itemId={12}
/>
}
const instance = compView.find(compViewComponent).instance();
instance.onAddItemHandle(items) // when I am giving only one instance my logic is working
instance.onAddItemHandle(items) //when I am giving it for second time it's failing I am getting error like expected - 0 , received +18 I want to update the items here when user clicks for second time but it is failing.
expect(instance.state.processingItems).toEqual([items])
Missing a ',' before the ItemID is the only issue I faced while reproducing.- https://codesandbox.io/s/intelligent-chaplygin-0ot56e?file=/src/App.js
const items = {
itemList: {
itemOne: [{
id: "01",
category: "It-A",
isCreated:"true"
}],
itemDesc:[{
id:"01",
type:"A-1",
isCreated:"true"
}]
},
ItemID:'123'
}

Filter inside the fetch with mongoDB query operators

how are you? I'm trying to move a filter inside the fetch I'm doing to bring my data from Builder.io and I'm struggling with one of them here. The title search works fine, but the second one don't. My objective is to filter between the entries to catch only the ones that match at least one of the annotationArray items.
The annotationArray can be, for example:
const annotationArray = ['Video', 'Image', 'GPS']
or just
const annotationArray = ['Video']
or whatever.
And the entries have an annotation field that consists in a string where I pass the annotations, like this:
const entries = [{title: 'First', annotation: 'Video, GPS'}, {title: 'Second', annotation: 'GPS'}, {title: 'Third', annotation: 'Video, Image'}]
So, for example, if the annotationArray is ['Video', 'GPS'], I want to fetch all of them. But if it's ['Video'], only the third and first, and so.
Currently I have this code
const sets = await builder.getAll('open-dataset', {
options: { noTargeting: true },
omit: 'data.blocks',
limit: 100,
query: {
data: {
title: { $regex: search, $options: 'i' },
annotation: { $regex: annotationArray && annotationArray.join(' '), $options: 'i' },
}
}
});
The result of annotationArray.join(' ') can be, for example, Video Image GPS or just Image. And annotation Video Image or whatever.
So I need to filter between the entries and fetch only the ones that contain at least one of the annotationArray strings.
My code is failing because currently it only fetches the ones that have all the annotationArray items, and not the ones that have at least one. I don't know how to do it with MondoDB query operators... previously, I had this code with javascript and it worked fine.
const filtered = entries.filter(item => annotationArray.some(data => item.annotation.includes(data)));
can somebody help me? thanks

Is there a more accurate way to use <MockedProvider /> for testing apollo requests

I've got my <MockedProvider /> set up passing in mocks={mocks}. everything is working, all good.
the issue is I have a form that whenever any part of it is edited then this makes a mutation, which returns a response and updates the total. say for example, quantity is changed, mutation increases quantity from 1 to 2. total price should double
problem is that in unit tests and mocked provider you only test the functionality in props and hardcoded response. it's not a proper test. perhaps it's more of an e2e/integration test but I was wondering if there's anything you can do with MockedProvider that allows for better testing in this situation?
Instead of using the normal static result property of the objects in the mocks array, you can set a newData function that will run dynamically and use whatever is returned as the result value. For example:
let totalNoteCount = 0;
const mocks = [{
request: {
query: CREATE_NOTE,
variables: {
title: 'Aloha!',
content: 'This is a note ...',
},
},
newData: () => {
// do something dynamic before returning your data ...
totalNoteCount += 1;
return {
data: {
createNote: {
id: 1,
totalNoteCount,
},
},
};
}
}];

React-native: undefined is not an object

Probably it's a newbie question... I get a json response with an object from a fetch() running into a function on componentDidMount(). The result is saved into a state
data:
{
id: 1,
name: 'joseph',
tickets:
[
{id: 334, descripton: 'example1'},
{id: 768, descripton: 'example2'},
],
}
I need to list this array "tickets" in render ().
componentDidMount(){
this.getFetch(...);
}
showTickets(WTickets){
console.log(WTickets);
WTickets.map((item)=>{
return (item.id)
})
}
render(){
return(
<View>
{this.showTickets(this.state.data.tickets)}
</View>
)
}
But the "first return" is "undefined", generating error and then the state changes to the correct result. The fetch is running with async await, but still show the "undefined" first.
The console.log show 2 results: one "undefined" and another with the result.
Any good soul to help me, please?
It's because at the start this.state.data.tickets is undefined and you are calling it in the render function which is not gonna wait until this.getFetch() finishes. So.. you can do a conditional rendering to check if this.state.data.tickets exist in rendering
replace {this.showTickets(this.state.data.tickets)}
with {this.state.data!==undefined? this.showTickets(this.state.data.tickets) : null}
What we are doing here is first checking if this.state.data.tickets is not undefined. While it is undefined (at the start) we return null, when it stops being undefined we call this.showTickets.
You can even initialize this.state.data as an empty array, and you can delete the part when we check if it's undefined since an empty array will return false
constructor() {
super();
this.state = {
data: []
};
}
....
....
//in render function
{this.state.data? this.showTickets(this.state.data.tickets) : null}
...

Subscribing sequentially to a variable number of Observables in Angular 2+

Sorry if this was answered elsewhere, I tried to search but I'm not even sure what I'm looking for.
Let say I have this object to work with:
userRequest: {
id: number,
subject: string,
...
orderIds: number[]
...
}
order: {
id: number,
...
clientId: number,
productIds: number[]
}
client: {
id: number,
name: string,
...
}
product: {
id: number,
name: string,
price: number
}
Now, at some point the user will fill a form using that composite object and send it for analysis. But before sending it, it has first to be validated. And I cannot validate in the form because the user is simply entering the data received on paper. If the data is "invalid", a request for more information will be sent.
So, I need to validate the request, but also the order, the products and the client. I am requested to show a "Validating Request" screen and after each element was checked, a "Valid" or "Invalid" screen. Simple enough.
But now, I'm sending http requests and get Observables to deal with. I'm trying to learn more about them and all the available operators and how to mix them, but at the moment, I'm completely lost.
So, I first get an Observable<userRequest> from server. Then, once I get a userRequest, I need to get all the orders from their id's, and when I get an "order", I have to get the client & his products.
All this is done asynchronously, but I cannot get the client or the products until I receive the order, and I need the userRequest to provide the orders. In addition, when I get an order, I need to get both the client AND the products at the "same time" since they both need the same order...? For the grand finale, for every element I get (request, order, client, product) I need to validate it and wait for every element to say "the request is valid" or not.
So to resume:
I need to get an Observable<userRequest> and validate
Now, I have to get an Observable<order[]> and validate each order
For each order, I have to 1) get an Observable<Client> and validate PLUS 2) get an Observable<Product[]> and validate each one
Wait for every observables to complete and check if it's valid or not
Steps 1 and 2 needs to be executed sequentially, but when step 2 completes, I need to execute steps 3.1 and 3.2 for each result of step 2. And wait.
I'm sure it's far from clear, I just hope it clear enough so you guys gets want I want to achieve. If you have any hints for me, please do share!!! ; )
Edit
I do know somehow what needs to be done. But where I lose my cool, is when I need to chain the Observables sequentially (as each one depends on the one before), at various point I need to call a validation method and when it comes to the Client and the Products, both need the Order for it's Id. I did try many, many ways but I just don't grasp the concept completely.
bygrace - No, I don't want the validation to block. It should validate everything as it will result in a request for all the missing or invalid parts, and it should be showed at the end. That why I need a way to know when everything is done so I can check if errors were found.
The request, orders, client and products each comes from their respective services. The service makes an http resquest and returns an Observable. So I need to chain the calls (and when it comes to the Order, I need to get TWO Observables for the same Order Id).
QuietOran - Here's something I tried. It's horrible I know, but I'm so lost right now...
onValidateRequest(requestId: number) {
this.requestService.getUserRequest$(this.requestId)
.do(request => {
this.validateRequest(request);
})
.concatMap(request => this.orderService.getOrdersForRequest$(request.id))
.do(orders => {
this.validateOrders(orders);
})
.concatMap(orders => {
// Now, this is were I'm completely lost
// I manage to get the request and the orders, but in this block, I need to get the client AND the products
// and validate each one as I receive it
// Then return something
})
.do(() => {
// when I validate an element, if there's an error, I simple add it in an array.
// So when ALL the Observable above are completed, this function simply checks
// if there's something in it
this.checkForErrors();
})
.subscribe();
}
I'm going to give you something rough that you can refine with feedback because I'm not clear on the final shape of the data you want back and all. Hopefully this points you in the right direction.
Basically if you want the data from one observable to feed another then you can use switchmap or one of its cousins. If you need the value fed in as well as the result then just lump them together with a combineLatest or something similar.
console.clear();
function getUserRequest(requestId) {
return Rx.Observable.of({ id: 1, subject: 'a', orderIds: [10, 20] })
.delay(500).take(1);
}
function getOrdersForRequest(requestId) {
return Rx.Observable.of([
{ id: 10, clientId: 100, productIds: [ 1000 ] },
{ id: 20, clientId: 200, productIds: [ 1001, 1002 ] }
]).delay(200).take(1);
}
function getClientForOrder(orderId) {
let client;
switch(orderId) {
case 10:
client = { id: 100, name: 'Bob' };
break;
case 20:
client = { id: 200, name: 'Alice' };
break;
}
return Rx.Observable.of(client).delay(200).take(1);
}
function getProductsForOrder(orderId) {
let products;
switch(orderId) {
case 10:
products = [{ id: 1000, name: 'p1', price: 1 }];
break;
case 20:
products = [
{ id: 1001, name: 'p1', price: 2 },
{ id: 1002, name: 'p1', price: 3 }
];
break;
}
return Rx.Observable.of(products).delay(200).take(1);
}
Rx.Observable.of(1)
.switchMap(id => Rx.Observable.combineLatest(
getUserRequest(id),
getOrdersForRequest(id)
.switchMap(orders => Rx.Observable.combineLatest(
Rx.Observable.of(orders),
Rx.Observable.combineLatest(...orders.map(o => getClientForOrder(o.id))),
Rx.Observable.combineLatest(...orders.map(o => getProductsForOrder(o.id)))
)
),
(userRequest, [orders, clients, products]) =>
({ userRequest, orders, clients, products })
)
).subscribe(x => { console.dir(x); });
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.6/Rx.min.js"></script>
Right now I flattened the results by category. You may want them nested or something like that. This is just a rough pass so provide feedback as needed.

Categories