Kann ich im Controller auf ein Formular zugreifen?

152

Ich verwende derzeit Folgendes.

$scope.$$childHead.customerForm[firstName], damit:

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

Dies funktioniert jedoch nur in Chrome. Jetzt habe ich folgendes versucht:

$scope.editCustomerForm[firstName], damit:

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

Welches funktioniert nicht. Beachten Sie, dass sich mein Formular in einem Foundation Tab befindet. Wie kann ich darauf zugreifen firstName?

EDIT : Es sieht so aus, als ob das formnicht zum hinzugefügt wirdscope wenn es sich in einem Foundation Tab befindet.

Hat jemand eine Lösung dafür?

Vincent
quelle

Antworten:

210

Obwohl in anderen Kommentaren darauf hingewiesen, dachte ich, ich würde es ein wenig für diejenigen buchstabieren, die die "Controller As" -Syntax verwenden:

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

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

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

</div>

Dann können Sie in Ihrem Code wie folgt auf den FormController zugreifen:

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

    function saveChanges() {

       if(vm.myForm.$valid) { 
            // Save to db or whatever.
            vm.myForm.$setPristine();
       }
}
Slopapa
quelle
Soweit ich sehen kann, kann die Vorlage die "saveChanges" -Methode nicht aufrufen, da sie nicht für die Vorlage verfügbar ist
Spock
2
Die "saveChanges" -Methode wird in Zeile 3 des Javascript angezeigt oder verstehe ich das falsch?
Slopapa
3
Dies ist gut, da es bedeutet, dass Sie vermeiden können, den gesamten $ scope zu injizieren, was meiner Meinung nach sauberer ist
72GM
2
Wie testest du das in Jasmin? In meiner Spezifikation ist vm.myForm undefiniert
bahrieinn
1
Dies sollte in den offiziellen Dokumenten für 1.5.X vermerkt werden, in denen Komponenten und es6 ausgeführt werden. Vielen Dank, Sir
MatanCo
91

Sie können das Formular an ein Objekt anhängen, das in einem übergeordneten Controller definiert ist. Dann können Sie Ihr Formular auch von einem untergeordneten Bereich aus erreichen.

Übergeordneter Controller

$scope.forms = {};

Einige Vorlagen in einem untergeordneten Bereich

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

Das Problem ist, dass das Formular nicht in dem Moment definiert werden muss, in dem der Code in der Steuerung ausgeführt wird. Also muss man so etwas machen

$scope.$watch('forms.form1', function(form) {
  if(form) {
    // your code...
  }
});
ondrs
quelle
10
Ich würde vorschlagen, mit var watcher = $scope.$watcherund innerhalb der if-Anweisung watcher () auszuführen, um die Uhr zu lösen. Dies macht es zu einer einmaligen Uhr, so dass Sie nicht jeden Digest sehen, nachdem er eingestellt wurde
willJk
91

Wenn Sie das Formular zu Validierungszwecken an den Controller übergeben möchten, können Sie es einfach als Argument an die Methode übergeben, die die Übermittlung verarbeitet. Verwenden Sie den Formularnamen. Für die ursprüngliche Frage wäre dies ungefähr so:

<button ng-click="submit(customerForm)">Save</button>
Anthony Shull
quelle
13
Um zu verdeutlichen, dass Ihr Formular für zukünftige Leser ähnlich <form name="myform"></form>oder sogar ähnlich benannt / definiert ist , <div ng-form name="myform"></div>lautet Ihr Klickereignis wie folgt : ng-click="submit(myform)". Dann können Sie das Eckige Form zugreifen Objekt in der Klick - Funktion wie: $scope.submit = function (form) { if (form.$valid) {usw.
Matty J
Ich finde hier ein Problem - sagen wir, das Formular enthält eine Dropdown-Liste. Mit der obigen Methode erhalte ich nur den Ansichtswert und nicht den genauen Wert, den ich benötige. Oder mache ich etwas falsch, wird eine Geige hinzufügen.
Swateek
82

Etwas spät für eine Antwort, aber mit der folgenden Option. Es funktioniert bei mir, ist mir aber nicht sicher, ob es der richtige Weg ist oder nicht.

Aus meiner Sicht mache ich das:

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

Und in der Steuerung:

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

Nachdem ich dies getan habe, habe ich mein Formular in meiner Controller-Variablen, die ist $scope.myForm

Atul Chaudhary
quelle
1
Das einzige, was ich hinzufügen möchte, ist sicherzustellen, dass dies am Ende des Formulars steht.
smb
Die Position von <div ng-init = "setForm (formName);"> </ div> spielt keine Rolle. Pass nur auf, dass es in Form ist.
waqas
1
gut, aber ich würde eine einfachere Lösung bevorzugen: ng-init = "$ parent.myForm = formName" Ohne die Notwendigkeit, den Controller zu ändern Hinweis: Es funktioniert nur mit direktem Controller, im Gegensatz zu der obigen Lösung
Mastilver
Nachdem ich die anderen Methoden ausprobiert hatte, entschied ich mich für diese, da das nameAttribut genau das sein kann, was ich möchte. Das Problem mit den anderen Dummy-Objekt-Lösungen besteht darin, dass, wenn diese Komponente in einer anderen Komponente mit einem ng-Formular verwendet wird, dieses andere ng-Formular diesen Formularnamen wörtlich verwendet. Es wird also ein Feld mit dem String-Literal-Namen (NICHT verschachtelte Eigenschaften) "dummy.myForm" geben. Ich fand das inakzeptabel.
Basil
Ich habe viele Male versucht und bin fehlgeschlagen, die controllerAs-Syntax zu verwenden (ich arbeite mit $ mdDialog). Endlich haben wir uns damit zufrieden gegeben und es hat einen tollen Job gemacht. Der einzige Hinweis ist, dass alle Controller-Initialisierungen mit einem $ Timeout ausgeführt werden müssen, da das Formular nicht verfügbar ist, wenn der Controller zum ersten Mal ausgeführt wird
Peter Nixey,
22

Um auf das Formular in Ihrem Controller zugreifen zu können, müssen Sie es einem Dummy-Scope-Objekt hinzufügen.

Etwas wie $scope.dummy = {}

Für Ihre Situation würde dies ungefähr Folgendes bedeuten:

<form name="dummy.customerForm">

In Ihrem Controller können Sie auf das Formular zugreifen, indem Sie:

$scope.dummy.customerForm

und Sie werden in der Lage sein, Dinge wie zu tun

$scope.dummy.customerForm.$setPristine()

WIKI LINK

Ein ... haben '.' in Ihren Modellen wird sicherstellen, dass die prototypische Vererbung im Spiel ist. Verwenden Sie also <input type="text" ng-model="someObj.prop1">eher als<input type="text" ng-model="prop1">

Wenn Sie wirklich ein Grundelement verwenden möchten / müssen, gibt es zwei Problemumgehungen:

1.Verwenden Sie $ parent.parentScopeProperty im untergeordneten Bereich. Dadurch wird verhindert, dass der untergeordnete Bereich eine eigene Eigenschaft erstellt. 2. Definieren Sie eine Funktion für den übergeordneten Bereich und rufen Sie sie vom untergeordneten Bereich aus auf. Übergeben Sie den primitiven Wert an den übergeordneten Bereich (nicht immer möglich).

Carsten
quelle
Wo ist der effektive Bereich zum Definieren der Formularbindung?
Gus Crawford
Es ist erwähnenswert, dass dummy.customerFormdies undefiniert sein wird, bis die Bedingungen von ng-iferfüllt sind, sollte das Formularelement eine ng-ifBedingung haben
haxxxton
22

Diese Antwort ist etwas spät, aber ich bin auf eine Lösung gestoßen, die alles viel einfacher macht.

Sie können den Formularnamen tatsächlich direkt Ihrem Controller zuweisen, wenn Sie die ControllerAs-Syntax verwenden, und ihn dann aus Ihrer "this" -Variablen heraus referenzieren. So habe ich es in meinem Code gemacht:

Ich habe den Controller über einen UI-Router konfiguriert (aber Sie können es tun, wie Sie möchten, auch im HTML-Code direkt mit so etwas wie <div ng-controller="someController as myCtrl">). So könnte es in einer UI-Router-Konfiguration aussehen:

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

und dann setzen Sie im HTML einfach den Formularnamen als "controllerAs". "name" wie folgt:

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

Jetzt können Sie in Ihrem Controller ganz einfach Folgendes tun:

angular
.module("something")
.controller("someController",
    [
       "$scope",
        function ($scope) {
            var vm = this;
            if(vm.someForm.$valid){
              // do something
            }
    }]);
FrankieAvocado
quelle
2
Obwohl dies meistens nur die gleiche Technik ist, wie einige andere Antworten vermuten lassen, ist es die beste Variante und sollte die akzeptierte Antwort sein, zumal jetzt sowieso jeder ControllerAs verwendet.
Semikolon
6

Ja, Sie können auf ein Formular im Controller zugreifen (wie in den Dokumenten angegeben ).

Außer wenn Ihr Formular nicht im Controller-Bereich definiert ist und stattdessen in einem untergeordneten Bereich definiert ist.

Grundsätzlich einige Winkel Richtlinien, wie zum Beispiel ng-if, ng-repeatoder ng-includewird ein Kind isoliert Bereich erstellen. Dies gilt auch für benutzerdefinierte Anweisungen mit einer scope: {}definierten Eigenschaft. Wahrscheinlich stehen Ihnen auch Ihre Fundamentkomponenten im Weg.

Ich hatte das gleiche Problem, als ich ein einfaches ng-ifum das <form>Tag herum einführte .

Weitere Informationen finden Sie hier:

Hinweis: Ich schlage vor, dass Sie Ihre Frage neu schreiben. Die Antwort auf Ihre Frage lautet Ja, aber Ihr Problem ist etwas anders:

Kann ich vom Controller aus auf ein Formular in einem untergeordneten Bereich zugreifen?

Worauf die Antwort einfach lauten würde: Nein .

Andre Torgal
quelle
... es sei denn, Sie richten Ihre Formulare und Ihren Controller wie in der Antwort von @ondrs (mit $scope.forms = {}und name="forms.form1") beschrieben
marapet
Bitte lesen Sie die Antwort von KhalilRavanna direkt über Ihrer. Sie können über $ scope.formName auf das Formular zugreifen. Er liefert ein funktionierendes Beispiel
micahblu
3

Fügen Sie ng-model="$ctrl.formName"Ihrem Formular ein Attribut hinzu, und im Controller können Sie auf das Formular als Objekt in Ihrem Controller zugreifenthis.formName

Dhurim Kelmendi
quelle
0

Auf jeden Fall können Sie nicht auf das Formular zugreifen, da. es wird nicht erstellt. Das DOM aus der HTML-Vorlage wird wie der Controller-Konstruktor etwas langsam geladen. Die Lösung besteht darin, zu beobachten, bis DOM geladen und der gesamte Bereich definiert ist!

im Controller:

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