Home > Software design >  Pass a property as parameter and update it inside the function in typescript
Pass a property as parameter and update it inside the function in typescript

Time:10-28

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.

Profile view


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.

I've checked the Error

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.

  • Related