¿Puedo acceder a un formulario en el controlador?

152

Actualmente estoy usando lo siguiente.

$scope.$$childHead.customerForm[firstName], así que eso:

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

Pero esto solo funciona en Chrome. Ahora probé lo siguiente:

$scope.editCustomerForm[firstName], así que eso:

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

Lo que no funciona. Tenga en cuenta que mi formulario está dentro de una pestaña de Fundación. ¿Cómo puedo acceder firstName?

EDITAR : Parece que formno se agrega a scopecuando está dentro de una pestaña de Fundación.

¿Alguien tiene una solución para esto?

Vincent
fuente

Respuestas:

210

Aunque aludido en otros comentarios, pensé en explicarlo un poco para aquellos que usan la sintaxis "Controlador como":

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

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

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

</div>

Luego puede acceder al FormController en su código como:

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

    function saveChanges() {

       if(vm.myForm.$valid) { 
            // Save to db or whatever.
            vm.myForm.$setPristine();
       }
}
slopapa
fuente
Por lo que puedo ver, la plantilla no puede llamar al método "saveChanges", ya que no está expuesta a la plantilla
Spock
2
El método "saveChanges" está expuesto en la línea 3 del javascript o ¿estoy malentendido?
slopapa
3
esto es bueno, ya que significa que puede evitar inyectar todo el alcance de $, que es más limpio en mi opinión
72GM
2
¿Cómo se prueba esto en jazmín? En mi especificación, vm.myForm no está definido
bahrieinn
1
Esto debe tenerse en cuenta en los documentos oficiales de 1.5.X que es la forma de hacer componentes y es6. gracias señor
MatanCo
91

Puede adjuntar el formulario a algún objeto que se define en un controlador principal. Entonces puede alcanzar su formulario incluso desde un ámbito secundario.

Controlador principal

$scope.forms = {};

Alguna plantilla en un ámbito secundario

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

El problema es que el formulario no tiene que definirse en el momento en que se ejecuta la codificación en el controlador. Entonces tienes que hacer algo como esto

$scope.$watch('forms.form1', function(form) {
  if(form) {
    // your code...
  }
});
ondrs
fuente
10
Sugeriría usar var watcher = $scope.$watchery dentro de la declaración if que ejecutarías watcher () para desvincular el reloj. Esto lo convierte en un reloj de una
sola
91

Si desea pasar el formulario al controlador para fines de validación, simplemente puede pasarlo como argumento al método que maneja el envío. Use el nombre del formulario, por lo que para la pregunta original sería algo como:

<button ng-click="submit(customerForm)">Save</button>
Anthony Shull
fuente
13
Para aclarar a los lectores futuros, si dicen que su forma se llama / definida similar a este <form name="myform"></form>, o incluso <div ng-form name="myform"></div>, a continuación, su evento click sería de la siguiente manera: ng-click="submit(myform)". Luego puede acceder al objeto de forma angular en su función de clic como: $scope.submit = function (form) { if (form.$valid) {etc.
Matty J
Aquí encuentro un problema, digamos que hay una lista desplegable en el formulario. Usar el método anterior solo me da el valor de vista y no el valor exacto que necesito. O estoy haciendo algo mal, agregaré un violín.
swateek
82

Un poco tarde para una respuesta, pero vino con la siguiente opción. Me está funcionando, pero no estoy seguro de si es la forma correcta o no.

En mi opinión, estoy haciendo esto:

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

Y en el controlador:

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

Ahora, después de hacer esto, tengo mi formulario en la variable de mi controlador, que es $scope.myForm

Atul Chaudhary
fuente
1
Lo único que agregaría a esto es asegurarme de que esté en la parte inferior del formulario.
smb
La posición de <div ng-init = "setForm (formName);"> </div> no importa. Solo tenga cuidado de que esté en forma.
waqas
1
bueno, pero preferiría una solución más simple: ng-init = "$ parent.myForm = formName" Sin la necesidad de cambiar el controlador Nota: solo funciona con un controlador directo, contrario a la solución anterior
mastilver
Después de probar los otros métodos, me decidí por este porque permite que el nameatributo sea exactamente lo que quiero que sea. El problema con las otras soluciones de objeto ficticio es que si este componente se usa en otro componente con una forma ng, esa otra forma ng usa este nombre de formas literalmente. Por lo tanto, tendrá un campo con un nombre de cadena literal (NO propiedades anidadas) de "dummy.myForm", encontré esto inaceptable.
Basil
Intenté y fallé muchas veces para usar la sintaxis controllerAs (estoy trabajando con $ mdDialog). Finalmente se conformó con esto e hizo un gran trabajo. La única nota es que cualquier inicialización del controlador debe ejecutarse en un tiempo de espera $ ya que el formulario no está disponible cuando el controlador se ejecuta por primera vez
Peter Nixey
22

Para poder acceder al formulario en su controlador, debe agregarlo a un objeto de alcance ficticio.

Algo como $scope.dummy = {}

Para su situación, esto significaría algo como:

<form name="dummy.customerForm">

En su controlador podrá acceder al formulario de la siguiente manera:

$scope.dummy.customerForm

y podrás hacer cosas como

$scope.dummy.customerForm.$setPristine()

WIKI LINK

Teniendo un '.' en sus modelos se asegurará de que la herencia prototípica esté en juego. Entonces, use en <input type="text" ng-model="someObj.prop1">lugar de<input type="text" ng-model="prop1">

Si realmente quiere / necesita usar una primitiva, hay dos soluciones:

1.Utilice $ parent.parentScopeProperty en el ámbito secundario. Esto evitará que el ámbito secundario cree su propia propiedad. 2.Defina una función en el ámbito primario y llámela desde el elemento secundario, pasando el valor primitivo al elemento primario (no siempre es posible)

Carsten
fuente
¿Dónde está el área efectiva para definir el enlace del formulario?
Gus Crawford
vale la pena mencionar que dummy.customerFormserá indefinido hasta que las condiciones de ng-ifque se cumplan caso de que el elemento de formulario tienen una ng-ifcondicionada a que
haxxxton
22

Esta respuesta llega un poco tarde, pero me topé con una solución que hace que todo sea MUCHO más fácil.

En realidad, puede asignar el nombre del formulario directamente a su controlador si está utilizando la sintaxis de controllerAs y luego hacer referencia a él desde su variable "this". Así es como lo hice en mi código:

Configuré el controlador a través del enrutador ui (pero puedes hacerlo como quieras, incluso en el HTML directamente con algo así <div ng-controller="someController as myCtrl">) Esto es lo que podría parecer en una configuración de enrutador ui:

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

y luego en el HTML, simplemente configura el nombre del formulario como "controllerAs". "name" de esta manera:

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

ahora dentro de su controlador puede simplemente hacer esto:

angular
.module("something")
.controller("someController",
    [
       "$scope",
        function ($scope) {
            var vm = this;
            if(vm.someForm.$valid){
              // do something
            }
    }]);
FrankieAguacate
fuente
2
Aunque esta es principalmente la misma técnica que sugieren varias otras respuestas, es la mejor variación y debería ser la respuesta aceptada, especialmente porque todos usan controladores como de todos modos ahora.
Semicolon
6

Sí, puede acceder a un formulario en el controlador (como se indica en los documentos ).

Excepto cuando su formulario no está definido en el ámbito del controlador y en su lugar se define en un ámbito secundario.

Básicamente, algunas directivas angulares, como ng-if, ng-repeato ng-include, crearán un ámbito secundario aislado. También lo harán las directivas personalizadas con una scope: {}propiedad definida. Probablemente, sus componentes básicos también están en su camino.

Tuve el mismo problema al introducir un simple ng-ifalrededor de la <form>etiqueta.

Ver estos para más información:

Nota: le sugiero que vuelva a escribir su pregunta. La respuesta a su pregunta es sí, pero su problema es ligeramente diferente:

¿Puedo acceder a un formulario en un ámbito secundario desde el controlador?

A lo que la respuesta sería simplemente: no .

Andre Torgal
fuente
... a menos que configure sus formularios y controlador como se describe en la respuesta de @ondrs (usando $scope.forms = {}y name="forms.form1")
marapet
Vea la respuesta inmediatamente superior a la suya de KhalilRavanna. Puede acceder al formulario desde $ scope.formName. Él proporciona un ejemplo de trabajo
micahblu
3

agregue ng-model="$ctrl.formName"atributo a su formulario, y luego en el controlador puede acceder al formulario como un objeto dentro de su controlador althis.formName

Dhurim Kelmendi
fuente
0

Definitivamente no puede acceder al formulario en el ámbito bec. No es creado. La plantilla DOM de html se carga un poco lentamente como el constructor del controlador. ¡la solución es mirar hasta que DOM se cargue y se defina todo el alcance!

en el controlador:

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