Return array when use .reduce Angular - arrays

The following function does not return an array but only an object element. I do not understand why
const selectedId = selectedItems.reduce<string[]>(
(acc, curr, index) => ({
...acc,
item: curr.id
}),
[]
);
console.log('selectedId ', selectedId ); // {"item": "1"}
I want to select an array like this: item: ["1", "2", "3"]
Please any idea, who is a problem in my code?

It returns an object because it returns whatever the last thing your callback function returned was,¹ and your callback function is returning an object (not an array).
You may have meant to use [] rather than {} for the callback's return value (=> [...acc, item: curr.id]), but if so, that operation is more clearly expressed via map:
const selectedId = selectedItems.map(item => item.id);
(I'd also suggest using the plural — selectedIds — since it holds multiple ID values.)
¹ If you use reduce on an empty array, your callback is never called, and so the seed value you provided is returned instead. (And if you don't provide one, reduce throws an error.)

Related

replace an array object in component state

My goal is to map over an array and replace objects that match a condition. Much like this working example:
const rows = [{
"name": "Dad",
"car": "Sedan"
}, {
"name": "Mom",
"car": "Sedan"
}]
const newCar = {
"name": "Dad",
"car": "Minivan"
}
const newArray = rows.map((r) => (r.name === newCar.name ? newCar : r))
console.log(newArray)
In my use case, component state contains the array, which is populated from an API.
const [rows, setRows] = useState([])
Later, a change is required to one object in the array. The data variable contains the modified object to be merged into the array. I map over the array looking for matches on the _id field. When the _id matches, I return the object from data (the value to be merged into the array). When there is not a match, I return the object as it originally existed in state.
setRows((rows) => [
...rows,
rows.map((r) => (r._id === data._id ? data : r)),
])
The desired outcome is an array of the same size as the original. This new array should contain one modified object in addition to all original array values.
The actual results from the code above are that the modified data object is added rather than updated.
How can I change my code to replace the modified array element instead?
The useState() functional updates form calls a function and passes it the previous state. The Array.map() function returns a new arrays with the updated values. This means that you only need to map the previous state to get a new state:
setRows(rows => rows.map((r) => (r._id === data._id ? data : r)))

How to use .$$eval function

I'm trying to run this code:
var aaa = await page.$$eval(
selector,
list => (list, value) => {
return resolve(list.find(element => element.textContent === value));
},
value
);
But I received an error.
Therefore, I tried to print the items in "list" (because I assumed that the problem is there), I tried this code:
var aaa = await page.$$eval(selector, list => list);
And I received that "aaa" is empty.
Any idea what may be the problem?
You are attempting to return DOM elements from page.$$eval(), which will return undefined because DOM elements are not serializable.
Try using page.$$() instead if you would like to return an ElementHandle array.
Take a look at the Puppeteer Documentation for page.$$eval() below:
page.$$eval(selector, pageFunction[, ...args])
selector <string> A selector to query page for
pageFunction <function> Function to be evaluated in browser context
...args <...Serializable|JSHandle> Arguments to pass to pageFunction
returns: <Promise<Serializable>> Promise which resolves to the return value of pageFunction
This method runs Array.from(document.querySelectorAll(selector)) within the page and passes it as the first argument to pageFunction.
If pageFunction returns a Promise, then page.$$eval would wait for the promise to resolve and return its value.
Examples:
const divsCounts = await page.$$eval('div', divs => divs.length);
Just try to map your array to more serializable one.
For example:
const links = await page.$$eval('h1 > a', e=>e.map((a)=>a.href))

Array.filter() in Angular 2 Component

In one component I can filter my array using the following:
// Array of product objects
const result = products.filter(p => p.name.includes('val'));
and value of products remains same as the first value but filtered value stores in result.
But in the following code, filter() filters array of strings itself:
// Array of strings
const result = strs.filter(s => s.includes('val'));
The question is how can I filter strings and return result without modifying the strs itself?
Note: I tried with array.filter(function() { return res; }); but didn't make any change.
It returns the filtered ones and don't change the actual array. You are doing something wrong
const strs = ['valval', 'bal', 'gal', 'dalval'];
const result = strs.filter(s => s.includes('val'));
console.log(strs);
console.log(result);
First thing we need to know is, if we filter our list we loose our original data
products: any[] = [
{
"productId": 1,
"productName": "foo-bar",
"price": 32.99
}
]
and can't get it back without re-getting the data from it's source so we have to make another list to store the filtered list.
filteredProduce: any[];
Next if you are working to show a list of filtered product on a grid or something like this we need a way to know when the user changes the filter criteria. we could use event binding and watch for key presses or value changes, but an easier way is to change our _listFilter property into a getter and setter, like this
get listFilter: string {
return this._listFilter;
}
set listFilter(value:string) {
this._listFilter= value;
}
next we want to set our filteredProducts array to the filtered list of products like this
set listFilter(value:string) {
this._listFilter= value;
this.filteredProducts = this._listFilter? this.performFilter(this._listFilter) : this.products;
}
in preceding code we are using js conditional operator to handle the posibility that _listFilterstring is empty, null or undefined.
Next we use this.performFilter(this._listFilter) to filter our list.
performFilter(filterBy: string): any[] {
filterBy = filterBy.toLocaleLowerCase();
return this.products.filter((product: any) =>
product.productName.toLocaleLowerCase().indexOf(filterBy) !== -1);
}
Finally we should assign the main list of products to the filteredProducts and _listFilter to what we want.
constructor() {
this.filteredProducts = this.products;
this._listFilter= 'foo-bar';
}
last step is to change our template to bind to our filteredProducts property.

Async array without using anything async?

It drives me crazy. I have a really simple "problem" and it took me hours and still have no idea whats going on.
I have a child service which inherits from a parent service (I'm using ES6). The constructor takes an 1 argument called options. options will be assigned to this._defaults.
Now before I pass the options into my object (new Service(options)) I populate options with some data. To keep it simple, my current options object looks like this:
const options = {
types: []
}
Now I add some stuff into the types array, like this:
const Types = {
standard: {
some: 'data'
},
freeroll: {
some: 'data'
},
mainevent: {
some: 'data'
},
qualifier: {
some: 'data'
}
};
angular.forEach(Types, (val, key) => {
options.types[key] = true;
});
I assign my service to the scope like this:
$scope.service = new Service(options)
and output the service using console. The console now says the value of _defaults.types is Array(0). When I click on the array the correct values will be shown but the scope is not aware of that.
How is that? Doesn't Array(0) mean that at the time of the console.log() the array wasn't filled with any values but has been later? Like an async function would do?
Here is a plunk of my problem.
The problem is that types is an array and you're treating it like a plain Object. You can solve this one of two ways.
First just change types to an Object:
const options = {
types: {}
};
Or, if you need an Array, change how you're adding items to the array:
angular.forEach(Types, (val, key) => {
options.types.push({
type: key,
value: val
});
});
Note that this is just one way of turning the object into an array, the data structure you end up with is up to you.

Typescript - generate TS object from array

My problem is that i get an information from server - array of objects. And i would like to "push" every object from array to new object so the inupt looks:
[{key : value}],[{key2:value2}]....
And the output should look like:
{key:value,
key2: value2 ... }
I don't know the syntax of "push" to make new object look like my desire output.
Here's a fun little trick:
const input = [{key: 'value'}, {key2: 'value2'}];
// Object.assign() always returns any with rest arguments,
// you should cast to the actual type you're expecting here.
const result = Object.assign({}, ...input) as MyApiType;
console.log(result);
How does this work?
Object.assign() will take an arbitrary number of arguments, and merges them.
Object.assign({}, {hello: 'world'}, {goodbye: 'world'});
// {hello: 'world', goodbye: 'world'}
We pass an empty object as the first parameter and spread input into the rest of the parameters.
Why the {}, ...input? Why not just ...input?
Because Object.assign() is destructive, it mutates the first argument passed to it. If I were to call Object.assign(...input), input[0] would have been changed. We want to avoid changing the input, because it's usually unexpected behavior to those looking at the code from the outside.
What you are looking for is not push put Array.reduce (plain old js). It allows you to reduce the array to a single object. You can use it this way.
let data: [{ key: string, value: string }] = [{
key: '1',
value: '2'
}];
let obj = data.reduce((prev, current) => {
prev[current.key] = current.value;
return prev;
}, {});

Resources