Czy mogę uzyskać dostęp do formularza w kontrolerze?

152

Obecnie używam następujących.

$scope.$$childHead.customerForm[firstName], więc:

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

Ale to działa tylko w Chrome. Teraz spróbowałem następujących rzeczy:

$scope.editCustomerForm[firstName], więc:

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

Co nie działa. Zauważ, że mój formularz znajduje się wewnątrz zakładki Foundation. Jak mogę uzyskać dostęp firstName?

EDYCJA : Wygląda na formto, że nie jest dodawany do karty, scopegdy znajduje się na karcie Podstawy.

Czy ktoś ma na to rozwiązanie?

Vincent
źródło

Odpowiedzi:

210

Chociaż wspomniałem w innych komentarzach, pomyślałem, że przeliteruję to trochę dla tych, którzy używają składni „Kontroler jako”:

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

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

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

</div>

Następnie możesz uzyskać dostęp do FormController w swoim kodzie, na przykład:

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

    function saveChanges() {

       if(vm.myForm.$valid) { 
            // Save to db or whatever.
            vm.myForm.$setPristine();
       }
}
slopapa
źródło
O ile widzę, szablon nie może wywołać metody "saveChanges", ponieważ nie jest ujawniony w szablonie
Spock,
2
Metoda „saveChanges” jest ujawniona w trzecim wierszu javascript czy nie rozumiem?
slopapa
3
to jest dobre, ponieważ oznacza to, że można uniknąć wstrzykiwania całego zakresu, który moim zdaniem jest czystszy
72GM
2
Jak to sprawdzić w jaśminie? W mojej specyfikacji vm.myForm jest niezdefiniowany
bahrieinn
1
Należy to odnotować w oficjalnych dokumentach dla wersji 1.5.X, czyli sposób wykonywania komponentów i es6. dziękuję panu
MatanCo
91

Możesz dołączyć formularz do obiektu, który jest zdefiniowany w kontrolerze nadrzędnym. Wtedy możesz dotrzeć do swojego formularza nawet z zakresu podrzędnego.

Kontroler rodzica

$scope.forms = {};

Jakiś szablon w zakresie podrzędnym

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

Problem w tym, że formularz nie musi być definiowany w momencie wykonywania kodu w kontrolerze. Więc musisz zrobić coś takiego

$scope.$watch('forms.form1', function(form) {
  if(form) {
    // your code...
  }
});
ondrs
źródło
10
Sugerowałbym użycie var watcher = $scope.$watcheri wewnątrz wyrażenia if, aby wykonać watcher (), aby rozpiąć zegarek. To sprawia, że ​​jest to zegarek jednorazowy, więc nie oglądasz każdego podsumowania po ustawieniu
willJk
91

Jeśli chcesz przekazać formularz do kontrolera w celu walidacji, możesz po prostu przekazać go jako argument do metody obsługującej przesłanie. Użyj nazwy formularza, więc dla oryginalnego pytania będzie to coś takiego:

<button ng-click="submit(customerForm)">Save</button>
Anthony Shull
źródło
13
Aby wyjaśnić czytelnikom przyszłych, jeśli mówią, Twój formularz został nazwany / zdefiniowane podobny do tego <form name="myform"></form>, lub nawet <div ng-form name="myform"></div>, wówczas zdarzenie click będzie w następujący sposób: ng-click="submit(myform)". Następnie możesz uzyskać dostęp do obiektu formularza Angular w funkcji klikania, takiej jak: $scope.submit = function (form) { if (form.$valid) {itp.
Matty J
Tu jest problem - załóżmy, że w formularzu jest lista rozwijana. Użycie powyższej metody daje mi tylko wartość widoku, a nie dokładną wartość, której potrzebuję. A może robię coś złego, dodam skrzypce.
swateek
82

Trochę za późno na odpowiedź, ale przyszedł z następującą opcją. To działa dla mnie, ale nie jestem pewien, czy jest to właściwy sposób, czy nie.

Moim zdaniem robię to:

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

A w kontrolerze:

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

Teraz po zrobieniu tego mam swój formularz w mojej zmiennej kontrolera, która jest $scope.myForm

Atul Chaudhary
źródło
1
Jedyne, co do tego dodam, to upewnienie się, że znajduje się na dole formularza.
smb
Pozycja <div ng-init = "setForm (formName);"> </div> nie ma znaczenia. Tylko uważaj, aby to nie było w formie.
waqas
1
dobrze, ale wolałbym prostsze rozwiązanie: ng-init = "$ parent.myForm = formName" Bez potrzeby zmiany kontrolera Uwaga: działa tylko z bezpośrednim kontrolerem, w przeciwieństwie do powyższego rozwiązania
mastilver
Po wypróbowaniu innych metod zdecydowałem się na tę, ponieważ pozwala ona, nameaby atrybut był dokładnie taki, jak chcę. Problem z innymi rozwiązaniami obiektów fikcyjnych polega na tym, że jeśli ten komponent jest używany w innym komponencie z formą ng, to inna forma ng używa tej nazwy formy dosłownie. Więc będzie miało pole z nazwą „dummy.myForm” w postaci literału tekstowego (NIE zagnieżdżonych właściwości), uznałem to za niedopuszczalne.
Bazylia,
Wielokrotnie próbowałem i nie udało mi się użyć składni controllerAs (pracuję z $ mdDialog). W końcu się na to zgodził i wykonał świetną robotę. Należy tylko pamiętać, że wszelkie inicjalizacje kontrolera muszą być uruchamiane z limitem czasu $, ponieważ formularz nie jest dostępny po pierwszym uruchomieniu kontrolera
Peter Nixey
22

Aby mieć dostęp do formularza w kontrolerze, musisz dodać go do obiektu fikcyjnego zakresu.

Coś jak $scope.dummy = {}

W Twojej sytuacji oznaczałoby to coś takiego:

<form name="dummy.customerForm">

W swoim kontrolerze będziesz mieć dostęp do formularza poprzez:

$scope.dummy.customerForm

i będziesz mógł robić takie rzeczy

$scope.dummy.customerForm.$setPristine()

WIKI LINK

Mający '.' w modelach zapewni, że w grę wchodzi dziedziczenie prototypowe. Więc użyj <input type="text" ng-model="someObj.prop1">zamiast<input type="text" ng-model="prop1">

Jeśli naprawdę chcesz / potrzebujesz użyć prymitywu, istnieją dwa obejścia:

1. Użyj $ parent.parentScopeProperty w zakresie podrzędnym. Uniemożliwi to zakresowi podrzędnemu utworzenie własnej właściwości. 2. Zdefiniuj funkcję w zakresie nadrzędnym i wywołaj ją od dziecka, przekazując wartość pierwotną do rodzica (nie zawsze jest to możliwe)

Carsten
źródło
Gdzie jest efektywny obszar definiowania wiążącego formularza?
Gus Crawford,
warto wspomnieć, że dummy.customerFormbędzie niezdefiniowane, dopóki warunki nie ng-ifzostaną spełnione, jeśli element formularza będzie miał na to ng-ifwarunek
haxxxton
22

Ta odpowiedź jest trochę spóźniona, ale natknąłem się na rozwiązanie, które znacznie ułatwia wszystko.

W rzeczywistości możesz przypisać nazwę formularza bezpośrednio do swojego kontrolera, jeśli używasz składni controllerAs, a następnie odwołać się do niej ze swojej zmiennej „this”. Oto jak zrobiłem to w moim kodzie:

I skonfigurowany kontroler poprzez UI-routera (ale można to zrobić tylko chcesz, nawet w HTML bezpośrednio z czymś takim <div ng-controller="someController as myCtrl">) To co to może wyglądać w konfiguracji routera-ui:

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

a następnie w kodzie HTML po prostu ustaw nazwę formularza jako „kontrolerAs”. „nazwa” w następujący sposób:

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

teraz w kontrolerze możesz to zrobić w bardzo prosty sposób:

angular
.module("something")
.controller("someController",
    [
       "$scope",
        function ($scope) {
            var vm = this;
            if(vm.someForm.$valid){
              // do something
            }
    }]);
FrankieAvocado
źródło
2
Chociaż jest to w większości ta sama technika, co sugeruje kilka innych odpowiedzi, jest to najlepsza odmiana i powinna być akceptowaną odpowiedzią, zwłaszcza, że ​​wszyscy używają kontrolera Jak i tak teraz.
Średnik
6

Tak, możesz uzyskać dostęp do formularza w kontrolerze (zgodnie z dokumentacją ).

Z wyjątkiem sytuacji, gdy formularz nie jest zdefiniowany w zakresie kontrolera i zamiast tego jest zdefiniowany w zakresie podrzędnym.

Zasadniczo niektóre dyrektywy kątowe, takie jak ng-if, ng-repeatlub ng-include, utworzą izolowany zakres potomny. Podobnie będzie z wszelkimi dyrektywami niestandardowymi ze scope: {}zdefiniowaną właściwością. Prawdopodobnie na twojej drodze są również komponenty fundamentu.

Miałem ten sam problem podczas wprowadzania prostego ng-ifdookoła <form>tagu.

Zobacz te, aby uzyskać więcej informacji:

Uwaga: sugeruję ponowne napisanie pytania. Odpowiedź na Twoje pytanie brzmi tak, ale Twój problem jest nieco inny:

Czy mogę uzyskać dostęp do formularza w zakresie podrzędnym z poziomu kontrolera?

Na co odpowiedź brzmiałaby po prostu: nie .

Andre Torgal
źródło
... chyba że skonfigurujesz swoje formularze i kontroler zgodnie z opisem w odpowiedzi @ondrs (używając $scope.forms = {}i name="forms.form1")
marapet
Zobacz odpowiedź bezpośrednio nad twoją przez KhalilRavanna. Dostęp do formularza można uzyskać z poziomu $ scope.formName. Podaje działający przykład
micahblu
3

dodaj ng-model="$ctrl.formName"atrybut do swojego formularza, a następnie w kontrolerze możesz uzyskać dostęp do formularza jako obiektu wewnątrz kontrolera przezthis.formName

Dhurim Kelmendi
źródło
0

Zdecydowanie nie możesz uzyskać dostępu do formularza w zakresie bec. nie jest stworzona. DOM z szablonu html jest ładowany trochę powoli, jak konstruktor kontrolera. rozwiązaniem jest obserwowanie, aż DOM zostanie załadowany i cały zakres zdefiniowany!

w kontrolerze:

$timeout(function(){
    console.log('customerForm:', $scope.customerForm);
    // everything else what you need
});
Victor Orletchi
źródło