Angular ng-repeat con ng-form, accesso alla convalida nel controller
-
21-12-2019 - |
Domanda
Sto cercando di generare un elenco modificabile usando ng-repeat
.Voglio ricordare all'utente di aggiornare eventuali modifiche prima di andare avanti, quindi sto usando ng-form
per creare moduli "nidificati" al volo perché la documentazione dice che posso quindi utilizzare la convalida su questi input creati dinamicamente.
Mentre sembra funzionare all'interno dell'HTML, non vedo come accedere a quei moduli creati dinamicamente e ai relativi campi di convalida nel controller.In particolare, quando l'utente cambia l'input, uso la proprietà form dirty dirty per far apparire un pulsante per dire all'utente di eseguire il commit delle modifiche.Finora, così buono.Tuttavia, una volta che le modifiche sono state impegnate, voglio $setPristine()
sul campo per indicare che le modifiche sono state impostate.Potrebbero esserci altri modi per garantire che le modifiche vengano impegnate su ciascun input prima di consentire il commit del modulo principale, ma questo è stato il meglio che ho potuto trovare.
Sfortunatamente, anche se la documentazione dice che se nomino il ng-form verrà propagato al $scope
oggetto, non riesco a trovare un modo per accedervi. $scope.dynamic_form
non è definito.
Ecco un plunker che mostra cosa intendo:
Grazie!
[EDIT] Solo per aggiungere al problema, cosa funziona per questo esempio specifico è aggiungere al ng-click
sull'input creato dinamicamente:
ng-click="namesForm.name.$setPristine();clean()"
Ma non ho ancora accesso al modulo creato dinamicamente nel controller.Vorrei, ad esempio, aggiungere un osservatore al namesForm.name.$pristine
in modo che io possa impostare il mainForm.$setValidity(false)
ogni volta che il sub-form è $dirty
per impedire all'utente di inviare il modulo principale fino a quando tutte le modifiche del modulo secondario non sono state eseguite.
Quindi, in poche parole, il problema è come accedere in un controller padre ai valori di convalida di una ngForm nidificata creata dinamicamente?
Soluzione
Aggiornato 2015-01-17:
Come sottolineato da Leblanc Meneses nei commenti Angolare 1.3 ora supporta l'interpolazione con form
, ngForm
e input
direttiva.
Ciò significa che l'uso di espressioni per nominare i tuoi elementi:
<div ng-form="namesForm_{{$index}}" ng-repeat="name in names">
<input type="text"
name="input_{{$index}}_0"></input>
<!-- ... -->
</div>
funzionerà come previsto:
$scope['namesForm_0']
$scope.namesForm_1
// Access nested form elements:
$scope.namesForm_1.input_1_0
...
Risposta originale per Angular <= 1.2:
Lavorare con le forme e il ngFormController
può diventare difficile abbastanza rapidamente.
È necessario essere consapevoli del fatto che è possibile aggiungere dinamicamente elementi del modulo e input ma non possono essere dinamicamente prende - l'interpolazione non funziona nel ngForm
o name
direttiva.
Ad esempio, se hai provato a nominare dinamicamente i moduli nidificati in questo modo:
<div ng-form="namesForm_{{$index}}" ng-repeat="name in names">
<!-- ... -->
</div>
Invece di rendere disponibili tutti i moduli nidificati nell'ambito in questo modo: scope['namesForm_0']
avresti solo accesso al singolo (ultimo) modulo con il nome letterale scope['namesForm_{{$index}}']
.
Nella tua situazione è necessario creare una direttiva personalizzata che verrà aggiunta insieme a ngForm
per gestire l'impostazione $pristine$
e $invalid
per quell'istanza di forma.
JavaScript:
Questa direttiva vigilerà sulla $dirty
stato della sua forma per impostare il $validity
per evitare la presentazione quando sporco e gestire l'impostazione del $pristine
stato quando viene premuto il pulsante' clean'.
app.directive('formCleaner', function(){
return {
scope: true,
require: '^form',
link: function(scope, element, attr){
scope.clean = function () {
scope.namesForm.$setPristine();
};
scope.$watch('namesForm.$dirty', function(isDirty){
scope.namesForm.$setValidity('name', !isDirty);
});
}
};
});
HTML:
Quindi l'unica modifica al tuo HTML è aggiungere il formCleaner
direttiva.
Quindi cambia il tuo HTML originale da questo:
<body ng-controller="MainCtrl">
<form name="mainForm" submit="submit()">
<h3>My Editable List</h3>
<div ng-form="namesForm"
ng-repeat="name in names">
<!-- ... -->
</div>
<button class="btn btn-default" type="submit">Submit</button>
</form>
</body>
a questo, aggiungendo form-cleaner
accanto ng-form
:
<body ng-controller="MainCtrl">
<form name="mainForm" submit="submit()">
<h3>My Editable List</h3>
<!-- Add the `form-cleaner` directive to the element with `ng-form` -->
<div form-cleaner
ng-form="namesForm"
ng-repeat="name in names">
<!-- ... -->
</div>
<button class="btn btn-default" type="submit">Submit</button>
</form>
</body>
Ecco un Plunker aggiornato che mostra il nuovo comportamento: http://plnkr.co/edit/Lxem5HJXe0UCvslqbJr3?p=preview