J'ai d'abord appris Vue.js, et j'ai maintenant un projet dans Angular 4 donc je viens d'apprendre Angular. Je trouve que tout n'est pas si différent de Vue sauf le "Propriété calculée". Dans Vue, je peux créer une propriété calculée qui écoute les modifications d'autres propriétés et exécuter des calculs automatiquement.
Par exemple (dans Vue 2):
computed: {
name(){
return this.firstname + ' ' + this.lastname;
}
}
La propriété name ne sera recalculée que lorsque l'un des changements de prénom ou de nom de famille. Comment gérer cela dans Angular 2 ou 4?
oui, vous pouvez.
Dans le fichier TS:
export class MyComponent {
get name() {
return this.firstname + ' ' + this.lastname;
}
}
et ensuite en html:
<div>{{name}}</div>
voici un exemple:
@Component({
selector: 'my-app',
template: `{{name}}`,
})
export class App {
i = 0;
firstN;
secondN;
constructor() {
setInterval(()=> {
this.firstN = this.i++;
this.secondN = this.i++;
}, 2000);
}
get name() {
return this.firstN + ' ' + this.secondN;
}
}
Bien que cela soit déjà répondu, mais je pense que ce n'est pas une très bonne réponse et les utilisateurs ne devraient pas utiliser les getters comme propriétés calculées en angulaire. Pourquoi pouvez-vous demander? getter est juste une syntaxe sucrée pour la fonction et il sera compilé en fonction simple, cela signifie qu'il sera exécuté à chaque vérification de détection de changement. C'est terrible pour les performances car la propriété est recalculée des centaines de fois à chaque changement.
Jetez un œil à cet exemple: 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;
}
}
Si vous voulez vraiment avoir des propriétés calculées, vous pouvez utiliser un conteneur d'état comme mobx
class TodoList {
@observable todos = [];
@computed get unfinishedTodoCount() {
return this.todos.filter(todo => !todo.finished).length;
}
}
mobx a @computed decorator donc la propriété getter sera mise en cache et recalculée uniquement si nécessaire
Je vais essayer d'améliorer Andzej Maciusovic
espère obtenir une réponse canonique. En effet VueJS a une fonctionnalité appelée propriété calculée qui peut être rapidement montrée à l'aide d'un exemple:
<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>
Chaque fois que l'utilisateur modifie la valeur d'entrée pour a
ou b
, product
et productFunc
se connectent à la console. Si l'utilisateur modifie c
, seul productFunc
est appelé.
Revenant à Angular, mobxjs aide vraiment avec ce problème:
npm install --save mobx-angular mobx
observable
et computed
pour les propriétés liéesFichier TS
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;
}
}
Balisage
<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>
Si a
ou b
est modifié, AB
est appelé une fois et getAB
plusieurs fois. Si c
est modifié, seul getAB
est appelé. Ainsi, cette solution est plus efficace même lorsque le calcul doit être effectué .
Dans certains cas, l'utilisation d'un Pure Pipe peut être une alternative raisonnable, cela vient évidemment avec certaines restrictions, mais cela évite au moins le coût de l'exécution de la fonction sur n'importe quel événement.
@Pipe({ name: 'join' })
export class JoinPipe implements PipeTransform {
transform(separator: string, ...strings: string[]) {
return strings.join(separator);
}
}
Dans votre modèle, au lieu d'une propriété de nom complet, vous pouvez peut-être simplement utiliser ' ' | join:firstname:lastname
. Assez triste que les propriétés calculées n'existent toujours pas pour angulaire.