AngularJS - L'attribut Value sur une zone de texte en entrée est ignoré lorsqu'un modèle ng est utilisé?

219

Utilisation d'AngularJS si j'ai défini une valeur de zone de texte de saisie simple à quelque chose comme "bob" ci-dessous. La valeur ne s'affiche pas si l' ng-modelattribut est ajouté.

    <input type="text"
           id="rootFolder"
           ng-model="rootFolders"
           disabled="disabled"
           value="Bob"
           size="40"/>

Quelqu'un sait qu'il existe un moyen simple de contourner cette entrée par défaut et de conserver le ng-model? J'ai essayé d'utiliser un ng-bindavec la valeur par défaut mais cela ne semble pas fonctionner non plus.

Bonjour le monde
la source

Réponses:

223

C'est le comportement souhaité, vous devez définir le modèle dans le contrôleur, pas dans la vue.

<div ng-controller="Main">
  <input type="text" ng-model="rootFolders">
</div>


function Main($scope) {
  $scope.rootFolders = 'bob';
}
Vojta
la source
11
Merci. Mais dans ce cas, le modèle est défini dans le contrôleur. Et dans les documents angulaires, c'est toujours la même chose, les données sont définies dans le contrôleur. Mais mon contrôleur est dans un fichier JS. Comment faire quand sur un formulaire "edit"? Comment passer des données de formulaire par défaut au contrôleur "de manière angulaire"?
ByScripts
8
Cela ne fonctionne pas pour moi, mais l'ajout de l'attribut supplémentaire ng-init montré par Mark Rajcok (ng-init = "rootFolders = 'Bob'") fonctionne très bien.
Kaizar Laxmidhar
Et comment définir la valeur par défaut si j'ai un champ de saisie comme: <input type = "number" ng-model = "newTransaction [$ index] [user.email]" />?
shish
188

Vojta a décrit la "voie angulaire", mais si vous avez vraiment besoin de faire ce travail, @urbanek a récemment publié une solution de contournement en utilisant ng-init:

<input type="text" ng-model="rootFolders" ng-init="rootFolders='Bob'" value="Bob">

https://groups.google.com/d/msg/angular/Hn3eztNHFXw/wk3HyOl9fhcJ

Mark Rajcok
la source
33
Vous n'avez peut-être pas besoin de la partie 'value = "Bob"'.
Mark Rajcok
2
+1 mais, comme mentionné dans l'un des articles de la discussion liée, il convient de l'éviter (car logiquement, c'est moins correct et cela rend les tests plus difficiles).
0xc0de
1
Cette méthode fonctionne correctement si vous utilisez également une valeur de modèle sur la version 1.2. <... ng-init = "rootFolders = someModelAttribute" ...>
dmcqu314
@MarkRajcok, vous avez tellement de bons articles AngularJS sur Stack Overflow! Merci pour tout le temps que vous avez consacré à partager vos idées avec la communauté SO. Je suis sûr que je parle pour de nombreux développeurs soulagés quand je dis que nous apprécions sincèrement toutes les heures que vous nous avez sauvées!
Jeremy Moritz
1
J'apprécie vraiment la réponse de Mark car cela a résolu mon problème. Je confirme que nous n'avons PAS besoin de value="Bob"partie dans la balise d'entrée.
Devner
68

Remplacer la directive d'entrée semble faire l'affaire. J'ai apporté quelques modifications mineures au code de Dan Hunsaker :

  • Ajout d'une vérification de ngModel avant d'essayer d'utiliser $parse().assign()sur des champs sans attributs ngModel.
  • Correction de l' assign()ordre des paramètres de fonction.
app.directive('input', function ($parse) {
  return {
    restrict: 'E',
    require: '?ngModel',
    link: function (scope, element, attrs) {
      if (attrs.ngModel && attrs.value) {
        $parse(attrs.ngModel).assign(scope, attrs.value);
      }
    }
  };
});
Ivan Breet
la source
C'est la meilleure réponse que j'ai trouvée! ... résout mon problème de manière élégante. J'ai dû capturer une valeur sur une entrée cachée (un jeton de formulaire Symfony, généré sur le serveur).
PachinSV
Ce n'est pas seulement intelligent mais c'est la meilleure solution. Dans mon cas, je ne peux pas définir la valeur par défaut de ng-model sur le contrôleur car il s'agit d'un formulaire PHP, si la validation côté serveur échoue, le formulaire sera actualisé et tout ce qui se trouve dans ng-model sera perdu en supprimant la valeur d'entrée aussi.
Luis Elizondo
2
Cela semble la meilleure solution si vous souhaitez également qu'une version de base de votre formulaire HTML fonctionne sans JavaScript.
Darren
Excellente solution qui devrait vraiment être une option configurable non par défaut dans angular elle-même.
Gracie
Merci pour votre solution. Comment résoudriez-vous le problème de saisie de numéro? Il renvoie une erreur docs.angularjs.org/error/ngModel/numfmt?p0=20.12
mate.gwozdz
21

La voie angulaire

La manière angulaire correcte de le faire est d'écrire une application d'une seule page, AJAX dans le modèle de formulaire, puis de la remplir dynamiquement à partir du modèle. Le modèle n'est pas renseigné par défaut à partir du formulaire car le modèle est la seule source de vérité. Au lieu de cela, Angular ira dans l'autre sens et essaiera de remplir le formulaire à partir du modèle.

Si toutefois vous n'avez pas le temps de recommencer à zéro

Si vous avez une application écrite, cela peut impliquer des changements architecturaux assez lourds. Si vous essayez d'utiliser Angular pour améliorer un formulaire existant, plutôt que de créer une application entière d'une seule page à partir de zéro, vous pouvez extraire la valeur du formulaire et la stocker dans la portée au moment du lien à l'aide d'une directive. Angular liera ensuite la valeur de l'étendue au formulaire et la gardera synchronisée.

Utilisation d'une directive

Vous pouvez utiliser une directive relativement simple pour extraire la valeur du formulaire et la charger dans la portée actuelle. Ici, j'ai défini une directive initFromForm.

var myApp = angular.module("myApp", ['initFromForm']);

angular.module('initFromForm', [])
  .directive("initFromForm", function ($parse) {
    return {
      link: function (scope, element, attrs) {
        var attr = attrs.initFromForm || attrs.ngModel || element.attrs('name'),
        val = attrs.value;
        if (attrs.type === "number") {val = parseInt(val)}
        $parse(attr).assign(scope, val);
      }
    };
  });

Vous pouvez voir que j'ai défini quelques solutions de rechange pour obtenir un nom de modèle. Vous pouvez utiliser cette directive en conjonction avec la directive ngModel, ou vous lier à autre chose que $ scope si vous préférez.

Utilisez-le comme ceci:

<input name="test" ng-model="toaster.test" value="hello" init-from-form />
{{toaster.test}}

Notez que cela fonctionnera également avec les zones de texte et sélectionnez des listes déroulantes.

<textarea name="test" ng-model="toaster.test" init-from-form>hello</textarea>
{{toaster.test}}
superluminaire
la source
Voici un module compact qui implémente une solution similaire à ce qui est décrit ici github.com/platanus/angular-keep-values
Agustin
1
Excellente solution, mais cela ne fonctionnera qu'avec input="text". Si vous en avez un, numberil lancera Model n'est pas de type number docs.angularjs.org/error/ngModel/numfmt?p0=333
smoksnes
2
Pour prendre en charge les chiffres, vous pouvez ajouter if (attrs.type === "number") val = parseInt(val);
smoksnes
@smoksnes - vous avez absolument raison. J'ai mis à jour la réponse :)
superluminary
7

Mise à jour: Ma réponse initiale impliquait que le contrôleur contienne du code compatible DOM, ce qui rompt les conventions angulaires en faveur du HTML. @dmackerman a mentionné des directives dans un commentaire sur ma réponse, et cela m'a complètement manqué jusqu'à présent. Avec cette entrée, voici la bonne façon de le faire sans enfreindre les conventions angulaires ou HTML:


Il y a aussi un moyen d'obtenir les deux - saisir la valeur de l'élément et l'utiliser pour mettre à jour le modèle dans une directive:

<div ng-controller="Main">
    <input type="text" id="rootFolder" ng-model="rootFolders" disabled="disabled" value="Bob" size="40" />
</div>

puis:

app.directive('input', ['$parse', function ($parse) {
    return {
        restrict: 'E',
        require: '?ngModel',
        link: function (scope, element, attrs) {
            if(attrs.value) {
                $parse(attrs.ngModel).assign(scope, attrs.value);
            }
        }
    };
}]);

Vous pouvez bien sûr modifier la directive ci-dessus pour en faire plus avec l' valueattribut avant de définir le modèle sur sa valeur, notamment en utilisant $parse(attrs.value, scope)pour traiter l' valueattribut comme une expression angulaire (bien que j'utiliserais probablement un attribut [personnalisé] différent pour cela, personnellement, les attributs HTML standard sont donc systématiquement traités comme des constantes).

En outre, une question similaire est posée sur Rendre les modèles de données disponibles pour le modèle ng qui peut également être intéressant.

Dan Hunsaker
la source
Vous ne devriez pas faire de manipulation / découverte DOM dans vos contrôleurs. Devrait utiliser une directive à la place.
dmackerman
2
J'ai explicitement mentionné cet inconvénient dans ma réponse. Vous ne devriez pas , mais vous le pouvez . Tout dépend si vous trouvez plus important de suivre les conventions Angular ou HTML. Parce qu'Angular brise le HTML.
Dan Hunsaker
3
Oh, je suis un mannequin. J'ai complètement manqué le peu d'utiliser une directive. Réponse mise à jour en conséquence. Sincères excuses pour avoir été un con pour vous, @dmackerman.
Dan Hunsaker
Merci pour la directive! Cela m'a donné des idées à appliquer dans un projet sur lequel je travaille, où je génère du côté du serveur de contenu, puis je dois l'utiliser comme modèle pour le client.
ggalmazor
Heureux d'avoir pu aider. Bien sûr, d'une manière générale, vous souhaiterez créer votre contenu côté serveur en tant que JSON et faire en sorte que votre application manipule le modèle en fonction de cela, mais parfois il est utile d'avoir d'autres options, et ce n'en est qu'une.
Dan Hunsaker
7

Si vous utilisez la directive AngularJs ngModel, n'oubliez pas que la valeur de l' valueattribut ne se lie pas au champ ngModel. Vous devez l' initier par vous-même et la meilleure façon de le faire est de

<input type="text"
       id="rootFolder"
       ng-init="rootFolders = 'Bob'"
       ng-model="rootFolders"
       disabled="disabled"
       value="Bob"
       size="40"/>
Hazarapet Tunanyan
la source
Sent bizarre de l'initier dans la directive / balisage au lieu du contrôleur.
random_user_name
5

Ceci est une légère modification des réponses précédentes ...

Il n'y a pas besoin de $ parse

angular.directive('input', [function () {
  'use strict';

  var directiveDefinitionObject = {
    restrict: 'E',
    require: '?ngModel',
    link: function postLink(scope, iElement, iAttrs, ngModelController) {
      if (iAttrs.value && ngModelController) {
        ngModelController.$setViewValue(iAttrs.value);
      }
    }
  };

  return directiveDefinitionObject;
}]);
dale.lotts
la source
gardez à l'esprit que ngModelController. $ setViewValue changera l'état du modèle en sale et vierge en faux ce qui affectera également l'état de forme qui peut être douloureux un certain temps.
Atul Chaudhary
2

Salut, vous pouvez essayer les méthodes ci-dessous avec initialiser le modèle.

Ici, vous pouvez initialiser le modèle ng de la zone de texte dans les deux sens

- Avec utilisation de ng-init

- Avec utilisation de $ scope dans js

<!doctype html>
 <html >
 <head>
        <title>Angular js initalize with ng-init and scope</title>
        <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>
</head>
<body ng-app="app" >
    <h3>Initialize value with ng-init</h3>
    <!-- Initlialize model values with ng-init -->
    <div ng-init="user={fullname:'Bhaskar Bhatt',email:'[email protected]',address:'Ahmedabad'};">
        Name : <input type="text" ng-model="user.fullname" /><br/>
        Email : <input type="text" ng-model="user.email" /><br/>
        Address:<input type="text" ng-model="user.address" /><br/>

    </div>  
    <!-- initialize with js controller scope -->
    <h3>Initialize with js controller</h3>

    <div  ng-controller="alpha">
        Age:<input type="text" name="age" ng-model="user.age" /><br/>
        Experience : <input type="text" name="experience" ng-model="user.exp" /><br/>
        Skills : <input type="text" name="skills" ng-model="user.skills" /><br/>
    </div>  

</body> 
<script type="text/javascript">
        angular.module("app",[])
        .controller("alpha",function($scope){
            $scope.user={};
            $scope.user.age=27;
            $scope.user.exp="4+ years";
            $scope.user.skills="Php,javascript,Jquery,Ajax,Mysql";
        });

     </script>
 </html>                
Bhaskar Bhatt
la source
0

Le problème est que vous devez définir le modèle ng sur l'élément parent à l'endroit où vous souhaitez définir la valeur / valeur ng. Comme mentionné par Angular:

Il est principalement utilisé sur les éléments d'entrée [radio] et d'option, de sorte que lorsque l'élément est sélectionné, le ngModel de cet élément (ou son élément parent sélectionné) est défini sur la valeur liée.

Par exemple: Ceci est un code exécuté:

<div class="col-xs-12 select-checkbox" >
<label style="width: 18em;" ng-model="vm.settingsObj.MarketPeers">
  <input name="radioClick" type="radio"  ng-click="vm.setPeerGrp('market');" 
         ng-value="vm.settingsObj.MarketPeers" 
         style="position:absolute;margin-left: 9px;">
  <div style="margin-left: 35px;color: #717171e8;border-bottom: 0.5px solid #e2e2e2;padding-bottom: 2%;">Hello World</div>
</label>
</div>

Remarque: dans ce cas ci-dessus, j'ai déjà eu la réponse JSON au modèle ng et à la valeur, j'ajoute simplement une autre propriété à l'objet JS en tant que "MarketPeers". Ainsi, le modèle et la valeur peuvent dépendre selon les besoins, mais je pense que ce processus aidera, à avoir à la fois ng-modèle et valeur mais ne pas les avoir sur le même élément.

sg28
la source
0

J'ai eu un problème similaire. Je n'ai pas pu utiliser value="something"pour afficher et modifier. J'ai dû utiliser la commande ci-dessous à l'intérieur de mon <input>long avec le modèle ng en cours de déclaration.

[(ngModel)]=userDataToPass.pinCode

Où j'ai la liste des données dans l'objet userDataToPasset l'élément que je dois afficher et modifier estpinCode .

Pour la même chose, je me suis référé à cette vidéo YouTube

tkrloltkr
la source
Pour ce howTo, l'OP utilise AngularJS, votre référence vidéo YT utilise Angular 4.
Chris22