AngularJS n'envoie pas de valeur de champ masqué

192

Pour un cas d'utilisation spécifique, je dois soumettre un seul formulaire «à l'ancienne». Cela signifie que j'utilise un formulaire avec action = "". La réponse est diffusée, donc je ne recharge pas la page. Je suis tout à fait conscient qu'une application AngularJS typique ne soumettrait pas de formulaire de cette façon, mais jusqu'à présent, je n'ai pas d'autre choix.

Cela dit, j'ai essayé de remplir certains champs cachés d'Angular:

<input type="hidden" name="someData" ng-model="data" /> {{data}}

Veuillez noter que la valeur correcte des données est affichée.

Le formulaire ressemble à un formulaire standard:

<form id="aaa" name="aaa" action="/reports/aaa.html" method="post">
...
<input type="submit" value="Export" />
</form>

Si je clique sur Soumettre, aucune valeur n'est envoyée au serveur. Si je change le champ de saisie pour taper "texte", cela fonctionne comme prévu. Mon hypothèse est que le champ caché n'est pas vraiment rempli, alors que le champ de texte est en fait affiché en raison de la liaison bidirectionnelle.

Des idées sur la façon dont je peux soumettre un champ masqué rempli par AngularJS?

Christian
la source
4
Hmm ... que diriez-vous de taper du texte display: none;? C'est moche tho. Angular ignore les éléments cachés.
tymeJV
mettez cela comme réponse @tymeJV!
Jeroen Ingelbrecht
7
J'utilise la syntaxe suivante pour lier une valeur: <input type="hidden" required ng-model="data.userid" ng-init="data.userid=pivot.id" /> . Ce n'est peut-être pas la bonne façon de faire, mais cela fonctionne pour moi.
John P

Réponses:

287

Vous ne pouvez pas utiliser de double liaison avec un champ masqué. La solution est d'utiliser des crochets:

<input type="hidden" name="someData" value="{{data}}" /> {{data}}

EDIT: Voir ce fil sur github: https://github.com/angular/angular.js/pull/2574

ÉDITER:

Depuis Angular 1.2, vous pouvez utiliser la directive 'ng-value' pour lier une expression à l'attribut value de input. Cette directive doit être utilisée avec une radio d'entrée ou une case à cocher mais fonctionne bien avec une entrée masquée.

Voici la solution utilisant ng-value:

<input type="hidden" name="someData" ng-value="data" />

Voici un violon utilisant ng-value avec une entrée cachée: http://jsfiddle.net/6SD9N

Mickael
la source
Impressionnant. Merci beaucoup. J'allais presque cacher le champ de texte, mais maintenant je pense que c'est une excellente solution de contournement.
Christian
22
Génial. Et vous pouvez également utiliser ng-value = "modelName" pour le faire sans crochets.
Jonathan
2
C'est vrai, depuis Angular 1.2, vous pouvez utiliser ng-value pour lier une expression à l'attribut value, la réponse est à jour.
Mickael
avez-vous vraiment besoin d'un champ caché lorsque vous utilisez AngularJS? sur ngSubmit, vous frappez un contrôleur, toutes vos données sont complètement visibles pour l'accès, et vous les envoyez via un service $ http.
mtpultz
3
Merci beaucoup. Le fait que ng-model ne puisse pas être utilisé pour une entrée masquée doit être documenté dans AngularJS IMO.
yoonchee
47

Vous pouvez toujours utiliser un type=textet display:none;puisque Angular ignore les éléments masqués. Comme le dit OP, normalement vous ne le feriez pas, mais cela semble être un cas particulier.

<input type="text" name="someData" ng-model="data" style="display: none;"/>
tymeJV
la source
Merci! Je pensais dans le même sens, mais je devais simplement préférer la {{}} Solution de Mickael.
Christian
1
solution intelligente / intelligente
ImranNaqvi
8

Dans le contrôleur:

$scope.entityId = $routeParams.entityId;

Dans la vue:

<input type="hidden" name="entityId" ng-model="entity.entityId" ng-init="entity.entityId = entityId" />
meffect
la source
1
Bon point ... je préfère le faire uniquement dans le contrôleur la prochaine fois
meffect
je tombe amoureux de ng-init
ImranNaqvi
Nooon. en boucle, il fait beaucoup de mal et attribue la dernière valeur à tout entityIdsi entityIdest un tableau
ImranNaqvi
4

J'ai trouvé une belle solution écrite par Mike sur sapiensworks . C'est aussi simple que d'utiliser une directive qui surveille les changements sur votre modèle:

.directive('ngUpdateHidden',function() {
    return function(scope, el, attr) {
        var model = attr['ngModel'];
        scope.$watch(model, function(nv) {
            el.val(nv);
        });
    };
})

puis liez votre entrée:

<input type="hidden" name="item.Name" ng-model="item.Name" ng-update-hidden />

Mais la solution fournie par tymeJV pourrait être meilleure car l'entrée masquée ne déclenche pas l'événement de changement en javascript comme l'a dit yycorman dans cet article, donc lorsque vous changez la valeur via un plugin jQuery, cela fonctionnera toujours.

Edit J'ai modifié la directive pour appliquer une nouvelle valeur au modèle lorsque l'événement de modification est déclenché, il fonctionnera donc comme un texte d'entrée.

.directive('ngUpdateHidden', function () {
    return {
        restrict: 'AE', //attribute or element
        scope: {},
        replace: true,
        require: 'ngModel',
        link: function ($scope, elem, attr, ngModel) {
            $scope.$watch(ngModel, function (nv) {
                elem.val(nv);
            });
            elem.change(function () { //bind the change event to hidden input
                $scope.$apply(function () {
                    ngModel.$setViewValue(  elem.val());
                });
            });
        }
    };
})

Ainsi, lorsque vous déclenchez un $("#yourInputHidden").trigger('change')événement avec jQuery, il mettra également à jour le modèle lié.

Joan JB
la source
Quelqu'un d'autre a-t-il du mal à faire fonctionner cette solution? Le problème est que le paramètre ngModel n'est pas défini lorsque la directive est analysée et exécutée, par conséquent, $ watch n'est pas ajouté.
icfantv
D'accord. Il semble que le problème soit que le quatrième paramètre ngModel est un objet, alors que l'exemple référencé à partir du lien de sapiensworks récupère la valeur de chaîne de l'attribut ng-model via attr ['ngModel'], puis la transmet à la montre. Je peux confirmer que cette modification résout le problème de la montre.
icfantv
Il y a un autre problème ici. jQuery ne déclenche pas d'événement de modification lorsque vous modifiez par programme la valeur d'un champ d'entrée masqué. Donc, si je dis $ (hidden_input_elt) .val ("snoopy"), je dois également ajouter .change () pour déclencher l'événement de changement. Le problème avec ceci est qu'Angular se plaindra du $ scope.apply () ci-dessus car il est déjà dans un $ apply est déjà en cours. La solution ici est de supprimer $ scope. $ Apply dans la fonction de changement ci-dessus et d'appeler simplement ngModel. $ SetViewValue (...).
icfantv
2

Nous avons trouvé un comportement étrange à propos de cette valeur cachée () et nous ne pouvons pas le faire fonctionner.

Après avoir joué, nous avons trouvé que le meilleur moyen consiste simplement à définir la valeur dans le contrôleur lui-même après la portée du formulaire.

.controller('AddController', [$scope, $http, $state, $stateParams, function($scope, $http, $state, $stateParams) {

    $scope.routineForm = {};
    $scope.routineForm.hiddenfield1 = "whatever_value_you_pass_on";

    $scope.sendData = function {

// JSON http post action to API 
}

}])
dcpartners
la source
1

J'ai réalisé cela via -

 <p style="display:none">{{user.role="store_user"}}</p>
Vivex
la source
1

mettre à jour la réponse de @tymeJV, par exemple:

 <div style="display: none">
    <input type="text" name='price' ng-model="price" ng-init="price = <%= @product.price.to_s %>" >
 </div>
Albert.Qing
la source
0

J'ai eu le même problème, j'ai vraiment besoin d'envoyer une clé de mon jsp au script java, cela passe environ 4h ou plus de ma journée à le résoudre.

J'inclus cette balise sur mon JavaScript / JSP:

 $scope.sucessMessage = function (){  
    	var message =     ($scope.messages.sucess).format($scope.portfolio.name,$scope.portfolio.id);
    	$scope.inforMessage = message;
    	alert(message);  
}
 

String.prototype.format = function() {
    var formatted = this;
    for( var arg in arguments ) {
        formatted = formatted.replace("{" + arg + "}", arguments[arg]);
    }
    return formatted;
};
<!-- Messages definition -->
<input type="hidden"  name="sucess"   ng-init="messages.sucess='<fmt:message  key='portfolio.create.sucessMessage' />'" >

<!-- Message showed affter insert -->
<div class="alert alert-info" ng-show="(inforMessage.length > 0)">
    {{inforMessage}}
</div>

<!-- properties
  portfolio.create.sucessMessage=Portf\u00f3lio {0} criado com sucesso! ID={1}. -->

Le résultat était: Portfólio 1 criado com sucesso! ID = 3.

Meilleures salutations

LeoJava
la source
0

Juste au cas où quelqu'un aurait encore du mal avec cela, j'ai eu un problème similaire en essayant de garder une trace de la session utilisateur / de l'ID utilisateur sur un formulaire multipage

J'ai corrigé cela en ajoutant

.when ("/ q2 /: uid" dans le routage:

    .when("/q2/:uid", {
        templateUrl: "partials/q2.html",
        controller: 'formController',
        paramExample: uid
    })

Et ajouté ceci en tant que champ caché pour passer des paramètres entre les pages de formulaire Web

<< input type = "hidden" required ng-model = "formData.userid" ng-init = "formData.userid = uid" />

Je suis nouveau sur Angular, donc je ne suis pas sûr que ce soit la meilleure solution possible, mais cela semble fonctionner correctement pour moi maintenant

macieku
la source
0

Attribuez directement la valeur au modèle dans l' data-ng-valueattribut. Puisque l'interpréteur angulaire ne reconnaît pas les champs cachés dans le cadre de ngModel.

<input type="hidden" name="pfuserid" data-ng-value="newPortfolio.UserId = data.Id"/>
Nikhil.Hmath
la source
0

J'utilise un javascript classique pour définir la valeur sur une entrée masquée

$scope.SetPersonValue = function (PersonValue)
{
    document.getElementById('TypeOfPerson').value = PersonValue;
    if (PersonValue != 'person')
    {
        document.getElementById('Discount').checked = false;
        $scope.isCollapsed = true;
    }
    else
    {
        $scope.isCollapsed = false;
    }
}
Ivan Kuznietsov
la source
0

Le code ci-dessous fonctionnera pour cet IFF dans le même ordre que celui mentionné, assurez-vous que votre commande est de type puis de nom, ng-model ng-init, valeur. c'est tout.

Pawan Parashar
la source
0

Ici, je voudrais partager mon code de travail:

<input type="text" name="someData" ng-model="data" ng-init="data=2" style="display: none;"/>
OR
<input type="hidden" name="someData" ng-model="data" ng-init="data=2"/>
OR
<input type="hidden" name="someData" ng-init="data=2"/>

J. Middya
la source
Pourriez-vous plus d'explications s'il vous plaît
JSmith
Sûr! Lorsque nous utilisons un champ masqué ou un champ de texte avec un attribut display: none, l'utilisateur ne peut pas saisir de valeur. Dans ce cas, la directive ng-init aide à définir la valeur du champ. Merci
J. Middya
dans le post Je voulais dire Désolé
JSmith