I need to apply different destructuring for the function response depending of global flag [single service for multiple apps]
// Destructuring template should be defined as value
let destructuringTemplate;
if (flag) {
destructuringTemplate = {data: {classA: user}};
} else {
destructuringTemplate = {data: {classB: user}};
}
// This technique would not work, this is just my idea representation.
this.getUser(({destructuringTemplate: user) => { this.localUser = user });
At this moment it works this way:
let destructuringTemplate;
if (flag) {
destructuringTemplate = ({data: {classA: user}}) => user;
} else {
destructuringTemplate = ({data: {classB: user}}) => user;
}
this.getUser(response => { this.localUser = destructuringTemplate(response)};
it is kinda ugly, some suggestion how it should be done?
You could use a computed property name with a conditional (ternary) operator ?:.
var flag = true,
object = { data: { classA: 'foo', classB: 'bar' } },
{ data: { [flag ? 'classA' : 'classB']: user } } = object,
{ data: { [!flag ? 'classA' : 'classB']: user1 } } = object;
console.log(user);
console.log(user1);
You don't need to use destructuring, use simple dot/bracket notation:
const userClass = flag ? 'classA' : 'classB'
this.getUser(response => { this.localUser = response.data[userClass] })
If you want to reuse this logic, just create simple function, e.g.:
const extractUser = response => response.data[userClass]
Related
Is there a way that I can simplify this code?
I was thinking if there is a way to set { ...filterItem, type: 'chip' } as the parameter in map function instead of creating a const that will be returned in each state.
Is this type of syntax possible to do? If so, is there a specific term for it?
filtersToUse = filtersToChip.map((filterItem) => {
const filterItem2 = { ...filterItem, type: 'chip' }
if (filterItem.id === '12345') {
return { ...filterItem2, labelOverride: 'new-label' }
} else if (filterItem.id === '67890') {
return { ...filterItem2, labelOverride: 'new-label' }
}
return filterItem2
})
Seems like you want to:
Add type: 'chip' too all the elements
Add labelOverride: 'new-label' if id is 12345 OR 67890
You could do something like:
filtersToUse = filtersToChip.map((filterItem) => ({
...filterItem,
type: 'chip',
...([ '12345', '67890'].includes(filterItem.id) ? { labelOverride: 'new-label' } : {})
});
Where we use object spreading to add the desired options, if needed
Couldn't you do this:
filtersToUse = filtersToChip.map((filterItem) => ({
...filterItem,
type: 'chip',
labelOverride: ['12345', '67890'].includes(filterItem.id)
? 'new-label'
: undefined,
}));
I don't know if that is what you're searching for but i would optimize like that.
const newLabelItemIds = ['12345', '67890'];
const filtersToUse = filtersToChip.map((filterItem) => {
const label = newLabelItemIds.include(filterItem.id) ? { label: 'new-label' } : {};
return {
...filterItem,
...label,
type: 'chip',
};
});
For some reason I have variables outside of my function and I'm updating that variable in my function but when I call that variable in another function I get a undefined typeError
let bikeShare = []
let stations = []
function startRide(vin) {
bikeShare = bikeShare.map((bike) => {
bike.vin === vin ? { ...bike, checkOut: true } : bike
})
return {}
}
function endRide(vin) {
console.log(bikeShare)
bikeShare = bikeShare.map((bike) => {
bike.vin === vin && bike.checkOut
? { ...bike, checkOut: false, totalRides: bike.totalRides + 1 }
: bike
})
return {}
}
function createBike(color = 'red') {
const vin = bikeShare.length + Date.now();
const payload = { vin, color, checkOut: false, totalRides: 0 }
bikeShare.push(payload);
return payload
}
const bike_1 = createBike('red')
const bike_2 = createBike('blue')
const bike_7 = createBike('green')
startRide(bike_1.vin) // in the startRide function I get an array [undefined, undefined, undefined]
endRide(bike_1.vin)
You are in the startRide() function not returning the result of each assignment in the .map method, so it returns undefined which why you see the array of undefined values.
This should fix it:
let bikeShare = []
let stations = []
function startRide(vin) {
bikeShare = bikeShare.map((bike) => {
return bike.vin === vin ? { ...bike, checkOut: true } : bike
})
return {}
}
function endRide(vin) {
console.log(bikeShare)
bikeShare = bikeShare.map((bike) => {
bike.vin === vin && bike.checkOut
? { ...bike, checkOut: false, totalRides: bike.totalRides + 1 }
: bike
})
return {}
}
function createBike(color = 'red') {
const vin = bikeShare.length + Date.now();
const payload = { vin, color, checkOut: false, totalRides: 0 }
bikeShare.push(payload);
return payload
}
const bike_1 = createBike('red')
const bike_2 = createBike('blue');
const bike_7 = createBike('green');
startRide(bike_1.vin) // in the startRide function I get an array [undefined, undefined, undefined]
endRide(bike_1.vin)
To lift this out of comment, the body of the map argument function in startRide is enclosed in curly braces. You could remove the braces or put return bike inside the braces to stop it returning undefined.
However, setting bike.vin to a bike "payload" object with checkout set to true, leaving bike.checkout set to false, is a bug. One solution might be to use find instead of map:
let bikeShare = []
let stations = []
function startRide(vin, start = true) {
const bike = bikeShare.find(bike=>bike.vin === vin);
if( bike) {
bike.checkOut = start;
}
return bike; // for debugging
}
function endRide(vin) {
return startRide( vin, false);
}
function createBike(color = 'red') {
const vin = bikeShare.length + Date.now();
const payload = { vin, color, checkOut: false, totalRides: 0 }
bikeShare.push(payload);
return payload
}
const bike_1 = createBike('red')
const bike_2 = createBike('blue')
const bike_7 = createBike('green')
console.log( startRide(bike_1.vin));
console.log( endRide(bike_1.vin));
This is the form of constructor which Douglas Crockford suggests in his book "How Javascript works" and in his lectures.
const constructor_x = function (spec) {
let { a } = spec // private state
// methods can modify private state
const method_x = function () { a = '...' }
// methods are exposed as public interface
return Object.freeze({ method_x })
}
He suggests the following pattern for composition:
const constructor_y = function (spec) {
let { b } = spec // private state
// we can call other constructor and borrow functionality
const { method_x } = constructor_x(spec)
// we define new methods
const method_y = function () { b = '...' }
// we can merge borrowed and new functionality
// and expose everything as public interface
return Object.freeze({ method_x, method_y })
}
So here we see how to compose constructor_x and constructor_y. But my problem with this example (and all examples used when this pattern is presented) is that constructor_x and constructor_y make separate private states. constructor_x works on variable a, while constructor_y works on variable b. What if we want our constructors to share state? What if constructor_y also wants to work with variable a?
const constructor_y = function (spec) {
let { a, b } = spec
const { method_x } = constructor_x(spec)
const method_y = function () { b = '...' }
const method_z = function () {
// we may want to read `a` and maybe write to it
a = '...'
}
return Object.freeze({ method_x, method_y, method_z })
}
Of course this doesn't achieve what I want because a which constructor_y sees is not the same a constructor_x sees. If I used this, I could have achieved that maybe like so:
const constructor_x = function (spec) {
return {
_a: spec.a,
method_x () { this._a = '...' }
}
}
const constructor_y = function (spec) {
return {
...constructor_x(spec),
_b: spec.b
method_y () { this._b = '...' },
method_z () { this._a = '...' }
}
}
But here I have lost privacy of variables _a and _b since they are attached to instance and are accessible just like methods. The best I can do is add underscore prefix which Douglas Crockford calls a sign of incompetence. I also lost instance's rigidness because it can no longer be frozen.
I could have exposed accessors for variable a in constructor_x like so:
const constructor_x = function (spec) {
let { a } = spec // private state
// methods can modify private state
const method_x = function () { a = '...' }
// methods are exposed as public interface
return Object.freeze({
method_x,
get_a () { return a },
set_a (val) { a = val }
})
}
const constructor_y = function (spec) {
let { a, b } = spec
const { method_x, get_a, set_a } = constructor_x(spec)
const method_y = function () { b = '...' }
const method_z = function () { set_a('...') }
return Object.freeze({ method_x, method_y, method_z })
}
These accessors can now be used by constructor_y to access private state of constructor_x. They are something like protected members in classical inheritance model. This makes constructor_x in some way special: It is not to be used as normal constructor, but only for composition inside other constructors. Another problem is that if we had another constructor like constructor_x which works on private variable a, we couldn't use them together in composition:
// another constructors which wants to work on `a`
const constructor_x2 = function (spec) => {
let { a } = spec
const method_z = function () { a = '...' }
return Object.freeze({
method_z,
get_a () { return a },
set_a (val) { a = val }
})
}
const constructor_y = function (spec) {
let { a, b } = spec
const { method_x, get_a, set_a } = constructor_x(spec)
const { method_x2, get_a: get_a2, set_a: set_a2 } = constructor_x2(spec)
// How do I use variable a now? There are two of them
// and constructors x and x2 don't share them.
}
All of this would not be a problem if I used this and modified state on the instance.
From my comments above ...
"1/2 ... First, all this creator functions should be referred to as factories or factory functions. They are not constructors. ... What if we want our constructors to share state? " ... then just implement the factories in a way that they can share each their entire inner/encapsulated state object and/or that they aggregate a shared state object while running the object creation process (the chained invocation of related functions during the composition process)."
What the OP wants to achieve can not be entirely covered by closure creating factory functionality according to Crockford / provided by the OP.
Encapsulated but shared (thus also mutable) state amongst "Function based Composable Units of Reuse" gets achieved best by a single factory which takes care of the composition process by invoking one or more mixin like functions which in addition to the to be shaped / aggregated type (the latter should carry public methods only) also need to get passed the type's local state(which will be accessed by the types's public methods).
function withActionControl(type, actionState) {
actionState.isInAction = false;
return Object.assign(type, {
monitorActions() {
const {
isInAction,
...otherActions } = actionState;
return { ...otherActions };
},
});
}
function withCanSwimIfNotBlocked(type, state) {
state.isSwimming = false;
return Object.assign(type, {
startSwimming() {
if (!state.isInAction) {
state.isInAction = true;
state.isSwimming = true;
console.log({ startSwimming: { state } })
}
},
stopSwimming() {
if (state.isSwimming) {
state.isInAction = false;
state.isSwimming = false;
console.log({ stopSwimming: { state } })
}
},
});
}
function withCanFlyIfNotBlocked(type, state) {
state.isFlying = false;
return Object.assign(type, {
startFlying() {
if (!state.isInAction) {
state.isInAction = true;
state.isFlying = true;
console.log({ startFlying: { state } })
}
},
stopFlying() {
if (state.isFlying) {
state.isInAction = false;
state.isFlying = false;
console.log({ stopFlying: { state } })
}
},
});
}
function withLaysEggsIfNotBlocked(type, state) {
state.isLayingEggs = false;
return Object.assign(type, {
startLayingEggs() {
if (!state.isInAction) {
state.isInAction = true;
state.isLayingEggs = true;
console.log({ startLayingEggs: { state } })
}
},
stopLayingEggs() {
if (state.isLayingEggs) {
state.isInAction = false;
state.isLayingEggs = false;
console.log({ stopLayingEggs: { state } })
}
},
});
}
function createSeabird(type) {
const birdState = {
type,
actions: {},
};
const birdType = {
valueOf() {
return JSON.parse(
JSON.stringify(birdState)
);
},
};
const { actions } = birdState;
withActionControl(birdType, actions)
withLaysEggsIfNotBlocked(birdType, actions);
withCanFlyIfNotBlocked(birdType, actions);
withCanSwimIfNotBlocked(birdType, actions);
return birdType;
}
const wisdom = createSeabird({
family: 'Albatross',
genus: 'North Pacific albatross',
species: 'Laysan albatross',
name: 'Wisdom',
sex: 'female',
age: 70,
});
console.log({ wisdom });
console.log('wisdom.valueOf() ...', wisdom.valueOf());
console.log('wisdom.monitorActions() ...', wisdom.monitorActions());
console.log('wisdom.startFlying();')
wisdom.startFlying();
console.log('wisdom.startFlying();')
wisdom.startFlying();
console.log('wisdom.startSwimming();')
wisdom.startSwimming();
console.log('wisdom.startLayingEggs();')
wisdom.startLayingEggs();
console.log('wisdom.stopFlying();')
wisdom.stopFlying();
console.log('wisdom.stopFlying();')
wisdom.stopFlying();
console.log('wisdom.startSwimming();')
wisdom.startSwimming();
console.log('wisdom.startSwimming();')
wisdom.startSwimming();
console.log('wisdom.startLayingEggs();')
wisdom.startLayingEggs();
console.log('wisdom.startFlying();')
wisdom.startFlying();
console.log('wisdom.stopSwimming();')
wisdom.stopSwimming();
console.log('wisdom.stopSwimming();')
wisdom.stopSwimming();
console.log('wisdom.startLayingEggs();')
wisdom.startLayingEggs();
console.log('wisdom.startLayingEggs();')
wisdom.startLayingEggs();
console.log('wisdom.valueOf() ...', wisdom.valueOf());
console.log('wisdom.monitorActions() ...', wisdom.monitorActions());
.as-console-wrapper { min-height: 100%!important; top: 0; }
Close with one of the above initial comments ...
"2/2 ... Just take advantage of the language's flexibility and expressiveness. Just be aware of the advantages, pitfalls and comprehensibility (to others) of your modeling approach(es). And once this is checked don't worry about [too strict]* Crockford disciples (or any other school / religion / cult). A good teacher shows you a [path]* and allows / encourages you to discover or follow your own, once you understood what the base/basics are good for."
I have a method in my service where i wish to return true or false according to value gotten and access the value in my component.
My service file:
checkProfile (user) {
let p = {
username: user,
key: '00'
}
this.postMethod(p).subscribe(
d => {
return d['code'] == '000' ? true : false;
}
)
}
my component where i wish to know the value of the above:
let a = myService.checkProfile(this.user);
How do i get the method to return true or false so that i may be able to access it via the variable a. Right now a is undefined
checkProfile should return an Observable, use map to transform the value to a boolean. Read more about it here https://www.learnrxjs.io/operators/transformation/map.html
checkProfile(user):Observable<boolean> {
let p = {
username: user,
key: '00'
}
return this.postMethod(p).pipe(map(d=>{
return d['code'] == '000' ? true : false
}))
}
and in the component
export class YourComponent{
check$:Observable<boolean> // if you want it to subscribe multiple times
constructor(private myService:MyService){
this.check$: Observable<boolean> = myService.checkProfile(this.user); // if
you want it to subscribe multiple times
}
// the other approach, if you only want to subscribe here
someMethod(){
this.myService.checkProfile(this.user).subscribe((check:boolean)=>{
let a =check // here you have the value in ts.
})
}
}
I think you should return your postMethod
like this:
checkProfile (user) {
let p = {
username: user,
key: '00'
}
return this.postMethod(p).subscribe(
d => {
return d['code'] == '000' ? true : false;
}
)
}
You could turn checkProfile into a Promise so you can then use async/await in other function calls
async checkProfile (user) {
let p = {
username: user,
key: '00'
}
const d = await this.postMethod(p).toPromise()
return d['code'] == '000' ? true : false;
}
let a = await myService.checkProfile(this.user);
You will also want to mark your component function as async. In my opinion this is all a lot easier as you don't have to handle multiple subscriptions and remembering to unsubscribe.
I am working with some state management application where I have a data structure as follows
const mainObject = {
firstLevel: {
secondLevel: {
thirdLevel: {
actualProperty: 'Secret'
}
}
},
firstLevelUntouched:{
secondLevelUntouched:{
thirdLevelUntouched:{
untouchedProperty:'I don`t want to change'
}
}
}
};
I want to change the actualProperty to a new value which out a deepClone
I did it with the following code
const modified = {
...mainObject,
...{
firstLevel: {
...mainObject.firstLevel,
...{
secondLevel: {
...mainObject.firstLevel.secondLevel,
thirdLevel: {
...mainObject.firstLevel.secondLevel.thirdLevel,
actualProperty: 'New secret'
}
}
}
}
}
}
But its looks like Bulky Code. So I need to write a function like
modified = myCustomAssignment(mainObject, ['firstLevel', 'secondLevel', 'thirdLevel', 'actualProperty'], 'New secret')
Can anyone help me on this?
You could use a simple traversal function for this that just traverses the passed properties until it arrives as the final one, then sets that to the new value.
function myCustomAssignment(mainObject, propertyList, newValue) {
const lastProp = propertyList.pop();
const propertyTree = propertyList.reduce((obj, prop) => obj[prop], mainObject);
propertyTree[lastProp] = newValue;
}
You could even add propertyList = propertyList.split('.') to the top of this function so the list can be passed in as an easy-to-read string, like myCustomAssignment(mainObject, 'firstLevel.secondLevel.thirdLevel.actualProperty', 'new value') if you wanted that.
export function mutateState(mainObject: object, propertyList: string[], newValue: any) {
const lastProp = propertyList.pop();
const newState: object = { ...mainObject };
const propertyTree =
propertyList
.reduce((obj, prop) => {
obj[prop] = { ...newState[prop], ...obj[prop] };
return obj[prop];
}, newState);
propertyTree[lastProp] = newValue;
return newState as unknown;
}
This fixed my issue. thanks all..