open modal form example bootstrap javascript forms angularjs modal-dialog

javascript - form - modal angularjs example



El objeto de formulario de diálogo modal AngularJS no está definido en el controlador (5)

La respuesta a la pregunta "¿Por qué?" es "scoping" tl; dr creó un nuevo ámbito con el diálogo modal que ocultó el objeto de formulario del alcance de su controlador.

Si simplificamos su código, obtenemos aproximadamente lo siguiente:

<div ng-ctrl="organizeCtrl"> <modal-dialog> <form name="invitationForm"> <input type="email" ng-model="invitation.email" placeholder="Enter email..." /> <input type="submit" ng-click="sendInvitation()" text="Invite!" /> <input type="button" ng-click="cancel()" text="Cancel :(" /> </form> </modal-dialog> </div>

(Esta es una versión muy simplificada que debería tener todos los componentes principales.) Ahora, veamos dónde se crean los ámbitos y qué se inyecta en ellos.

<div ng-ctrl="sendInvitationController"> <!-- scope created above with "invitation" and "sendInvitation" from sendInvitationController --> <modal-dialog> <!-- scope created above for the modal dialog transclude --> <form name="invitationForm"> <!-- add "invitationForm" to the modal dialog''s scope --> <input type="email" ng-model="invitation.email" placeholder="Enter email..." /> <input type="submit" ng-click="sendInvitation()" text="Invite!" /> <input type="button" ng-click="cancel()" text="Cancel :(" /> </form> </modal-dialog> </div>

Aquí puede ver que hay un nuevo ámbito hijo creado en el elemento <modal-dialog> y que es donde realmente se agrega el objeto invitationForm . Es por eso que no puede ver el objeto en el sendInvitationController pero puede verlo en los botones para ng-disabled . Si desea poder acceder a la construcción del formulario fuera del elemento <modal-dialog> (por ejemplo, en sendInvitationController ), tendrá que pasarlo en la llamada a la función:

<div ng-ctrl="organizeCtrl"> <modal-dialog> <form name="invitationForm"> <input type="email" ng-model="invitation.email" placeholder="Enter email..." /> <input type="submit" ng-click="sendInvitation(invitationForm)" text="Invite!" /> <input type="button" ng-click="cancel()" text="Cancel :(" /> </form> </modal-dialog> </div>

Con el controlador aceptando el formulario de invitación como un parámetro para la función sendInvitation :

app.controller(''sendInvitationController'', [''$targetOrganisationId'', ''$scope'', ..., function ($targetOrganisationId, $scope, ...) { $scope.invitation = { targetOrganisation: { id: $targetOrganisationId } }; $scope.sendInvitation = function (form) { if (form.$invalid) { return false; } // send the invitation... }; }]);

@Robin identificó la otra solución, específicamente para crear un objeto enraizado en el alcance del sendInvitationController y luego adjuntar el formulario directamente a ese objeto, confiando en el mecanismo transversal de alcance de Angular para encontrar el objeto de form en el alcance fuera del <modal-dialog> y adjunte el objeto de formulario a eso. Tenga en cuenta que si no especificó $scope.form = {} en sendInvitationController , Angular habría creado un nuevo objeto para el form en el alcance para el <modal-dialog> y aún no habría podido acceder a él en el sendInvitationController .

Esperamos que esto lo ayude a usted u otras personas a aprender sobre el alcance angular.

Tenemos una página que abre un cuadro de diálogo modal con un formulario como a continuación. Sin embargo, cuando accionamos el controlador que debe manejar la acción de forma, el objeto de forma no está definido y soy demasiado novato en angular para entender por qué ...

Este es el controlador de página principal que tiene la función para abrir el diálogo modal:

app.controller(''organisationStructureController'', [''$scope'', ..., ''$modal'', function ($scope, ..., $modal) { $scope.openInvitationDialog = function (targetOrganisationId) { $modal.open({ templateUrl: ''send-invitation.html'', controller: ''sendInvitationController'', resolve: {$targetOrganisationId: function () { return targetOrganisationId; } } } ); };

en una página como esta:

// inside a loop over organisations <a ng-click="openInvitationDialog({{organisation.id}})">Invite new member</a>

el html de invitación-diálogo se ve así:

<div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <!-- ... --> </div> <div class="modal-body"> <form name="invitationForm"> <div class="form-group"> <label for="email" style="color:white;">Email</label> <input type="email" class="form-control" autocomplete="off" placeholder="New member email" id="email" name="email" ng-model="invitation.email" required="true"/> <span class="error animated fadeIn" ng-show="invitationForm.email.$dirty && invitationForm.email.$error.required">Please enter an email address!</span> <span class="error animated fadeIn" ng-show="invitationForm.email.$error.email">Invalid email</span> </div> <!-- ... --> <div class="modal-footer"> <button type="button" class="btn btn-default" ng-click="cancel()">Cancel</button> <button type="submit" class="btn btn-primary" ng-click="sendInvitation()">Invite</button> </div> </form> </div> </div> </div>

El controlador que debe manejar la invitación está en otro lugar:

app.controller(''sendInvitationController'', [''$targetOrganisationId'', ''$scope'', ..., function ($targetOrganisationId, $scope, ...) { $scope.invitation = { // ... targetOrganisation: { id: $targetOrganisationId } }; $scope.sendInvitation = function () { // $scope.invitationForm is undefined if ($scope.invitationForm.$invalid) { return false; } // send the invitation... }; }]);

Entonces, ¿cuál es la forma correcta de obtener el alcance del formulario en el controlador?

¿Tal vez necesito inyectar $modal en sendInvitationController y agregar la función sendInvitation a él? Pero cuando lo hago, la acción nunca entra en el controlador. ¿O debo agregar la función que maneja la acción de envío a $modal.open({ ... lugar de hacer referencia al controlador? Aunque preferiría tener sendInvitationController en su propio archivo y alcance).

¡Gracias por cualquier ayuda!

EDITAR

Encontramos varias cosas que nos ayudaron a construir una solución y que podrían ayudar a alguien a responder la pregunta en sí:

  1. el objeto $scope.invitation no está indefinido en sendInvitationController pero contiene los datos correctos, mientras que $scope.invitationForm permanece indefinido.
  2. dentro de send-invitation.html podemos acceder $scope.invitationForm.$invalid y hacer la validación allí mismo: <button type="button" ng-click="sendInvitation()" ng-disabled="invitationForm.$invalid">Invite</button>

Entonces, la pregunta es: ¿por qué no se envía el enlace del objeto invitationForm al $scope mientras el modelo de formulario se une correctamente?


Tengo el mío para trabajar así:

$modal.open({ templateUrl: ''send-invitation.html'', controller: ''sendInvitationController'', scope: $scope // <-- I added this }

Sin nombre de formulario, no $parent . Estoy usando AngularUI Bootstrap versión 0.12.1.

Me informaron sobre esta solución por this .


Tuve el mismo problema y pude resolverlo definiendo el objeto de formulario en el alcance del controlador de modales. Para que su código funcione $scope.form = {}; , por ejemplo, $scope.form = {}; al comienzo de su controlador y cambie su etiqueta de formulario a <form name="form.invitation"> . Después $scope.form.invitation.$invalid debe ser llenado.


Actualización de noviembre de 2014 : comenzando desde angular-ui-bootstrap 0.12.0 alcance de la transclusión 0.12.0 se fusiona con el alcance del controlador. No hay necesidad de hacer nada.

Antes de 0.12.0 :

Para poner invitationForm directamente en el ámbito de su controlador principal, debe omitir el ámbito transcluido de esta manera:

<form name="$parent.invitationForm">

Arriba se creará automáticamente un objeto de formulario en su controlador principal. No hay necesidad de material previo a la inicialización, rutas largas de objetos o eventos pasados. Simplemente acceda con $scope.invitationForm una vez que se abra modal.


$mdDialog.show({ locals: {alert:"display meassage"}, controller: DialogController, templateUrl: ''views/dialog.html'', parent: angular.element(document.body), clickOutsideToClose:true, backdrop: true, keyboard: true, backdropClick: true, })