2

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?

1 Answer 1

1

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)
  })
}
Sign up to request clarification or add additional context in comments.

8 Comments

Thank you for you response, but is not working, i wanna change this model @Input() category: CategoryModel;, but i send this object inside a function that others model use, so i make a function called this.checkMedia(this.category, this.module); that i pass this model in parameter. So if i pass in parameter i was thinking that if use model ( parameter ) is referecing this object, so i simple use model.hasMedia = newModel.hasMedia and it is supposed to work because if use this.category.hasMedia = newModel.hasMedia ( directly, it works )
OK does ... this.category = cloneDeep(model) ... work?
this.category.hasMedia = newModel.hasMedia; ( works ), but i wanna understand why it works and not by parameter
because i want to make a function that works for both objects and not creating something like checkCategoryMedia() and checkFoodMedia() you understand?
OK I think I understand, you are passing an object by reference and its not updating the object unless you assign to it directly - how about using return values instead? see edit to my answer
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.