wavrik
wavrik

Reputation: 361

Why in my Angular application using typescript, is not changing my variable inside a function in this situation?

I'm having a strange problem.

In my component CategoryComponent i have a variable in escope that is:

@Input() category: CategoryModel;

When i make a simple post with a service and return a data i change this variable to change so i make a function that do this:

if (category.uploading) {
  this.checkMedia(this.category, this.module);
}

Inside my function i make this:

checkMedia(model: any, module: String) {
    let counter = 0;
    var refreshIntervalId = setInterval(() => {
      const service =
        model instanceof CategoryModel
          ? this.categoryService
          : this.foodService;
      service
        .hasMedia(model)
        .pipe(
          switchMap((hasMedia) => {
            if (hasMedia) {
              return service.show(model, module);
            }
            return of(undefined);
          }),
          catchError((_) => {
            clearInterval(refreshIntervalId);
            return of(undefined);
          })
        )
        .subscribe(
          (newModel) => {
            if (newModel) {
              if(newModel.hasMedia) {
                model.hasMedia = newModel.hasMedia;
                model.images = newModel.images;
                model.uploading = false;
                console.log(model);
                console.log(this.category);
                clearInterval(refreshIntervalId);
                this.cd.detectChanges();
              }
            }
          },
          (_) => {
            clearInterval(refreshIntervalId);
          }
        );
      counter++;
      if (counter == 3) {
        if (refreshIntervalId) {
          model.uploading = false;
          clearInterval(refreshIntervalId);
          this.cd.detectChanges();
        }
      }
    }, 8000);
  }

Why in this part:

        model.hasMedia = newModel.hasMedia;
        model.images = newModel.images;
        model.uploading = false;
        console.log(model);
        console.log(this.category);
        clearInterval(refreshIntervalId);
        this.cd.detectChanges();

My screen change only if i reference this variable directly like, this.category.name = "TESTE";, for example but when i use with the paremeter model:any, it's change the global variable when i see in console.log() but in my front page the state that i want is not changing why?

Upvotes: 2

Views: 142

Answers (1)

danday74
danday74

Reputation: 57223

THE MAIN CONCERN

The bit I don't understand, what are you doing with model? Why are you not using this.model? I would expect that you would be referencing model in your HTML somewhere and would thus need to update a class member variable this.model = {blah-blah-blah}. Have you declared a public property model somewhere in your class? Why is it not being updated? In your class you need to declare:

@Input() category: CategoryModel;
model: any;

And then in your code:

this.model = something

And then in your html:

{{ model | json }}

OTHER POTENTIAL ISSUES

What change detection strategy are you using? OnPush or default? You should not use OnPush unless you are confident with it. Its possible that because you are mutating model change detection is not kicking in. You should avoid object mutation. To fix this try adding this line:

model.hasMedia = newModel.hasMedia;
model.images = newModel.images;
model.uploading = false;
model = {...model}; // creates a new object reference which will cause Angular change detection to kick in

OR

import {cloneDeep} from 'lodash-es';

model.hasMedia = newModel.hasMedia;
model.images = newModel.images;
model.uploading = false;
model = cloneDeep(model); // creates a new object reference which will cause Angular change detection to kick in

I find the second approach more readable.

This is mutation (BAD):

model.hasMedia = newModel.hasMedia;
model.images = newModel.images;
model.uploading = false;

This is not mutation (GOOD):

model = {
  ...model
  hasMedia: newModel.hasMedia;
  images: newModel.images;
  uploading: false;
}

EDIT ... USING RETURN VALUES

this.checkMedia(this.category, this.module).then((cat) => {
  this.category = cat;
});

and return a value from checkMedia

checkMedia(model: any, module: String): Promise<any> {
  return new Promise((resolve) => {
    // your existing code
    resolve(model)
  })
}

Upvotes: 0

Related Questions