I have a class:
class OrderParameterInfo {
Name: string;
Value: string;
and I am trying to create a JSON string. By using JSON.stringify(OrderParameterInfo("foo_name", "foo_value")) it creates {"Name":"foo_name","Value":"foo_value"} however I want it to be more like the python dictionary. So the desired output is {"foo_name":"foo_value"}.
Is there a way I can do that?
Certainly, you can create dynamic object keys like this:
const key = 'some_dynamic_key';
const value = 'some_dynamic_value';
const yourObject = { [key]: value }; // { some_dynamic_key: 'some_dynamic_value' }
So in order to achieve the result you want, you can easily create a function to do this for you like this:
const orderParameterInfo = (name, value) => ({ [name]: value });
JSON.stringify(orderParameterInfo('foo_name', 'foo_value'));
Related
I have to write the captured data from the application in JSON file as like below:
let expectedKey = 'PaperCode';
cy.get('app-screen').find('#code-details').invoke('val').as(code);
cy.get('#code').then(code) => {
cy.readFile('cypress/fixtures/applicationDetails.json').then((appDetails) => {
if(expectedKey === 'StudentCode'){
appDetails.StudentCode = code;
}
if(expectedKey === 'DepartmentCode'){
appDetails.DepartmentCode = code;
}
if(expectedKey === 'PaperCode'){
appDetails.PaperCode = code;
}
if(expectedKey === 'ResultsCode'){
appDetails.ResultsCode = code;
}
})
})
Here, the key and its value are added to json in multiple if blocks. Still, there are many if blocks to implement based on different codes. I want to remove the if blocks and need to add the key and its value to json file based on the expectedKey. Any help please?
Using bracket notation appDetails[expectedKey] to define the new property,
let expectedKey = 'studentCode';
cy.readFile('cypress/fixtures/applicationDetails.json').then((appDetails) => {
cy.get('app-screen').find('#code-details').invoke('val')
.then(code) => {
appDetails[expectedKey] = code; // add (or overwrite) new key
cy.writeFile('cypress/fixtures/applicationDetails.json', appDetails)
})
})
Clearing the file of all keys except the one you want
const expectedKey = 'studentCode';
const appDetails = {}
cy.get('app-screen').find('#code-details').invoke('val')
.then(code) => {
appDetails[expectedKey] = code; // add (or overwrite) new key
cy.writeFile('cypress/fixtures/applicationDetails.json', appDetails)
})
I have a type that I have defined in its own .ts file
export class FakeType {
value:{
name: string,
id: number
},
x: number
}
and I have an instance of that object in a .tsx file
let myObj: FakeType;
myObj = {
value:{
name: "Foo",
id: 99
},
x: 5
}
How can I programmatically create html elements corresponding to each field?
I can manually create my desired output as follows, but this won't work if FakeType has hundreds of fields
return (
<div>Value: {myObj.value}</div>
<div>x: {myObj.x}</div>);
Note that I need access to both the field name and its value when I display it on a webpage.
Using Object.keys() you can iterate each key of your object with Array.map() to return the desired HTML and display the value of each object key with myObj[key] syntax.
Working example: https://codesandbox.io/s/react-stackoverflow-60783297-ozjeu
See comments in the code below for explanation...
// Your object.
const myObj: FakeType = {
value: {
name: "Foo",
id: 99
},
x: 5
};
// Function to get value of an object with key name and unquote value object props.
// Typing `obj: any` is necessary to avoid TypeScript to complain
// about the type of the key value you're trying to retrieve.
const getValue = (obj: any, key: string) => {
const value = obj[key];
const stringify = JSON.stringify(value);
const unquoted = stringify.replace(/"([^"]+)":/g, "$1:");
return unquoted;
};
// Loop through `myObj` keys and display its value
// using the `getValue()` function implemented above.
return (
<React.Fragment>
{Object.keys(myObj).map(key => (
<div>
{key}: {getValue(myObj, key)}
</div>
))}
</React.Fragment>
);
Hope the title isn't too specific.
The back-end I am working with returns Dates as a string. I have a function to convert that string to a javascript Date object. I use a Rxjs map to convert the json response to my Typescript objects like so.
getAllRecordsByEmployeeId(employeeId: number): Observable<Record[]> {
return this.http.get<Record[]>(
this.basePath
+ this.recordPath
+ this.recordEmployeeIdParam
+ employeeId,
this.httpOptions)
.pipe(
map((res: any) => res.records as Record[]),
);
}
I want to mutate res.records.startDate with a function before it gets turned into a Record object. How can I accomplish this?
getAllRecordsByEmployeeId(employeeId: number): Observable<Record[]> {
return this.http.get<Record[]>(
I understand, that your http request does not actually return a Record array. It returns an object with a Record Array field, which is basically another Record model. It is very similar, but it's a different model.
Please consider changing it to:
interface RecordFromApi extends Record {
startDate: string; // overwrite attribute
}
interface RecordResponse {
records: RecordFromApi[];
}
getAllRecordsByEmployeeId(employeeId: number): Observable<Record[]> {
return this.http.get<RecordResponse>(
this.basePath
+ this.recordPath
+ this.recordEmployeeIdParam
+ employeeId,
this.httpOptions)
.pipe(
map((res: RecordResponse) => res.records.map(record => mapRecord(record))), // mapRecord is a custom function which maps RecordFromApi model to Record model
);
}
We do something similar in my application. But instead of returning
res.records as Record[]
we do something like this:
.pipe(
map((records: Record[]) => records.map(records => new Record(record)))
);
and then on the record.ts
export class Record {
/*
properties
*/
date: Date;
constructor(params: Partial<Record> = {}) {
this.date = new Date(params.date);
}
}
This way you actually get instances of your class and you can use any functions you may have in your class (that's the issue we had when we came up with this solution).
I want to go through every key and get the name value from each key.
This is how my LocalStorage looks like.
key: 3 Value:
{"name":"Kevin","country":"Canada","about":"Test","image":""}
key: 4 Value:
{"name":"Homer","country":"Canada","about":"Test","image":""}
I want to getboth of these names and add them to my array. I tried it with this method:
for(var key in localStorage){
let user = JSON.parse(localStorage.getItem(key));
this.users.push(user);
}
Error I get is:
SyntaxError: Unexpected token e in JSON at position 1
var keys = Object.keys(localStorage);
keys.forEach(key=>{
var json_str =localStorage.getItem(key)
try {
var abc = JSON.parse(json_str);
this.user = abc;
} catch (e) {
console.log(e)
}
})
when you say I want to getboth of these names, i don't get it but either way you can try something like:
var keys = Object.keys(localStorage);
for(var i=0;i<keys.length;i++){
var key = keys[i];
console.log(key, localStorage[key]);
//store here "both names" where you want them
//you can also access each element with localStorage[key].name, localStorage[key].country, etc.
}
This is a refinement of Robert's answer.
Just enumerate all of the values (The keys themselves do not matter) in localStorage that have a name property that is a string. Then return that array.
Based on your own answer, you likely have inconsistent mutable state as moving your temporary variable to instance scope should not impact your situation.
function getUsers() {
return Object.values(localStorage)
.map(json => {
try {
return JSON.parse(json);
}
catch (e) {
return undefined;
}
})
.filter((user?: any): user is {name: string} => user && typeof user.name === 'string');
}
const users = getUsers();
You can consider using my library ngx-store to deal with localStorage, sessionStorage, cookies and a bit more in Angular. To achieve what you want you will be able to store whole array in storage or just use code like the below with your current data structure:
import { LocalStorageService } from 'ngx-store';
export class Example {
public users: Array<any> = [];
constructor(public localStorageService: LocalStorageService) {
this.localStorageService.utility.forEach((value, key) => this.users.push(value));
}
}
Really, it can be just that simple ;)
You can use method hasOwnProperty('propertyName') to check name available or not in object. Then perform the operation that you want.
let localStorage = {
"key1": {"name":"Kevin","country":"Canada","about":"Test","image":""},
"key2": {"name":"Homer","country":"Canada","about":"Test","image":""}
}
for(let key of Object.keys(localStorage)){
if(localStorage[key].hasOwnProperty('name')){
console.log(localStorage[key]['name']);
}
}
const allItems = []
const keys = Object.keys(window.localStorage); // all keys
keys.forEach(key=> {
const item = JSON.parse(localStorage.getItem(key) + ''); //item with type Object
allItems.push(item);
});
console.log(allItems) // arry of object
I manage to solve it, was a simple error by always initializing a new let user inside the loop.
I moved out the user and the rest of the code works.
user: any;
getUsers():void{
for(var key in localStorage){
this.user = JSON.parse(localStorage.getItem(key));
this.users.push(this.user);
}
}
I've a data structure like this (generated by normalizr):
const data = fromJS({
templates: {
"83E51B08-5F55-4FA2-A2A0-99744AE7AAD3":
{"uuid": "83E51B08-5F55-4FA2-A2A0-99744AE7AAD3", test: "bla"},
"F16FB07B-EF7C-440C-9C21-F331FCA93439":
{"uuid": "F16FB07B-EF7C-440C-9C21-F331FCA93439", test: "bla"}
}
})
Now I try to figure out how to replace the UUIDs in both the key and the value of the template entries. Basically how can I archive the following output:
const data = fromJS({
templates: {
"DBB0B4B0-565A-4066-88D3-3284803E0FD2":
{"uuid": "DBB0B4B0-565A-4066-88D3-3284803E0FD2", test: "bla"},
"D44FA349-048E-4006-A545-DBF49B1FA5AF":
{"uuid": "D44FA349-048E-4006-A545-DBF49B1FA5AF", test: "bla"}
}
})
A good candidate seems to me the .mapEntries() method, but I'm struggling on how to use it ...
// this don't work ... :-(
const result = data.mapEntries((k, v) => {
const newUUID = uuid.v4()
return (newUUID, v.set('uuid', newUUID))
})
Maybe someone can give me a hand here?
mapEntries is the correct method. From the documentation, the mapping function has the following signature:
mapper: (entry: [K, V], index: number, iter: this) => [KM, VM]
This means that the first argument is the entry passed in as an array of [key, value]. Similarly, the return value of the mapper function should be an array of the new key and the new value. So your mapper function needs to look like this:
([k, v]) => {
const newUUID = uuid.v4()
return [newUUID, v.set('uuid', newUUID)]
}
This is equivalent to the following (more explicit) function:
(entry) => {
const key = entry[0]; // note that key isn't actually used, so this isn't necessary
const value = entry[1];
const newUUID = uuid.v4()
return [newUUID, value.set('uuid', newUUID)]
}
One thing to note is that the templates are nested under the templates property, so you can't map data directly -- instead you'll want to use the update function.
data.update('templates', templates => template.mapEntries(...)))
So putting everything together, your solution should look like the following:
const result = data.update('templates', templates =>
templates.mapEntries(([k, v]) => {
const newUUID = uuid.v4()
return [newUUID, v.set('uuid', newUUID)]
})
);