J'ai un champ de saisie où l'utilisateur peut entrer le taux de quelque chose.
Lorsque l'utilisateur entre une valeur, je souhaite qu'elle s'affiche après l'arrondi, puis la valeur mise à jour soit stockée sur le modèle de support dans le fichier ts
.
Utiliser un tube Angular angulaire n'est pas bon pour cela car un tube dans une direction et la valeur mise à jour ne seront pas reflétés sur le modèle.
Donc, pour le rendre bidirectionnel, je fais ce qui suit:
<input type="text" [ngModel]="model.rate" (ngModelChange)="model.rate=roundRate($event)" name="rate" />
La fonction roundDate
ressemble à ceci
roundRate(value) {
return Math.round(value);
}
Maintenant, lorsque j'entre des valeurs telles que 5,6, 7,8, 9,5, etc., elles sont toutes arrondies, affichées et stockées sur le modèle à 6, 8 et 10 respectivement, ce qui est le comportement attendu.
Le problème commence lorsque j'entre 2.1, 3.4, 5.3 etc. Dans ce cas, la fonction roundRate
est appelée et renvoie la valeur après l'arrondi. Mais les valeurs affichées à l'écran sont toujours les anciennes valeurs (2.1, 3.4, 5.3)
J'ai inspecté l'élément input
sur Chrome et j'ai constaté que la propriété ng-reflect-model
Était mise à jour aux valeurs attendues (2, 3, 5).
<input _ngcontent-c39="" name="rate" type="text" ng-reflect-name="rate" ng-reflect-model="5" class="ng-valid ng-dirty ng-touched">
Quelqu'un peut-il expliquer ce qui se passe ici et malgré la mise à jour de la propriété ng-reflect-model
, Pourquoi l'écran affiche toujours les anciennes valeurs?
Merci de votre aide!
Pour une implémentation plus propre, utilisez simplement la propriété (change)
@Output
Et [(ngModel)]
. L'implémentation de roundRate
changera quelque chose comme ceci:
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
model = { rate: null };
roundRate() {
this.model.rate = Math.round(+this.model.rate);
}
}
Et dans le modèle:
<input type="text" [(ngModel)]="model.rate" (change)="roundRate()" name="rate" />
PS: Cela ne mettra à jour la valeur qu'une fois que vous blur
à partir de votre champ de saisie
Voici un exemple StackBlitz pour votre référence.
Commencez par regarder de plus près la directive ngModel
API , vous verrez que ngModel
est @Input
Contraignant qui accepte une valeur comme variable model
. Au moment de l'initialisation ngModel
contrôlez-le crée FormControl
implicitement.
public readonly control: FormControl = new FormControl();
La magie de la mise à jour de la valeur model
se produit à partir de ngOnChanges
hook , de cette façon, il synchronise la valeur de la vue avec la valeur model
. Si vous regardez de plus près le crochet ngOnChanges
, vous constaterez que cela valide l'entrée et applique également d'autres vérifications, après quoi il vérifie strictement que si la valeur de ngModel
la valeur est vraiment modifiée à l'aide de isPropertyUpdated
méthode.
ngOnChanges - Directive ngModel
ngOnChanges(changes: SimpleChanges) {
this._checkForErrors();
if (!this._registered) this._setUpControl();
if ('isDisabled' in changes) {
this._updateDisabled(changes);
}
if (isPropertyUpdated(changes, this.viewModel)) {
this._updateValue(this.model); // helps to update
this.viewModel = this.model;
}
}
private _updateValue(value: any): void {
resolvedPromise.then(() => {
// set value will set form control
this.control.setValue(value, {emitViewToModelChange: false});
});
}
Mais pour y arriver Angular devrait reconnaître les changements pendant le cycle de détection des changements. Et puisque nous n'avons pas changé notre modèle, il ne déclenchera pas le hook ngOnChanges:
Ce que j'ai expliqué jusqu'à présent, c'était la partie API. Revenons à la question.
Essayez ci-dessous extrait de stackblitz , quelle serait notre attente. Lors d'un changement de valeur d'entrée, il doit définir cette valeur sur 10
Lui-même.
<input type="text"
[ngModel]="model.rate"
(ngModelChange)="model.rate = 10"
name="rate" />
Malheureusement, cela ne se produit pas de cette façon, vous verrez que lors de la frappe initiale d'un nombre, cela changera la valeur d'entrée en 10
Et plus tard, tout ce que vous saisirez continuera à s'ajouter à la saisie de numéro. Ahh, je me demande pourquoi?
Revenons à la question d'origine,
<input type="text"
[ngModel]="model.rate"
(ngModelChange)="model.rate=roundRate($event)"
name="rate" />
{{model.rate}}
ngModel
utilisé comme liaison unidirectionnelle. Le comportement attendu est que toutes les valeurs affectées au model.rate
Doivent être reflétées à l'intérieur du input
. Essayons d'entrer 1.1, vous verrez qu'il nous montre la valeur 1.1
. Maintenant, essayez de saisir 1.2
, Les résultats en 1,2 résultent en 1
. Vous vous demandez pourquoi? Mais les liaisons model.rate
Sont certainement mises à jour correctement. De même, vérifiez 4.6
, 4.8
Donne 5 qui fonctionne parfaitement.
Décomposons l'exemple ci-dessus, que se passe-t-il lorsque vous essayez d'entrer 1.1
.
1
=> model.rate devient 1
1.
=> model.rate stay 1
1.1
=> model.rate stay 1
Finalement, lorsque vous tapez 1.1
Ou 1.2
, La valeur du modèle reste 1
Car nous Math.round
Valeur. Puisqu'il ne s'agit pas d'une mise à jour de la valeur model.rate
, Tout ce que vous entrez plus loin est simplement ignoré par la liaison ngModel
et affiché dans le champ input
.
Vérifiez 4.6
, 4.8
Fonctionne parfaitement. Pourquoi? décomposer étape par étape
4
=> model.rate devient 4
4.
=> model.rate stay 4
4.6
=> model.rate devient 5
Ici, lorsque vous entrez 4.6
Dans la zone de texte, la valeur de Math.round
Devient 5
. qui est une modification de la valeur de model.rate
(ngModel) entraînerait une mise à jour de la valeur du champ input
Maintenant, recommencez à lire la réponse, l'aspect technique expliqué initialement sera également effacé.
Remarque: Lors de la lecture d'une réponse, suivez les liens fournis vers l'extrait de code, cela peut vous aider à la comprendre plus précisément.
Pour le faire fonctionner, vous pouvez essayer de mettre à jour vos champs sur blur
/change
où cet événement se déclenche sur focus hors de fields
comme Sid's answer
. Cela a fonctionné parce que vous mettez à jour le modèle une fois que le champ est concentré.
Mais cela ne fonctionne qu'une seule fois. Pour garder les mises à jour constamment, nous pouvons faire quelques trucs:
this.model.rate = new String(Math.round(value));
ce qui entraînera une nouvelle référence d'objet chaque fois que nous arrondirons notre valeur.
In Angular la stratégie de détection de changement aide à refléter les changements sur l'interface utilisateur.
Veuillez utiliser le code ci-dessous:
Étape 1: Importez ChangeDetectorRef
dans votre composant
import { ChangeDetectorRef} from angular/core';
Étape 2: Créer une instance de ChangeDetectorRef
sur le constructeur.
constructor(private ref: ChangeDetectorRef){
}
Étape 3: Appelez où vous mettez à jour la valeur.
this.ref.detectChanges();
Nous pouvons également obtenir sa valeur en utilisant $ event et non en utilisant ngModel-
component.html
<table>
<tbody>
<tr>
<td colspan="2" style="width:100px;height:38px;"><input type = "text" (change)="enterDirectRowNumberResponse(data,$event.target.value)"></td></tr>
</tbody
</table>
component.ts
enterDirectRowNumberResponse(data,event){
console.log ("Inside enterDirectRowNumberResponse",event)
console.log ("data = ", data );
}