How to show only values of multi selected items using react-select? - reactjs

handleBeaconChange = (beacons) => {
this.setState({
beacons
});
};
this.state = {
name: '',
color: [],
description: '',
beacons: []
};
<Select.Async
multi={true}
className="margin-select"
value={this.state.beacons}
loadOptions={getBeacons}
onChange={this.handleBeaconChange}/>
[![This is the problem I'm facing actually
I had used react-select and using that I'm using multi-select functionality.
Now the Problem is I can select multiple items but it's showing the complete object in the array rather than only the values.
When I used simpleValue attribute it passes only value but not as a kind of element in an array but as a string separated by ",(comma)" than other string
What I want is the value of all the items selected in an array]2]2

To achieve expected result of getting array values use below option
var obj = this.state.beacons;
var x = obj.map(function(k,v){
return v
})
console.log(x)
https://codepen.io/nagasai/pen/NjwWqo?editors=1111

Related

Instead of replacing the object it adds a new one in a nested array with React

Sup,
So I have this object:
data: {
OtherFields: {},
Skills: [
{
id: Math.random(),
name: 'Default Category',
skills: [],
},
],
{
So the Skills Array is very dynamic, I need to add categories, and each categories have their own array named skills, that will be filled with other objects, and the default category is there.
While the skills inside will have:
{
id: Math.random(),
skillName: 'Default Category',
}
What I want to do is add the skill to the specific category in a dynamic way with the id category as we don't know how much the user will add.
Here what I did until now:
const handleAdd = (id, content) => {
// id is the cateogry of that specific cateogry that im receiving from input
// content is the value of the input
// this is the object i need to push into the category
const newItem = {
id: Math.random(),
skillName: content,
};
// and then update it,
const newData = data.Skills.find((i) => i.id === id);
console.log(newData)
newData.skills.push(newItem);
setData({ ...data, Skills: [...data.Skills, newData] });
//this it works but adds another cateogry and doesnt not replace the current one with the new value that is added
};
This appends newData to the array:
Skills: [...data.Skills, newData]
But it doesn't filter that same record from the array when appending it. It basically means "the whole array as-is, plus this new element". Even if that element is conceptually a duplicate, the code doesn't know that. (Heck, even if it's by reference a duplicate, there's still nothing stopping an array from containing two references to the same object.)
It sounds like you want to filter that whole array to remove that element before re-appending it. For example:
Skills: [...data.Skills.filter(s => s.id !== newData.id), newData]
Since you're modifying the original object this should work, rename your variables to make it easier to read.
Also consider not changing the original object.
setData({ ...data, Skills: [...data.Skills] });

Search for a particular field in a array object and put it in another array for displaying a table in angular

I am new to angular I am getting an object array as a response from the server I need to search if any of the arrays have same key value and then put the corresponding array element values in another array for displaying it in a table.
My scenario I am passing Inquiry Number as my input Eg: 10002
My Inquiry response contains the following details Inquirydocumentno, inquirydate, materialno, name of materialinquired etc..,
My actual Response is
[
{
InquiryDate: ["2015-03-04"]
InquiryType:["A"]
MaterialNo: ["30"]
Material Name: ["Chair"]
InquiryDocument No: ["0010000012"]
},
{
InquiryDate: ["2019-03-04"]
InquiryType:["A"]
MaterialNo: ["31"]
Material Name: ["Book"]
InquiryDocument No: ["0010000015"]
},
{
InquiryDate: ["2019-03-04"]
InquiryType:["A"]
MaterialNo: ["31"]
Material Name: ["Bag"]
InquiryDocument No: ["0010000015"]
},
{
InquiryDate: ["2015-05-19"]
InquiryType:["A"]
MaterialNo: ["34"]
Material Name: ["lamp"]
InquiryDocument No: ["0010000018"]
}
]
Here In this response the details such as Inquiry date and inquiry documentno, inquiry type are fixed as header details and need to be displayed as header table whereas material no and material name are item details need to be displayed in another table on click the corresponding inquirydocument no it should display all related item details for it.
Eg: InquiryDocumentNo: 0010000015 appears two times in the response I need to be displayed it as one time in header table and on clicking a buuton details it should display the 2 item(Bag, Book) inquired in another table.
I am trying to check if the documentno is same in the response array and trying to push the corresponding item details in another array in my code(appcomponent.ts) but it is doing correctly can anyone help me to figure it out and how to do this
inq =[];
for(var i=0;i<array.length;i++)
{
var element=array[i];
for(var j=i+1;j<array.length;j++)
{
var elt =array[j];
if(element.inquirydocno==elt.inquirydocno)
{
this.inq.push(elt.Materialno);
this.inq.push(elt.Materialname);
}
}
}
console.log(this.inq);
I had attached an image of how my output should be displayed
I'd recommend to use a dictionary for the 'details table'.
Something like this
export interface InquiryItem {
materialNo: string[];
materialName: string[];
}
inquiryItems: { [inquiryDocumentNo: string]: InquiryItem[] } = {};
// Manual populating
inquiryItems['001'] = [];
inquiryItems['002'] = [];
inquiryItems['001'].push({materialNo: '31', materialName: 'Book'});
inquiryItems["001"].push({materialNo: '31', materialName: 'Bag'});
inquiryItems["002"].push({materialNo: '30', materialName: 'Chair'});
// From response array
responseArray.forEach(entry => {
const docNo = entry.InquiryDocumentNo;
if(inquiryItems[docNo] === undefined)
inquiryITems[docNo] = [];
inquiryItems[docNo].push({
materialNo: entry.Materialno;
materialName: entry.Materialname;
});
})
// Retrieval:
docItems: InquiryItem[] = inquiryItems['0010000015'];

How to reassign the nested array keys based on Angular Reactive Forms?

I am working to recreate the nested array for Angular Reactive Forms.
Existing Nested Array.
nestedArray = [{
id:'abc',
required:true,
children:[{
id:"bcd",
parentId:"abc",
required:true,
children:[{
id:"cde",
parentId:"bcd",
required:false,
children:[{
id:"def",
parentId:"cde",
required:true,
children:[{
id:"efg",
parentId:"def",
required:false,
}]
},
{
id: "xyz",
parentId: "cde",
required: true,
}]
}]
}]
}]
Recreate this array for Angular Reactive Forms
nestedArray= this.fb.group({
abc: [''],
bcd: this.fb.group({
cde: [''],
efg: [''],
}),
});
Above array is incorrect, looking for the right way to create the children in Angular Reactive Form.
Thanks
You need make a recursive function that return a FormControl or a FormGroup
form = new FormArray(this.nestedArray.map(x=>{
const group=new FormGroup({})
group.addControl(x.id,this.getGroup(x))
return group
}));
getGroup(data: any) {
if (!data.children)
return new FormControl()
const group = new FormGroup({});
if (data.children) {
data.children.forEach(x=>{
group.addControl(x.id,this.getGroup(x))
})
}
return group;
}
See stackblitz
Update really the answer is wrong, becaouse we has no form control to the "parents". the function must be like
form = new FormArray(this.nestedArray.map(x=>this.getGroup(x)))
getGroup(data: any) {
if (!data.children)
{
return new FormControl)
}
const group = new FormGroup({});
group.addControl(data.id,new FormControl())
if (data.children) {
data.children.forEach(x=>{
group.addControl(x.id,this.getGroup(x))
})
}
return group;
}
Well, the question is how conrol this crazy form. We can try create a "recursive template", but I think it's better another aproach. Imagine you has an array of elements, each one with three porperties: "index","label" and "control". And control is a reference to the FormControl of our form. Then we can construct an .html like
<div *ngFor="let item of controls">
<span [style.margin-left]="item.index*10+'px'">{{item.label}}</span>
<input [formControl]="item.control">
<span *ngIf="item.control.errors?.required">*</span>
</div>
easy no? just use directly [formControl] and item.control.errors or item.control.touched
Well, for this first declare an empty array
controls:any[]=[];
And change the fuction so we add the group in two steps: 1.-create the formControl, 2.-Add to the group, the third step is add to our array an object with {label,control and "index"}. Well it's typical when we has a recursive function to want know the "index" of the recursion.
//we pass as index 0 at first
form = new FormArray(this.nestedArray.map(x=>this.getGroup(x,0)))
getGroup(data: any,index:number) {
if (!data.children)
{
//create the control
const control=new FormControl('',data.required?Validators.required:null)
//add to the array this.controls
this.controls.push({control:control,label:data.id,index:index})
//return control
return control
}
const group = new FormGroup({});
index++
//create the control
const control=new FormControl('',data.required?Validators.required:null)
//add to the array this.controls
this.controls.push({control:control,label:data.id,index:index})
//add the control to the group
group.addControl(data.id,control)
if (data.children) {
data.children.forEach(x=>{
group.addControl(x.id,this.getGroup(x,index++))
})
}
return group;
}
Well, In the stackblitz add the property "value" to our complex object, to show how can do it, and we use as "label" the "id" -perhafs our complex object need a new property label-
just a pseudo code below, but you will need to iterate and create the final key-value object to get similar structure...
anyhow there are some tools solving similar issues, consider this: https://jsonforms.io/ - i'd consider those first.
function patch (array: any[]): any {
let res: any = {};
for (let a of array) {
res[a.id] = a;
if (a.children && a.children.length) res[a.id]['children'] = patch(a.children)
}
return res;
}

Testcafe - how do I iterate over selectors of different element types?

I have a React address form which is config driven, and each element could either be a text <input> or a <select> dropdown. When trying to fill in the form using the code below, the text inputs are populated successfully, but the select element can't be found. If I remove the select elements from the loop and select them individually afterwards, it works fine. The MOCKS.deliveryAddress values are just strings.
const addressFields = {
addressLine2: Selector('[data-testid="input-addressLine2"]'),
addressLine1: Selector('[data-testid="input-addressLine1"]'),
addressLine3: Selector('[data-testid="input-addressLine3"]'),
addressLine4: Selector('[data-testid="input-addressLine4"]'),
postalCode: Selector('[data-testid="input-postalCode"]'),
};
const fieldConfig = {
addressLine1: 'text',
addressLine2: 'text',
addressLine3: 'text',
addressLine4: 'select',
postalCode: 'text',
};
const enterAddress = async () => {
await Promise.all(
Object.keys(addressFields).map(async (field) => {
if (fieldConfig[field] === 'text') {
if (MOCKS.deliveryAddress[field]) {
await t.typeText(
addressFields[field],
MOCKS.deliveryAddress[field],
{
replace: true,
},
);
}
} else {
await t.click(addressFields[field]);
await t.click(
addressFields[field]
.find('option')
.withText(MOCKS.deliveryAddress[field]),
);
}
}),
);
};
}
I get the error 1) The element that matches the specified selector is not visible.
Am I doing something wrong here in how I handle the selector inside a map?
Thanks in advance!
According to the TestCafe documentation, the element is considered as 'visible' if it does not have display: none or visibility: hidden CSS properties and has non-zero width and height. Using the browser development tool to investigate the properties of elements used in tests.
Turns out I was doing it wrong! I should have been chaining the click events for opening the dropdown and selecting an option, rather than awaiting the select click and then awaiting the option click. E.g.
await t
.click(addressFields[field])
.click(
addressFields[field]
.find('option')
.withText(MOCKS.deliveryAddress.addressLine4),
);

Convert an iterable map object to array object in ReactJS

I'm trying to load some json file in a DropdownList from react-widgets. When I load the json file the data type looks like this:
Map {size: 1, _root: ArrayMapNode, __ownerID: undefined, __hash: undefined, __altered: false}
__altered
:
false
__hash
:
undefined
__ownerID
:
undefined
_root
:
ArrayMapNode
size
:
1
__proto__
:
KeyedIterable
While the Dropdown component (from react-widgets) needs an array! So It makes this error:
Failed propType: Invalid prop `data` of type `object` supplied to `DropdownList`,
expected `array`. Check the render method of `Uncontrolled(DropdownList)`.
I can't load the json file directly and I have to use ajax to load it (or technically I can but it's a huge file and each time the user click on the dropdown list it takes couple of seconds to load the data from file). How can I convert this to an array?
P.S. The json file looks like this:
{
"items":[
{
"id": "aaa",
"name": "english"
},
{
"id": "aab",
"name": "Swedish"
},
]
}
I think you're looking for something along the lines of:
var dropdownList = jsonObject.items.map((item, i) => {
return (
<option key={i} val={item.id}>{item.name}</option>
);
})
The Array.prototype.map function simply goes over a list and produces a new list of the same size but with changes based on the modifier/callback function.
Update based on comment:
Based on the docs for DropdownList, you have two options for passing data to the list: a flat array of item names, or a list of objects with specific keys for the item name and value.
Option 1: flat list of item names
var itemNames = jsonObject.items.map((item) => item.name );
Option 2 : list of objects
var items = jsonObject.items.map((item) => {
return {
textField: item.name,
valueField: item.id
}
});
The benefit to using the second option would be when someone selects one of the items, the event that is created with point to the val attribute of the HTML <option>. This is useful for you especially since your ids and names are not the same. An example:
Option 1 (from above):
<DropwdownList
data={itemNames}
onSelect: (event) => {
// Will give the `val` attribute set by DropdownList
// This might be the item name, or it might be something unique to DrowdownList
console.log(event.target.value);
}
/>
Option 2 (from above):
<DropwdownList
data={items}
onSelect: (event) => {
// Will give the `valueField` attribute you set, which for you is the item's `id` field
// This might be the item name, or it might be something unique to DrowdownList
console.log(event.target.value);
}
/>

Resources