The issue in a single line: Is it possible to pass a property as a parameter to a functon and update it in the function itself?
Scenario
I have a profile class in my ionic project which opens several modals that are bound to the properties in it (name, gender, email, etc). All these methods are same, the only thing that makes them different is where to set the response after the modal is closed.
One example:
async changeName() {
const modal = await this.modalCtrl.create({
component: ChangeNameModalPage,
cssClass: 'default-modal',
componentProps: {
'content': this.name // get class property value
}
});
modal.onDidDismiss().then((modalDataResponse) => {
if (modalDataResponse.data !== null && modalDataResponse.data !== undefined) {
this.name = modalDataResponse.data; // set value back to class property
}
});
return await modal.present();
}
I have 6 functions that are the same as this, the only difference is the property that is consumed/set in the function.
The problem
This view will, probably, grow up in a few months from now receiving other properties and they will do the exact same thing, where the property will be added, which will cause too much code duplication.
My idea is to make it OO so the maintenance would be easier. I'm still learning typescript and I don't know if it has something similar to java reflection, where this kind of update would be a piece of cake.
My dream world would be this (roughly speaking):
async changeField(classProperty, modalPage) {
const modal = await this.modalCtrl.create({
component: modalPage, // the component that will be used
cssClass: 'default-modal',
componentProps: {
'content': classProperty // get current property value
}
});
modal.onDidDismiss().then((modalDataResponse) => {
if (modalDataResponse.data !== null && modalDataResponse.data !== undefined) {
classProperty = modalDataResponse.data; // set back the property value
}
});
return await modal.present();
}
async changeName() {
await this.changeField(this.name, ChangeNameModalPage)
}
async changePhone() {
await this.changeField(this.phone, ChangePhoneModalPage)
}
async changeEmail() {
await this.changeField(this.email, ChangeEmailModalPage)
}
What have I found so far
Throughout several posts in stackoverflow I came to know about the generic in keyof operator, but I am able to get the value but not set it back to the property that comes as a parameter.
Is this type of interaction in the code that I'm trying to achieve possible with typescript? Or am I doing something wrong that I'm not being able to spot?
Solution
As taught by @Cerbrus in the answer below, here's the (much more tidy, beautiful and maintainable) code.
async changeName() {
await this.changeField('name', ChangeNameModalPage);
}
async changeBirthday() {
await this.changeField('birthday', ChangeBirthdayModalPage);
}
async changeCPF() {
await this.changeField('cpf', ChangeCPFModalPage);
}
async changePhone() {
await this.changeField('phone', ChangePhoneModalPage);
}
async changeEmail() {
await this.changeField('email', ChangeEmailModalPage);
}
async changeGender() {
await this.changeField('gender', ChangeGenderModalPage);
}
async changeField(classProperty: keyof this, modalPage) {
const modal = await this.modalCtrl.create({
component: modalPage,
cssClass: 'default-modal',
componentProps: {
'content': this[classProperty]
}
});
modal.onDidDismiss().then((modalDataResponse) => {
if (modalDataResponse.data !== null && modalDataResponse.data !== undefined) {
this[classProperty] = modalDataResponse.data;
}
});
return await modal.present();
}
CodePudding user response:
You were close.
Looking at your original code, you're trying to set a property on this
, in the callback.
You'll just need to specify that classProperty
is a key of this
:
async changeField(classProperty: keyof this, modalPage) {
const modal = await this.modalCtrl.create({
component: modalPage, // the component that will be used
cssClass: 'default-modal',
componentProps: {
'content': this[classProperty] // get current property value
}
});
modal.onDidDismiss().then((modalDataResponse) => {
if (modalDataResponse.data !== null && modalDataResponse.data !== undefined) {
this[classProperty] = modalDataResponse.data; // set back the property value
}
});
return await modal.present();
}
You then call that, using the key you want to update:
await this.changeField('name', ChangeNameModalPage)
(Your IDE should be giving you suggestions on what that parameter can be)
In case the this
scope changed between the changeField
function and the onDidDismiss
callback, you can use keyof MyObjectType
instead of keyof this
to use the correct type.