3

I wanted to ask the better approach of my calling.

lets say i have a class Human

export default class Human {
    private firstname: string;
    private lastname: string;

    public getFirstName():string {
      return this.firstname;
    }

    public setFirstName(val : string ) {
      this.firstname = val;
    }

    public getLastName():string {
      return this.lastname
    }

    public setLastName(val : string ) {
      this.lastname = val;
    }

    public getFullName(): {
      return `${this.firstname} + ' ' + ${this.lastname}; 
    }
}

TS :

human: Human;

 // below some http call which asigns human class to response...
// Response variables assigned to class variables , f.e : human.setFirstName(data.firstname)

HTML :

<h2>{{human.getName()}}</h2>

And as it seems logical, everything would be good except it calls that function on each change, each second. What is the better approach of doing the same thing ? (I dont want to have variables because back-end changes a lot and I want to have all functions there). + I must change all the variables in whole front-end app html if I use variables, with functions I only have to change function inner variable.

5
  • Perhaps use Observables and | async in the template? Commented Feb 5, 2020 at 16:53
  • I use observables, I subscribe to backend response , I get the response and I assign it to class. From where I call these variables. Commented Feb 5, 2020 at 16:54
  • are you familiar with get and set in typescript? typescriptlang.org/docs/handbook/classes.html#accessors Commented Feb 5, 2020 at 17:15
  • Getters and setters you mean? Yes I am , but never tryed to make an class with it, for consuming apis, what is your experience about performance ? Commented Feb 5, 2020 at 18:15
  • the issue here is that you haven't built an angular friendly view model. Your view model should contain the simple data you need to display as properties, not functions. get used to doing this if you intend to use angular Commented Feb 5, 2020 at 19:43

4 Answers 4

3

the approach here is that you need to be building angular friendly view models. Function calls in template are generally bad practice, and as such, your view models should be avoiding the need. It's as simple as this:

export class HumanVm {
   firstName: string
   lastName: string
   fullName: string

   constructor(human: Human) {
     this.firstName = human.firstName
     this.lastName = human.lastName
     this.fullName = `${this.firstname} ${this.lastname}`
   }

}

then if something needs to change app wide, you change it in your model to view model mapping in the constructor. This bit of up front work is how you insulate yourself from frequent backend model changes on the front end and still maintain good angular practices.

Sign up to request clarification or add additional context in comments.

2 Comments

dev.to/florimondmanca/… - so this is the right way ?
I’d say that’s close to it. But they’re more adapting the response into a model in that post. I don’t usually do that (though you could). Instead I adapt my models into specific view models which are of course view specific as you can often have multiple views of the same data in an application, and it’s helpful to have both the backend model representation and ability to convert that into various view models as needed
0

An approach I have come across is to create a pure pipe. It will only run if the input changes, otherwise it will return a cached result.

Your component could be:

<h2>{{ human | humanFormatPipe : name }}</h2>

The pipe will take an argument which will decide which property of human to return.

3 Comments

Sorry but If I have 15 classes with 8 variables, I have to make 15x8 pipes for each ?
Or You mean each class will have one pipe ?
+ it seems you still using "name" which means it is variable and must be changed when back-end changes. I want to skip that part where you have to edit html after variable changes in backend
0

If you have any methods in the template, these methods will be run always with detectChanges.

If you want to improve performance you should use changeDetection: ChangeDetectionStrategy.OnPush in your components.

@Component({
  selector: '.....',
  templateUrl: '.....',
  styleUrls: ['.....'],
  changeDetection: ChangeDetectionStrategy.OnPush
})

When you use subscribe in component, you should write formatted data to component properties and these properties should be used in the template. In subscribe, after whole operations, you should run changeDetectorRef.detectChanges. This method tell template that the template have to refresh data.

The template only changes data on view, which was changed. When you use a method in the template, the template doesn't know the current value so have to execute this method.

If a particular component declares the OnPush strategy, the Zone checks this component and its children only if the bindings to the component’s input properties have changed, or if the component uses AsyncPipe, and the corresponding observable started emitting values.

2 Comments

Does changeDetection: ChangeDetectionStrategy.OnPush somehow affects other things ? I mean will it change something that will came with bugs ?
In some cases, If you don't run detectChanges manually, you won't have correct data on the view.
0

Do you need the class in your component? It sounds like you need to map the http call to the required fields into a view model for your component. An interface would suffice.

If you use the http observable from the service and pipe it to the map operator to transform it to the structure you need in the component.

You can also use the async pipe and enable ChangeDetectionStrategy.OnPush to limit the change detection cycle.

e.g.

@Component({
  selector: 'human',
  template: `<h1>Hello {{ (human$ | async).name }}!</h1>`,
  styles: [`h1 { font-family: Lato; }`],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class HumanComponent implements OnInit  {

  human$: Observable<{name: string}>;

  constructor(private humanService: HumanService) {
  }

  ngOnInit() { 
    this.human$ = this.humanService.getHuman()
      .pipe(map((human: Human) => ({ name: human.FullName })));
  }
}

and a StackBlitz to show how it fits together.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.