I learnt Vue.js first, and now have a project in Angular 4 so I just learnt Angular. I find everything is not that different from Vue except the "Computed Property". In Vue, I can create a computed property that listens to changes of other properties and run calculations automatically.
For example(in Vue 2):
computed: { name(){ return this.firstname + ' ' + this.lastname; } }
The name property will only recalculate when one of firstname or lastname change. How to handle this in Angular 2 or 4 ?
Angular JS is a web application framework, whereas Vue JS is a progressive framework perfect for building single-page applications. Angular JS is opinionated, which means there is a certain way application should be structured, whereas Vue JS is modular and flexible.
Reactivity of servicesYour services are stateful, but they are not reactive, like Angular. It means updating you service variables will not trigger change detection (thus, no UI update).
The Basics of Vue Reactivity Simply put, a computed property's dependencies are the reactive values that help the property that determine the value that is returned. If none of these change, then, again, the cached value will be returned. If no reactive dependency is changed, a computed property is not recalculated.
Computed props can react to changes in multiple props, whereas watched props can only watch one at a time. Computed props are cached, so they only recalculate when things change. Watched props are executed every time. Computed props are evaluated lazily, meaning they are only executed when they are needed to be used.
While this is already answered but I think this is not very good answer and users should not use getters as computed properties in angular. Why you may ask? getter is just sugar syntax for function and it will be compiled to plain function, this means that it will be executed on every change detection check. This is terrible for performance because property is recomputed hundred of times on any change.
Take a look at this example: https://plnkr.co/edit/TQMQFb?p=preview
@Component({ selector: 'cities-page', template: ` <label>Angular computed properties are bad</label> <ng-select [items]="cities" bindLabel="name" bindValue="id" placeholder="Select city" [(ngModel)]="selectedCityId"> </ng-select> <p *ngIf="hasSelectedCity"> Selected city ID: {{selectedCityId}} </p> <p><b>hasSelectedCity</b> is recomputed <b [ngStyle]="{'font-size': calls + 'px'}">{{calls}}</b> times</p> ` }) export class CitiesPageComponent { cities: NgOption[] = [ {id: 1, name: 'Vilnius'}, {id: 2, name: 'Kaunas'}, {id: 3, name: 'Pabradė'} ]; selectedCityId: any; calls = 0; get hasSelectedCity() { console.log('hasSelectedCity is called', this.calls); this.calls++; return !!this.selectedCityId; } }
If you really want to have computed properties you can use state container like mobx
class TodoList { @observable todos = []; @computed get unfinishedTodoCount() { return this.todos.filter(todo => !todo.finished).length; } }
mobx has @computed decorator so getter property will be cached and recalculated only when needed
I will try to improve upon Andzej Maciusovic
's hoping to obtain a canonical answer. Indeed VueJS has a feature called computed property that can be quickly shown using an example:
<template> <div> <p>A = <input type="number" v-model="a"/></p> <p>B = <input type="number" v-model="b"/></p> <p>C = <input type="number" v-model="c"/></p> <p>Computed property result: {{ product }}</p> <p>Function result: {{ productFunc() }}</p> </div> </template> <script> export default { data () { return { a: 2, b: 3, c: 4 } }, computed: { product: function() { console.log("Product called!"); return this.a * this.b; } }, methods: { productFunc: function() { console.log("ProductFunc called!"); return this.a * this.b; } } } </script>
Whenever the user changes input value for a
or b
, both product
and productFunc
are logging to console. If user changes c
, only productFunc
is called.
Coming back to Angular, mobxjs really helps with this issue:
npm install --save mobx-angular mobx
observable
and computed
attributes for bound propertiesTS file
import { observable, computed } from 'mobx-angular'; @Component({ selector: 'home', templateUrl: './home.component.html', animations: [slideInDownAnimation] }) export class HomeComponent extends GenericAnimationContainer { @observable a: number = 2; @observable b: number = 3; @observable c: number = 4; getAB = () => { console.log("getAB called"); return this.a * this.b; } @computed get AB() { console.log("AB called"); return this.a * this.b; } }
Markup
<div *mobxAutorun> <p>A = <input type="number" [(ngModel)]="a" /> </p> <p>B = <input type="number" [(ngModel)]="b" /> </p> <p>C = <input type="number" [(ngModel)]="c" /> </p> <p> A * B = {{ getAB() }}</p> <p> A * B (get) = {{ AB }}</p> </div>
If a
or b
is changed, AB
is called once and getAB
several times. If c
is changed, only getAB
is called. So, this solution is more efficient even when computation must be performed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With