Puis-je accéder à un formulaire dans le contrôleur?

152

J'utilise actuellement ce qui suit.

$scope.$$childHead.customerForm[firstName], pour que:

<form name="customerForm">
  <input type="text" name="firstName" 
         ng-model="data.customer.firstName" 
         tabindex="1"  
         ng-disabled="!data.editable" 
         validationcustomer />
</form>

Mais cela ne fonctionne que dans Chrome. Maintenant, j'ai essayé ce qui suit:

$scope.editCustomerForm[firstName], pour que:

<form name="customerForm" ng-model="editCustomerForm">
  <input type="text" name="firstName" 
         ng-model="data.customer.firstName" tabindex="1"  
         ng-disabled="!data.editable" 
         validationcustomer />
</form>

Ce qui ne marche pas. Notez que mon formulaire se trouve dans un onglet Foundation. Comment puis-je y accéder firstName?

EDIT : On dirait que le formn'est pas ajouté au scopequand il se trouve dans un onglet Foundation.

Quelqu'un a-t-il une solution pour cela?

Vincent
la source

Réponses:

210

Bien que mentionné dans d'autres commentaires, j'ai pensé que je le préciserais un peu pour ceux qui utilisent la syntaxe "Controller As":

<div ng-controller="MyController as ctrl">

<form name="ctrl.myForm">
    ...inputs
    Dirty? {{ctrl.myForm.$dirty}}

    <button ng-click="ctrl.saveChanges()">Save</button>
</form>

</div>

Ensuite, vous pouvez accéder au FormController dans votre code comme:

function MyController () {
    var vm = this;
    vm.saveChanges = saveChanges;

    function saveChanges() {

       if(vm.myForm.$valid) { 
            // Save to db or whatever.
            vm.myForm.$setPristine();
       }
}
slopapa
la source
Pour autant que je puisse voir, le modèle ne peut pas appeler la méthode "saveChanges", car il n'est pas exposé au modèle
Spock
2
La méthode "saveChanges" est exposée dans la ligne 3 du javascript ou suis-je mal compris?
slopapa
3
c'est bien car cela signifie que vous pouvez éviter d'injecter toute la portée $, ce qui est plus propre à mon avis
72GM
2
Comment testez-vous cela dans le jasmin? Dans mes spécifications, vm.myForm n'est pas défini
bahrieinn
1
Cela devrait être noté dans la documentation officielle pour 1.5.X qui est la façon de faire des composants et es6. merci monsieur
MatanCo
91

Vous pouvez attacher le formulaire à un objet défini dans un contrôleur parent. Ensuite, vous pouvez accéder à votre formulaire même à partir d'une portée enfant.

Contrôleur parent

$scope.forms = {};

Un modèle dans une portée enfant

<form name="forms.form1">
</form>

Le problème est que le formulaire n'a pas à être défini au moment où le code dans le contrôleur est exécuté. Alors tu dois faire quelque chose comme ça

$scope.$watch('forms.form1', function(form) {
  if(form) {
    // your code...
  }
});
ondrs
la source
10
Je suggérerais d'utiliser var watcher = $scope.$watcheret à l'intérieur de l'instruction if, vous exécuteriez watcher () pour détacher la montre. Cela en fait une montre
unique,
91

Si vous souhaitez transmettre le formulaire au contrôleur à des fins de validation, vous pouvez simplement le transmettre en tant qu'argument à la méthode gérant la soumission. Utilisez le nom du formulaire, donc pour la question d'origine, ce serait quelque chose comme:

<button ng-click="submit(customerForm)">Save</button>
Anthony Shull
la source
13
Afin de clarifier pour les futurs lecteurs, se dire que votre formulaire est nommé / défini semblable à celui <form name="myform"></form>, ou même <div ng-form name="myform"></div>, votre événement click serait comme suit: ng-click="submit(myform)". Ensuite, vous pouvez accéder à l'objet Forme angulaire dans votre fonction de clic comme: $scope.submit = function (form) { if (form.$valid) {etc.
Matty J
Je trouve un problème ici - disons qu'il y a une liste déroulante dans le formulaire. L'utilisation de la méthode ci-dessus ne me donne que la valeur de vue et non la valeur exacte dont j'ai besoin. Ou est-ce que je fais quelque chose de mal, ajoutera un violon.
swateek
82

Un peu en retard pour une réponse mais est venu avec l'option suivante. Cela fonctionne pour moi mais je ne sais pas si c'est la bonne façon ou non.

À mon avis, je fais ceci:

<form name="formName">
    <div ng-init="setForm(formName);"></div>
</form>

Et dans le contrôleur:

$scope.setForm = function (form) {
    $scope.myForm = form;
}

Maintenant, après avoir fait cela, j'ai mon formulaire dans ma variable de contrôleur qui est $scope.myForm

Atul Chaudhary
la source
1
La seule chose que j'ajouterais à cela est d'être sûr que cela se trouve au bas du formulaire.
smb le
La position de <div ng-init = "setForm (formName);"> </div> n'a pas d'importance. Faites juste attention qu'il soit sous forme.
waqas le
1
bien, mais je préférerais une solution plus simple: ng-init = "$ parent.myForm = formName" Sans avoir besoin de changer de contrôleur Remarque: cela ne fonctionne qu'avec un contrôleur direct, contrairement à la solution ci
mastilver
Après avoir essayé les autres méthodes, j'ai opté pour celle-ci car elle permet à l' nameattribut d'être exactement ce que je veux qu'il soit. Le problème avec les autres solutions d'objet factice est que si ce composant est utilisé dans un autre composant avec une forme ng, cette autre forme ng utilise littéralement ce nom de formulaire. Donc, il aura un champ avec un nom de chaîne littérale (PAS de propriétés imbriquées) de "dummy.myForm", j'ai trouvé cela inacceptable.
Basil
J'ai essayé et échoué plusieurs fois à utiliser la syntaxe controllerAs (je travaille avec $ mdDialog). Finalement réglé pour cela et cela a fait un excellent travail. La seule note est que toutes les initialisations de contrôleur doivent être exécutées avec un délai d'attente $ car le formulaire n'est pas disponible lors de la première exécution du contrôleur
Peter Nixey
22

Pour pouvoir accéder au formulaire dans votre contrôleur, vous devez l'ajouter à un objet de portée factice.

Quelque chose comme $scope.dummy = {}

Pour votre situation, cela signifierait quelque chose comme:

<form name="dummy.customerForm">

Dans votre contrôleur, vous pourrez accéder au formulaire en:

$scope.dummy.customerForm

et vous pourrez faire des choses comme

$scope.dummy.customerForm.$setPristine()

LIEN WIKI

Avoir un '.' dans vos modèles garantira que l'héritage prototypique est en jeu. Alors, utilisez <input type="text" ng-model="someObj.prop1">plutôt que<input type="text" ng-model="prop1">

Si vous voulez / devez vraiment utiliser une primitive, il existe deux solutions de contournement:

1.Utilisez $ parent.parentScopeProperty dans la portée enfant. Cela empêchera l'étendue enfant de créer sa propre propriété. 2.Définissez une fonction sur la portée parent, et appelez-la à partir de l'enfant, en passant la valeur primitive au parent (pas toujours possible)

Carsten
la source
Où est la zone efficace pour définir la liaison de formulaire?
Gus Crawford
il vaut la peine de mentionner qu'il dummy.customerFormsera indéfini jusqu'à ce que les conditions de ng-ifsoient remplies si l'élément de formulaire a une ng-ifcondition
haxxxton
22

Cette réponse est un peu tardive, mais je suis tombé sur une solution qui rend tout beaucoup plus facile.

Vous pouvez en fait attribuer le nom du formulaire directement à votre contrôleur si vous utilisez la syntaxe controllerAs, puis le référencer à partir de votre variable "this". Voici comment je l'ai fait dans mon code:

J'ai configuré le contrôleur via ui-router (mais vous pouvez le faire comme vous le souhaitez, même dans le HTML directement avec quelque chose comme <div ng-controller="someController as myCtrl">) Voici à quoi cela pourrait ressembler dans une configuration de ui-router:

views: {
            "": {
                templateUrl: "someTemplate.html",
                controller: "someController",
                controllerAs: "myCtrl"
            }
       }

puis dans le HTML, il vous suffit de définir le nom du formulaire comme "controllerAs". "name" comme ceci:

<ng-form name="myCtrl.someForm">
    <!-- example form code here -->
    <input name="firstName" ng-model="myCtrl.user.firstName" required>
</ng-form>

maintenant, dans votre contrôleur, vous pouvez très simplement faire ceci:

angular
.module("something")
.controller("someController",
    [
       "$scope",
        function ($scope) {
            var vm = this;
            if(vm.someForm.$valid){
              // do something
            }
    }]);
FrankieAvocado
la source
2
Bien que ce soit essentiellement la même technique que plusieurs autres réponses suggèrent, c'est la meilleure variante et devrait être la réponse acceptée, d'autant plus que tout le monde utilise de toute façon controllerAs de toute façon maintenant.
Point
6

Oui, vous pouvez accéder à un formulaire dans le contrôleur (comme indiqué dans la documentation ).

Sauf lorsque votre formulaire n'est pas défini dans la portée du contrôleur et est défini dans une portée enfant à la place.

Fondamentalement, certaines directives angulaires, telles que ng-if, ng-repeatou ng-include, créeront une portée enfant isolée. Tout comme les directives personnalisées avec unscope: {} propriété définie. Probablement, vos composants de fondation sont également sur votre chemin.

J'ai eu le même problème lors de l'introduction d'un simple ng-ifautour du <form>tag.

Consultez-les pour plus d'informations:

Remarque: je vous suggère de réécrire votre question. La réponse à votre question est oui mais votre problème est légèrement différent:

Puis-je accéder à un formulaire dans une étendue enfant à partir du contrôleur?

À quoi la réponse serait simplement: non .

André Torgal
la source
... sauf si vous configurez vos formulaires et votre contrôleur comme décrit dans la réponse de @ondrs (en utilisant $scope.forms = {}et name="forms.form1")
marapet
Veuillez voir la réponse immédiatement au-dessus de la vôtre par KhalilRavanna. Vous pouvez accéder au formulaire à partir de $ scope.formName. Il fournit un exemple de travail
micahblu
3

ajoutez un ng-model="$ctrl.formName"attribut à votre formulaire, puis dans le contrôleur, vous pouvez accéder au formulaire en tant qu'objet à l'intérieur de votre contrôleur enthis.formName

Dhurim Kelmendi
la source
0

Vous ne pouvez certainement pas accéder au formulaire dans la portée bec. il n'est pas créé. Le DOM du modèle html est chargé un peu lentement comme le constructeur du contrôleur. la solution est de regarder jusqu'à ce que le DOM soit chargé et que toute la portée soit définie!

dans le contrôleur:

$timeout(function(){
    console.log('customerForm:', $scope.customerForm);
    // everything else what you need
});
Victor Orletchi
la source