add dynamic empty objects to an array React - reactjs

I have the following code, which basically adds empty objects to an array.
handleAddNewRow = () => {
this.setState({
rowData: [
{ MEMBER: "", ALIAS: "", STATUS: "" },
...this.state.rowData
]
})
}
Lets say, I am passing an integer value to the function handleAddNewRow and then it dynamically adds the number of empty objects to the array based on the integer value, How is it possible?

You can look at my function:
handleAddNewRow = (number) => {
this.setState({
rowData: [
...this.state.rowData,
...(new Array(number).fill({ MEMBER: "", ALIAS: "", STATUS: "" }))
]
});
}

in the following code i wrote code in simple condition
change it on your own
const array = [{name: '', family: ''}]
function a(num, arr) {
let temp = [...arr, {name: '', family: ''}]
if (num - 1 > 0) {
temp = a(num - 1, temp)
}
return temp
}
const b = a(4, array)
console.log(b)

Related

want to filter an array

I want to get an array with filtered values.
My arrays are like,
let arr=[{name:'trt,tet', id:5},{name:td, id:25},{name:fxg, id:1},{name:fs, id:4},{name:ste, id:41}]
&
let arr1 =[{data:fxg, addr:po 87987},{data:tert, addr:po8798fvd7},{data:trt, addr:po 887},{data:trhd, addr:po 8798787}]
my resultant array that I want is,
let rslt =[data:tert, addr:po8798fvd7},{data:trhd, addr:po 8798787}]
that is in arr the object 'name' which is also in arr1 with name 'data' I don't need that array. nd some of which contain more than one name. I want to filter it.
try this
let arr=[{name:'trt,tet', id:5},{name:'td', id:25},{name:'fxg', id:1},{name:'fs', id:4},{name:'ste', id:41}]
let arr1 =[{data:'fxg', addr:'po 87987'},{data:'tert', addr:'po8798fvd7'},{data:'trt', addr:'po 887'},{data:'trhd', addr:'po 8798787'}]
const names = arr.flatMap(a => a.name.split(','))
const res = arr1.filter(a => !names.includes(a.data))
console.log(res)
This uses a Set which is optimized for lookups in O(1) and therefore the runtime of the algorithm is O(n) in contrast to using includes() which will result in a runtime of O(n²).
let arr = [
{ name: "trt", id: 5 },
{ name: "td", id: 25 },
{ name: "fxg", id: 1 },
{ name: "fs", id: 4 },
{ name: "ste", id: 41 },
];
let arr1 = [
{ data: "fxg", addr: "po87987" },
{ data: "tert", addr: "po8798fvd7" },
{ data: "trt", addr: "po887" },
{ data: "trhd", addr: "po8798787" },
];
// use array for quick lookups in O(1)
const set = new Set(arr.map(item => item.name));
// filter arr1 adding only items to result that are not in Set
const result = arr1.filter(item => !set.has(item.data))
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

In React, how do I name a field of my form that is part of an array?

I'm building a React 16.13.0 application. In my form, I want to submit data (an address) as part of an array, so I set up my state like so ...
constructor(props) {
super(props);
this.state = {
countries: [],
provinces: [],
errors: [],
newCoop: {
name: '',
types: [],
addresses: [{
formatted: '',
locality: {
name: '',
postal_code: '',
state: ''
},
country: FormContainer.DEFAULT_COUNTRY,
}],
enabled: true,
email: '',
phone: '',
web_site: ''
},
I then created these functions for managing changes to the input fields ...
  handleInput(e) {
    let self=this
    let value = e.target.value;
    let name = e.target.name;
    this.setValue(self.state.newCoop,name,value)
  }
  setValue = (obj,is, value) => {
       if (typeof is == 'string')
         return this.setValue(obj,is.split('.'), value);
       else if (is.length === 1 && value!==undefined) { 
         return this.setState({obj: obj[is[0]] = value});
       } else if (is.length === 0)
         return obj;
       else
         return this.setValue(obj[is[0]],is.slice(1), value);
  }
...
                <Input inputType={'text'}
                   title= {'Street'} 
                   name= {'addresses[0].formatted'}
                   value={this.state.newCoop.addresses[0].formatted} 
                   placeholder = {'Enter address street'}
                   handleChange = {this.handleInput}
                   errors = {this.state.errors} 
                  /> {/* Address street of the cooperative */}
The Input.jsx file looks like the below ...
const Input = (props) => {
    return (  
  <div className="form-group">
      <FormLabel>{props.title}</FormLabel>
      <FormControl
            isInvalid={props.errors && Boolean(props.errors[props.name])}
            type={props.type}
            id={props.name}
            name={props.name}
            value={props.value}
            placeholder={props.placeholder}
            onChange={props.handleChange}
          />
      {props.errors && props.errors[props.name] && (
          <FormControl.Feedback type="invalid">
                 {props.errors[props.name].map((error, index) => (
                     <div key={`field-error-${props.name}-${index}`} className="fieldError">{error}</div>
                 ))} 
          </FormControl.Feedback>
      )}
  </div>
    )
}
export default Input;
However, when I attempt to change the value, I get the below error. I'm not sure what else I need to be doing to name my component such that I can successfully change it's value. I would prefer not to change the data structure in my constructor, but I'm willing to if that's what it takes.
TypeError: Cannot set property 'formatted' of undefined
FormContainer.setValue
src/containers/FormContainer.jsx:127
124 | if (typeof is == 'string')
125 | return this.setValue(obj,is.split('.'), value);
126 | else if (is.length === 1 && value!==undefined) {
> 127 | return this.setState({obj: obj[is[0]] = value});
| ^
128 | } else if (is.length === 0)
129 | return obj;
130 | else
ISSUE:
Cannot set property 'formatted' of undefined
// Reason : because you can't access obj["addresses[0]"]["formatted"]
// Solution : it should look something like obj["addresses"][0]["formatted"]
Because you are splitting up string by ., so a result you are getting
[
"addresses[0]",
"formatted"
]
Now that you have successfully splitted up the string ,
You are trying to get object by name, specifically obj["addresses[0]"], But you can't access the object index like this,
It will give you undefined, so as a result, you are getting the above error. you can check that exact error by running below code snippet,
const obj = {
name: '',
types: [],
addresses: [{
formatted: '',
locality: {
name: '',
postal_code: '',
state: ''
},
}],
};
const names = "addresses[0].formatted".split(".")
console.log("obj['addresses[0]'] ===>" , obj[names[0]])
console.log("obj['addresses[0]']['formatted'] ===>" , obj[names[0]][names[1]])
SOLUTION :
So now question is if not obj["addresses[0]"] this then what, the solution is obj["addresses"]["0"],
So you have 2 options :
First : change this addresses[0].formatted to addresses.0.formatted
Second : you need to split the sting with .split(/[\[\].]+/)
I would prefer second option as this addresses[0].formatted looks real form name, and this is how it should look like, you can check that in below code snippet also.
const obj = {
name: '',
types: [],
addresses: [{
formatted: '',
locality: {
name: '',
postal_code: '',
state: ''
},
}],
};
const names = "addresses[0].formatted".split(/[\[\].]+/)
console.log("obj['addresses'] ==>" , obj[names[0]])
console.log("obj['addresses']['0'] ==>" , obj[names[0]][names[1]])
console.log("obj['addresses']['0']['formatted'] ==>" , obj[names[0]][names[1]][names[2]])
NOTE :
Now, once you solved the issue, real issue come up in the picture, obj: obj[is[0]] = value, here obj is object so this will throw error , and also your setValue function is limited to that functionality only, it should be generic
handleInput = e => {
let name = e.target.name;
let value = e.target.value;
const keys = name.split(/[\[\].]+/);
this.setState(this.updateValue(this.state, keys, value));
};
// I've created a recursive function such that it will create a
// copy of nested object so that it won't mutate state directly
// obj : your state
// name : input name
// value : value that you want to update
updateValue = (obj, name, value, index = 0) => {
if (name.length - 1 > index) {
const isArray = Array.isArray(obj[name[index]]);
obj[name[index]] = this.updateValue(
isArray ? [...obj[name[index]]] : { ...obj[name[index]] },
name,
value,
index + 1
);
} else {
obj = { ...obj, [name[index]]: value };
}
return obj;
};
WORKING DEMO :
Your code is quite confusing, that's part of your problem to begin with, the other problem with your code is that it is not good practice to have nested objects in react's state. You can learn more by reading this answer in this other question.
Here is an example of what you could do with your code to set the state, however, notice that this is a bad way of solving the issue:
handleInput(e) {
let value = e.target.value;
this.setState(prevState =>{
...prevState,
newCoop: {
...prevState.newCoop
addresses: [
{
...prevState.newCoop[0].addresses
formatted: value
}
]
}
})
}

How to find objects with the same property values in an Array of Objects in typescript?

I have an array of objects
var myArray = [
{id: 1, name: 'Foo Bar', email: 'foo#bar.com'},
{id: 2, name: 'Bar Foo', email: 'bar#foo.com'},
{id: 3, name: 'Joe Ocean', email: 'joe#ocean.com'},
{id: 3, name: 'Jenny Block', email: 'foo#bar.com'},
];
I am expecting the following output:
commonIdsObjects = [
{id: 3, name: 'Joe Ocean', email: 'joe#ocean.com'},
{id: 3, name: 'Jenny Block', email: 'foo#bar.com'},
]
I assume that you want the output to be a single array containing all the duplicate entries, even if some of those entries have different ids. For example, if you had added {id: 2, name: 'Fishy Joe', email: 'com#foo.bar'} to myArray, the resulting commonIdsObjects would be an array of four items: two for id: 2 and two for id: 3. If this is not what you want then you should take care to specify exactly the expected behavior.
Anyway, assuming you have a type corresponding to the elements of myArray, like this:
type Elem = typeof myArray[number];
And assuming your target runtime has access to the Object.values() and Array.prototype.flat() methods, then you can write
const commonIdsObjects = Object.values(
myArray.reduce<{ [k: number]: Elem[] }>(
(a, v) => ((a[v.id] || (a[v.id] = [])).push(v), a), {}
)
).filter(c => c.length > 1).flat(1);
What we're doing is using myArray.reduce() to build an object whose keys correspond to your elements' id values, and whose values are arrays of elements with those id. We convert this object into an array of arrays of elements, keep only those whose lengths are more than one (i.e., any id with more than one element corresponding to it), and flatten into a single array.
This will produce the desired result:
console.log(JSON.stringify(commonIdsObjects));
// [{"id":3,"name":"Joe Ocean","email":"joe#ocean.com"},
// {"id":3,"name":"Jenny Block","email":"foo#bar.com"}]
If you don't have access to Object.values() and [].flat() you can use Object.keys() and [].reduce() instead:
type ElemsById = { [k: string]: Elem[] }
const commonIdsObjects2 = ((o: ElemsById) => Object.keys(o).map(k => o[k]))(
myArray.reduce<ElemsById>(
(a, v) => ((a[v.id] || (a[v.id] = [])).push(v), a), {}))
.filter(c => c.length > 1).reduce<Elem[]>((a, v) => (a.push(...v), a), []);
console.log(JSON.stringify(commonIdsObjects2)); // same
which is essentially the same algorithm. Or you could do this algorithm the purely-imperative-programming way with various for loops:
const elemsById: ElemsById = {};
for (let v of myArray) {
if (!elemsById[v.id]) {
elemsById[v.id] = []
}
elemsById[v.id].push(v);
}
const commonIdsObjects3: Elem[] = []
for (let k in elemsById) {
if (elemsById[k].length <= 1) {
continue;
}
for (let v of elemsById[k]) {
commonIdsObjects3.push(v);
}
}
console.log(JSON.stringify(commonIdsObjects3)); // same
Okay, hope that helps; good luck!
Playground link to code
var myArray = [
{ id: 1, name: "Foo Bar", email: "foo#bar.com" },
{ id: 2, name: "Bar Foo", email: "bar#foo.com" },
{ id: 3, name: "Joe Ocean", email: "joe#ocean.com" },
{ id: 3, name: "Jenny Block", email: "foo#bar.com" }];
const commonIdsObjects = myArray.filter(x => x.id === 3);
console.log(commonIdsObjects);

How to transform object into array?

I have an object which is dynamically built. I need to get some of the fields of this object (exactly the dynamic ones) and parse them into an array.
In the code below, I need to transform the towers[X] into an array of objects.
{id: "", description: "Teste", towers[1]: true, towers[2]: true,
towers[3]: true, …}
description: "Test"
id: ""
towers[1]: true
towers[2]: true
towers[3]: true
towers[4]: ""
}
I want it to be something like:
{
id: ""
description: "Test",
towers[1]: true //Don't care if it stays here or not, will not use
...
}
And a new array like:
{
[id: 1, value: true],
[id: 2, value: true],
[id: 3, value: true],
[id: 4, value: ""]
}
Just going to guess towers[0] gives back a number, if it does you can do this. This will find all keys that have boolean values and keep them and append them to a object.
const obj = YOUROBJHERE;
Object.keys(obj ).filter((key) => tyepof obj[key] === "boolean").reduce((accum, key) => {
return {...accum, [key]: obj[key]};
}, {})
in case of X=number and obj is the object we want to transform
let result = [];
for (let indx = 1; indx <=x ; i++) {
result.push({value:indx,value: obj['towers'+indx]})
}
If you want to transform your array of object you can do some like:
this.obj=this.obj.map(obj=>{
return {
id:obj.id,
description:obj.description,
towers:Object.keys(obj).filter((key) => key.indexOf('towers') != -1 )
.map((k,index)=>{
return {id:index+1,value:obj[k]}
})
.filter((x:any)=>x.value)
}
})
See that, map allow an "index" (begins by 0)

How to augment search function to include array within objects

Given data in this format:
// projects.json
{
businessName: "",
address: "",
city: "",
reference: "",
contacts: [
{
name: ""
phone: ""
},
{
name: ""
phone: ""
}
],
}
... and a search function (btw, this is a Vue app) which iterates the 'project' objects of the json:
export default {
computed: {
filteredProjects: function() {
const searchTerm = this.search.toLowerCase();
if (!searchTerm) {
return false;
}
return this.projects.filter((project) => {
return (project.businessName.toLowerCase().match(searchTerm)) ||
(project.reference.toLowerCase().match(searchTerm));
});
}
} // computed
} // export default
... how can I augment this function to include in the search the 'contacts' array within each 'project' object, e.g.:
return this.projects.filter((project) => {
return (project.businessName.toLowerCase().match(searchTerm)) ||
(project.reference.toLowerCase().match(searchTerm)) ||
// PSEUDO-CODE (searching contact name doesn't throw error but returns 100% of the data):
(project.contacts.filter((el) => {
el.name.toLowerCase().match(searchTerm);
}))
});
Thanks in advance for any help or suggestions,
Whiskey T.
Two things:
filter returns an array, so its value will always be true; you need to check the length of it to get a false value when it's empty
you need a return in your project.contacts.filter arrow function

Resources