How to assign values to object that has similar keys? - javascript

just wanted to avoid if statements is there way to assign values to object if they have similar keys in response instead of checking each object with if ?
what could be efficient approach here ?
main.ts
public responsehandler(#Body()data: any): any {
const response: Idetails = {} as Idetails;
if (data.details === undefined || data.details === null) {
return data;
}
if (data.details) {
if (data.details.primary) {
response.details.primary.beginningBalance = data.details.primary.beginningBalance;
response.details.primary.endingBalance = data.details.primary.endingBalance;
}
if (data.details.secondary) {
response.details.secondary.beginningBalance = data.details.secondary.beginningBalance;
response.details.secondary.endingBalance = data.details.secondary.endingBalance;
}
}
return response;
}
interface.ts
export interface Idetails {
primary:balanceDetails;
secondary: balanceDetails;
}
export interface balanceDetails {
beginningBalance: string;
endingBalance: string;
}
data
details: {
primary: {
beginningBalance: 458,
endingBalance: 890
},
secondary: {
beginningBalance: 47,
endingBalance: 871
}
}

Check this out: https://developer.mozilla.org/es/docs/Web/JavaScript/Referencia/Objetos_globales/Object/hasOwnProperty
You could try this approach:
public responsehandler(#Body()data: any): any {
const response: Idetails = {} as Idetails;
if (!data.details) {
return data;
}
for (const key in response.details) {
if (data.details.hasOwnProperty(key)) {
response.details[key] = data.details[key];
}
}
return response;
}
You should check more validations or conditions to make it work for you.

If your goal is just to avoid if statements, you could rewrite it like so:
// in js (sorry not a ts user)
function responseHandler(data) {
return data.details == null ? data : {details: {...data.details}};
}
console.log(responseHandler({details: {primary: {beginningBalance: 0, endingBalance: 1}}}));
console.log(responseHandler({details: {secondary: {beginningBalance: 0, endingBalance: 1}}}));
console.log(responseHandler({noDetails: 'oopsy'}));

Related

How to generate getters and setters in Javascript?

I have the following code, which is very repetitious:
const flags = {
get logged() {
return localStorage.getItem("logged") === "true";
},
set logged(val: boolean) {
if (val) {
localStorage.setItem("logged", "true");
} else {
localStorage.removeItem("logged");
}
},
get notificationsMuted() {
return localStorage.getItem("notifications-muted") === "true";
},
set notificationsMuted(val: boolean) {
if (val) {
localStorage.setItem("notifications-muted", "true");
} else {
localStorage.removeItem("notifications-muted");
}
}
}
As you can see, the get and set for each flag type is identical, save for the property names. I would like to do something like this instead:
function getter(prop: string) {
return localStorage.getItem(prop) === "true";
}
function setter(prop: string, val: boolean) {
if (val) {
localStorage.setItem(prop, "true");
} else {
localStorage.removeItem(prop);
}
}
const flags = {
get logged: getter("logged")
set logged: setter("logged")
get notificationsMuted: getter("notifications-muted")
set notificationsMuted: setter("notifications-muted")
}
But I'm not sure if Javascript / Typescript has support for this sort of thing. Is such a thing possible, and if so, how? If not, is there any other way I can cut down on the repetition here?
You can use a proxy with get and set traps, use TS types to allow only props you wish to handle (TS playground)):
interface Flags {
logged: boolean,
'notifications-muted': boolean;
}
type Prop = keyof Flags;
const handlers = {
get(_: Flags, prop: Prop) {
return localStorage.getItem(prop) === "true";
},
set(_: Flags, prop: Prop, val: any) {
if (val) {
localStorage.setItem(prop, "true");
} else {
localStorage.removeItem(prop);
}
return true;
}
};
const flags = new Proxy<Flags>({} as Flags, handlers);
All you really need is to use Object.defineProperty with an object with a get and set properties. Or, with multiple properties, use Object.defineProperties to define them all at once.
One approach which will help with code organization is to not use lots of local storage keys, but instead use a single object that gets stored.
const props = ['logged', 'notificationsMuted'] as const;
const defaultStorage = Object.fromEntries(props.map(prop => [prop, false]));
const getStorage = () => JSON.parse(localStorage.getItem('settings') || JSON.stringify(defaultStorage));
const flags = Object.defineProperties(
{},
Object.fromEntries(
props.map(
prop => [
prop,
{
get: () => getStorage()[prop],
set: (newVal: boolean) => {
const store = getStorage();
store.prop = newVal;
localStorage.setItem('settings', JSON.stringify(store));
}
}
]
)
)
) as Record<(typeof props)[number], boolean>;
This is the current "best" solution I can come up with. Open to anyone who can provide an improvement over this:
function getter(prop: string): boolean {
return localStorage.getItem(prop) === "true";
}
function setter(prop: string, val: boolean): void {
if (val) {
localStorage.setItem(prop, "true");
} else {
localStorage.removeItem(prop);
}
}
const flags = {
get logged() { return getter("logged") },
set logged(val: boolean) { setter("logged", val) },
get notificationsMuted() { return getter("notifications-muted"); },
set notificationsMuted(val: boolean) { setter("notifications-muted", val); }
}

set name of properties dynamically JavaScript [duplicate]

Is there a way in typescript to set a property name from a variable?
Something like this
export function objectFactory(prop: string) {
return {
prop: {
valid: false
}
};
}
You are looking for computed properties, this is an ES6 feature and not specific to TypeScript.
export function objectFactory(prop: string) {
return {
[prop]: {
valid: false
}
};
}
You can do it like this:
export function objectFactory(prop: string) {
let data: any = {};
data[prop] = {};
data[prop].valid = false;
return data;
}

Angular 2 Array.map returns undefined

I'm stuck with return a value using Array.map in Angular 2
So what am I missing here?
export class TabsPage {
#ViewChild(SuperTabs) superTabs: SuperTabs;
public rootTab: string = 'ProductListPage';
public categories: Array<any>;
public collection_id: number;
public selectedindex: any;
private getArrayIndex(source, target) {
source.map((element, index) => {
if (element.attrs.collection_id === target) {
// Returns the Value i need
console.log('i: ', index);
return index;
}
});
}
constructor(
public navCtrl: NavController,
public navParams: NavParams,
public shopifyClientProvider: ShopifyClientProvider,
private superTabsCtrl: SuperTabsController,
) {
this.categories = navParams.get('collections');
this.collection_id = navParams.get('collection_id');
this.selectedindex = this.getArrayIndex(this.categories, navParams.get('collection_id'));
// Returns undefined
console.log('Index ', this.selectedindex);
}
}
I know this question is already answered but I have one solution for this same.
.ts file code
private getArrayIndex(source, target) {
let indx = -1;
source.map((element, index) => {
if (element.attrs.collection_id === target) {
// Returns the Value i need
console.log('i: ', index);
indx = index;
}
});
return indx;
}
You can use findIndex() to do this in pretty short order:
I don't know exactly what your data looks like, but given an array:
const target = 2;
const source = [
{
attrs: {
collection_id: 1
}
},
{
attrs: {
collection_id: 2
}
},
{
attrs: {
collection_id: 3
}
},
];
const index = source.findIndex(element => element.attrs.collection_id === target);
would return 1 for the index. If the index isn't found, -1 will be returned.
Plunkr: https://plnkr.co/edit/5B0gnREzyz6IJ3W3
Hope that helps you out.
Looks like Typescript breaks the return. With this modification i get the desired Value:
private getArrayIndex(source, target) {
let found: number;
source.map((element, index) => {
if (element.attrs.collection_id === target) {
console.log('i: ', index);
found = index;
}
});
return found;
}

Property name on object from variable

Is there a way in typescript to set a property name from a variable?
Something like this
export function objectFactory(prop: string) {
return {
prop: {
valid: false
}
};
}
You are looking for computed properties, this is an ES6 feature and not specific to TypeScript.
export function objectFactory(prop: string) {
return {
[prop]: {
valid: false
}
};
}
You can do it like this:
export function objectFactory(prop: string) {
let data: any = {};
data[prop] = {};
data[prop].valid = false;
return data;
}

how to pass a variable in attribute value while creating it in typescript

this.listvalue;
list.forEach((v: any) => {
v.data.forEach((v2: any) => {
this.searchlist.push({
header: v.header,
value: v2.value_0
});
});
});
i want to pass the this.listvalue on the place of v2.value_0 =>v2.this.listvalue but this is not working giving syntax error I also tried v2.valueof(this.listvalue) but its also not working like that i want to change call the v2 via this.listvalue
How can I do this? what is the correct syntax for this scenario?
the whole code is here
export class Md2Component {
#Input() list: any;
#Input() listvalue: any;
public searchlist;
public placeholder: String = "Searct the JSON";
public switch: boolean = true;
public switch5: boolean = true;
public searchlistresult: any
public data: string;
public header1: String;
public resultant_list: any;
public lastone: user[] = [];
#Output() _onSelect = new EventEmitter<any>();
public anyinstance: any
public user2: user
s = '';
public index;
constructor() {
}
ngOnInit() {
this.data = this.listvalue;
this.createSearchList(this.list);
this.latest(this.searchlist);
}
private createSearchList(list: any) {
this.searchlist = [];
this.listvalue;
list.forEach((v: any) => {
v.data.forEach((v2: any) => {
this.searchlist.push({
header: v.header,
value: v2.value_0
});
});
});
}
search1(s) {
this.search(s);
if (this.switch != true) {
this.latest(this.searchlistresult)
}
}
search(s) {
this.switch = false;
this.searchlistresult = _.filter(this.searchlist, (o: any) => {
if (s) {
return _.startsWith(_.lowerCase(o.value), _.lowerCase(s));
}
this.switch = true;
return true;
});
}
latest(list: any) {
const arr = list;
const keys = [];
for (let i of arr) {
if (!keys.includes(i.header)) keys.push(i.header);
}
const result = keys
.map(k => Object.assign({header: k}, {
data: arr.filter(x => x.header === k)
.map(y => Object.assign({}, {value: y.value}))
}));
this.anyinstance = result;
}
generateArray(obj) {
return Object.keys(obj).map((key) => {return obj[key]});
}
onSelect(header: any, value: any) {
{
console.log(header);
console.log(value);
this.s = value;
this.user2 = {
header: header,
value: value
}
this.lastone.push({
'header': header,
'value': value,
}
);
this.switch = true;
this._onSelect.emit(this.user2);
}
}
}
You've said this.listvalue is an #Input() so we will assume it has been initialized with a value already.
UPDATE You can try passing as a parameter. As the global scope of listvalue is what's causing your issue, passing it into the function will bring it into the correct scope.
// Bringing listvalue into scope, to avoid use of 'this' accessor.
private createSearchList(list: any, listvalue: any) {
this.searchlist = [];
list.forEach((v: any) => {
v.data.forEach((v2: any) => {
this.searchlist.push({
header: v.header,
value: listvalue
});
});
});
}

Categories

Resources