Destructuring an array of objects inside an object - ecmascript-6

I have an object with the following structure:
const inventory = {
item: {
details: [
{
name: "Item A",
type: "Type A"
}
]
}
}
I would like to access the name property with pure destructuring. So far I got to the first element in the details array.
const {item: {details: [firstDetail]}} = inventory;
I don't know where to go from here to access the name property. I was expecting it to be like the following but it doesn't work. Any ideas on how to achieve this?
const {item: {details: [firstDetail]: {name}}} = inventory;

Just {name} instead of firstDetail:
const inventory = {
item: {
details: [
{
name: "Item A",
type: "Type A"
}
]
}
}
const {item: {details: [{name}]}} = inventory;
console.log(name);

Related

Trying to loop over an object using Moment JS

I have a section that pulls in data from an array and displays it and groups it by month. In order for it to show the date object I have to remove a layer from the JSON file.
It feels like I'm missing something something very small and just need to make a tiny change to loop over the data array. Can anyone point out what I'm doing wrong?
Here is the table that displays the data:
<table class="table" *ngFor="let month of transactions | keyvalue">
<tr>
<th>{{month.key}}</th>
</tr>
<tr>
<td>
<table class="table" *ngFor="let customer of month.value">
<tr>
<td>
{{customer}}
</td>
</tr>
</table>
</td>
</tr>
</table>
This is the component that groups the data:
export class AppComponent {
public transactions = {};
// Sample Data
customers = [
{
data: [
{
customer: {
name: "John"
},
// transaction_date: "2017-04-18"
transaction_date: "2019-9-22T13:56:11.971643+00:00"
},
{
customer: {
name: "Dick"
},
transaction_date: "2019-10-22T13:56:11.971643+00:00"
},
{
customer: {
name: "Harry"
},
transaction_date: "2019-7-22T13:56:11.971643+00:00"
},
{
customer: {
name: "John"
},
transaction_date: "2019-9-22T13:56:11.971643+00:00"
}
]
}
];
constructor() {}
ngOnInit() {
const monthName = item =>
moment(item.transaction_date, "YYYY-MM-DD").format("MMM");
// Establish groupBy array
this.transactions = _.chain(this.customers)
.groupBy(monthName)
.mapValues(items => _.map(items, "customer.name"))
.value();
const byMonth = _.chain(this.customers)
.groupBy(monthName)
.mapValues(items => _.map(items, "customer.name"))
.value();
console.log(byMonth);
return byMonth;
console.log(this.customers2);
}
}
If I format the Json differently it works, but I need it to work with the data [] array as well.
// Working Array
customers2 = [
{
customer: {
name: "John"
},
// transaction_date: "2017-04-18"
transaction_date: "2019-9-22T13:56:11.971643+00:00"
},
{
customer: {
name: "Dick"
},
transaction_date: "2019-10-22T13:56:11.971643+00:00"
},
{
customer: {
name: "Harry"
},
transaction_date: "2019-7-22T13:56:11.971643+00:00"
},
{
customer: {
name: "John"
},
transaction_date: "2019-9-22T13:56:11.971643+00:00"
}
];
Try this:
this.transactions = _.chain(this.customers[0].data)
const byMonth = _.chain(this.customers[0].data)
Working stackblitz.
UPDATE
Your customers member variable is an array with only one element.
That was the reason for adding [0] to access it.
You simply access the first element in an array like that. Array name and an index value (zero based).
Few more examples:
customers = []; // <-- simple array
customers = [{}]; // <-- simple array with one object in it
How to access it?
customers[0] // <-- first element
Your case:
customers = [{ data: [] }]; // <-- simple array with one object in it with a property "data" which is another array.
How to access it?
customers[0].data // <-- the solution

Project data out of an immutable map to a different shape

I have a Map of immutable objects with a structure like:
id1: {
someField: 'anyvalue',
description: 'description1'
},
id2: {
someField: 'anotherValue`,
description: 'description2'
}
I want to project a List of the descriptions without resorting to toJS():
[ 'description1', 'description2' ]
How do I do this?
const data = new Immutable.Map({id1: {
someField: 'anyvalue',
description: 'description1'
},
id2: {
someField: 'anotherValue',
description: 'description2'
}});
const out = data.valueSeq().map(v => v.description).toList();
console.log(out)
<script src="https://cdnjs.cloudflare.com/ajax/libs/immutable/3.8.2/immutable.js"></script>

Angular2 & Typescript - Create object from nested JSON

I have a class which has multiple interfaces inside of it to model a JSON data. For example:
interface A {
id: number;
}
interface B {
name: string;
surname?: string;
}
class MyClass implements A {
people: B[];
notes: string[];
function1(){...}
function2(){...}
}
And I have a JSON in the same structure:
{
id: 1,
people: [
{
name: "john"
},
{
name: "alice",
surname: "smith"
}
],
notes: [ "Very important top secret note" ]
}
Can I create an instance of MyClass from this JSON directly?
Your data structure is almost the same as your class, you'd have to add an id property to the class
class MyClass implements A {
id: number;
// ....
}
The problem is if you were trying to do something like this:
let data: MyClass = {
id: 1,
people: [
{
name: "john"
},
{
name: "alice",
surname: "smith"
}
],
notes: [ "Very important top secret note" ]
}
This won't work because your json does not have the methods (function1, function2).
One solution would be to really instantiate the MyClass and pass the json, or have a constructor method for that like
class MyClass {
static createFrom(jsonData: A & B): MyClass {
// create the objct and return
}
}
Or, you could create a variable of that type by combining an existing instance of the class and spreading the json.
Like so:
let json = {
id: 1,
people: [
{
name: "john"
},
{
name: "alice",
surname: "smith"
}
],
notes: ["Very important top secret note"]
}
const c = new MyClass();
let mClass: MyClass = {...json, function1: c.function1, function2: c.function2 };
mClass.function1();
Link to playground

Typescript JSON string to class

Let be this JSON string:
[
{
"id": 1,
"text": "Jon Doe"
},
{
"id": 1,
"text": "Pablo Escobar"
}
]
Let be this class:
export class MyObject{
id: number;
text: string;
}
How can I cast this JSON string to list of MyObject?
If I do:
console.log(<MyObject[]>JSON.parse(json_string));
It returns a list of Object instead of a list of MyObject
You don't necessarily need a class here. You can just use an interface
export interface MyObject{
id: number;
text: string;
}
Then you can just write:
var myObjArray : MyObject[] = [
{
"id": 1,
"text": "Jon Doe"
},
{
"id": 1,
"text": "Pablo Escobar"
}
];
If you data comes from the server, you will probably have it in a variable of type any, and you can just assign it to an array of that type and it will work as expected.
var data: any = getFromServer();
var myObjectArray:MyObject[] = data;
In typescript you don't need a class implementing an interface. Any object literal that satisfies the interface contract will do.
If your data is still in string for you can just use JSON.parse(jsonString) to parse the string to JavaScript objects.
See playground here
You will need to create a constructor for your class, and call it for each item in the list you receive.
export class MyObject{
constructor(public id: number, public text: string) { }
}
let data = [
{
"id": 1,
"text": "Jon Doe"
},
{
"id": 1,
"text": "Pablo Escobar"
}
];
let objects = data.map(o => new MyObject(o.id, o.text));
You can check it out in the playground here.
There is a problem when MyObject has 50 or more properties...
Add a constructor in your MyObject class so that it extends your json object.
export class MyObject {
constructor( json: any )
{
$.extend(this, json);
}
id : number;
text : string;
methodOnMyObject() {...}
}
In your ajax callback, create the MyObject object from your json Object:
let newObject = new MyObject( json );
newObject.methodOnMyObject();
I detailed the solution in that post.
One more way to achieve this:
var data: any = getFromServer();
var myObjectArray = data as MyObject;
Or:
var data: any = getFromServer();
var myObjectArray = <MyObject>dataMyObject;

ImmutableJS: Convert List to indexed Map

This question is about Immutable.js library.
I have a List<T>, where T is {name: string, id: number}. I want to convert it to Map<number, T>, with id of T to the keys. Using standard method toMap gives me a Map with sequential indexes, and there is no way to hook there. And no method like indexBy or other. how to do that?
You can do it with a reducer like this:
function indexBy(iterable, searchKey) {
return iterable.reduce(
(lookup, item) => lookup.set(item.get(searchKey), item),
Immutable.Map()
);
}
var things = Immutable.fromJS([
{id: 'id-1', lol: 'abc'},
{id: 'id-2', lol: 'def'},
{id: 'id-3', lol: 'jkl'}
]);
var thingsLookup = indexBy(things, 'id');
thingsLookup.toJS() === {
"id-1": { "id": "id-1", "lol": "abc" },
"id-2": { "id": "id-2", "lol": "def" },
"id-3": { "id": "id-3", "lol": "jkl" }
};