AngularJS: ¿se ignora el atributo de valor en un cuadro de texto de entrada cuando se utiliza un modelo ng?

219

Usando AngularJS si configuro un valor de cuadro de texto de entrada simple para algo como "bob" a continuación. El valor no se muestra si ng-modelse agrega el atributo.

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

¿Alguien sabe de una solución simple para predeterminar esta entrada a algo y mantener el ng-model? Intenté usar a ng-bindcon el valor predeterminado, pero parece que tampoco funciona.

Hola Mundo
fuente

Respuestas:

223

Ese es el comportamiento deseado, debe definir el modelo en el controlador, no en la vista.

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


function Main($scope) {
  $scope.rootFolders = 'bob';
}
Vojta
fuente
11
Gracias. Pero en este caso, el modelo se establece en el controlador. Y en los documentos angulares, siempre es lo mismo, los datos se configuran en el controlador. Pero mi controlador está en un archivo JS. ¿Cómo hacerlo en un formulario de "edición"? ¿Cómo pasar datos de formulario predeterminados al controlador "de forma angular"?
ByScripts
8
Esto no funciona para mí, sin embargo, agregar el atributo adicional ng-init mostrado por Mark Rajcok (ng-init = "rootFolders = 'Bob'") funciona bien.
Kaizar Laxmidhar
¿Y cómo configuro el valor predeterminado si tengo un campo de entrada como: <input type = "number" ng-model = "newTransaction [$ index] [user.email]" />?
shish
188

Vojta describió la "forma angular", pero si realmente necesita hacer que esto funcione, @urbanek recientemente publicó una solución alternativa usando 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
fuente
33
Es posible que no necesite la parte 'value = "Bob"'.
Mark Rajcok
2
+1 pero, como se menciona en una de las publicaciones en la discusión vinculada, debe evitarse (ya que lógicamente es menos correcto y hace que las pruebas sean más difíciles).
0xc0de
1
Este método funciona bien si usa un valor de modelo también en v1.2. <... ng-init = "rootFolders = someModelAttribute" ...>
dmcqu314
@MarkRajcok, ¡tienes tantas publicaciones geniales de AngularJS en Stack Overflow! Gracias por todo el tiempo que ha dedicado a compartir sus ideas con la comunidad SO. ¡Estoy seguro de que hablo por muchos desarrolladores aliviados cuando digo que apreciamos sinceramente todas las horas que nos ha ahorrado!
Jeremy Moritz
1
Realmente aprecio la respuesta de Mark ya que eso resolvió mi problema. Confirmo que NO necesitamos value="Bob"parte en la etiqueta de entrada.
Devner
68

Anular la directiva de entrada parece hacer el trabajo. Hice algunas modificaciones menores al código de Dan Hunsaker :

  • Se agregó una comprobación para ngModel antes de intentar usar $parse().assign() en campos sin atributos ngModel.
  • Se corrigió el assign()orden de la función param.
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
fuente
¡Esta es la mejor respuesta que encontré! ... resuelve mi problema de una manera elegante. Tuve que capturar un valor en una entrada oculta (un token de formulario Symfony, generado en el servidor).
PachinSV
Esto no solo es inteligente sino la mejor solución. En mi caso, no puedo establecer el valor predeterminado de ng-model en el controlador porque es un formulario PHP, si la validación del lado del servidor falla, el formulario se actualizará y lo que esté en ng-model se perderá eliminando el valor de entrada también.
Luis Elizondo
2
Esta parece ser la mejor solución si también desea que una versión básica de su formulario HTML funcione sin JavaScript.
Darren
Excelente solución que realmente debería ser una opción configurable no predeterminada dentro del propio ángulo.
Gracie
Gracias por tu solución. ¿Cómo resolverías el problema de entrada de números? Lanza
mate.gwozdz
21

El camino angular

La forma angular correcta de hacer esto es escribir una aplicación de una sola página, AJAX en la plantilla de formulario, y luego llenarla dinámicamente desde el modelo. El modelo no se rellena desde el formulario de forma predeterminada porque el modelo es la única fuente de verdad. En su lugar, Angular irá en sentido contrario e intentará completar el formulario desde el modelo.

Sin embargo, si no tiene tiempo para comenzar de nuevo desde cero

Si tiene una aplicación escrita, esto podría implicar algunos cambios arquitectónicos bastante fuertes. Si está intentando usar Angular para mejorar un formulario existente, en lugar de construir una aplicación de página única desde cero, puede extraer el valor del formulario y almacenarlo en el alcance en el momento del enlace utilizando una directiva. Angular luego vinculará el valor en el alcance de nuevo al formulario y lo mantendrá sincronizado.

Usando una directiva

Puede usar una directiva relativamente simple para extraer el valor del formulario y cargarlo en el ámbito actual. Aquí he definido una directiva 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);
      }
    };
  });

Puedes ver que he definido un par de alternativas para obtener un nombre de modelo. Puede usar esta directiva junto con la directiva ngModel, o unirse a algo que no sea $ scope si lo prefiere.

Úselo así:

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

Tenga en cuenta que esto también funcionará con áreas de texto y menús desplegables seleccionados.

<textarea name="test" ng-model="toaster.test" init-from-form>hello</textarea>
{{toaster.test}}
superluminario
fuente
Aquí hay un módulo empaquetado que implementa una solución similar a la que se describe aquí github.com/platanus/angular-keep-values
Agustin
1
Gran solución, pero solo funcionará input="text". Si tiene un number, arrojará Modelo no es del tipo number docs.angularjs.org/error/ngModel/numfmt?p0=333
smoksnes
2
Para admitir números que puede agregar if (attrs.type === "number") val = parseInt(val);
smoksnes
@smoksnes: tienes toda la razón. He actualizado la respuesta :)
superluminary
7

Actualización: Mi respuesta original implicaba que el controlador contuviera código compatible con DOM, que rompe las convenciones angulares a favor del HTML. @dmackerman mencionó las directivas en un comentario sobre mi respuesta, y me perdí por completo hasta ahora. Con esa entrada, esta es la forma correcta de hacerlo sin romper las convenciones Angular o HTML:


También hay una forma de obtener ambos: tome el valor del elemento y úselo para actualizar el modelo en una directiva:

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

y entonces:

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);
            }
        }
    };
}]);

Por supuesto, puede modificar la directiva anterior para hacer más con el valueatributo antes de establecer el modelo en su valor, incluido el uso$parse(attrs.value, scope) para tratar elvalue atributo como una expresión angular (aunque probablemente usaría un atributo [personalizado] diferente para eso, personalmente, entonces los atributos HTML estándar se tratan consistentemente como constantes).

Además, hay una pregunta similar en Hacer que los datos estén disponibles para ng-model que también pueden ser de interés.

Dan Hunsaker
fuente
No debería estar haciendo ninguna manipulación / descubrimiento de DOM en sus controladores. Debería usar una directiva en su lugar.
dmackerman
2
Mencioné explícitamente ese inconveniente en mi respuesta. Usted no debería , pero se puede . Todo depende de si le resulta más importante seguir las convenciones de Angular o HTML. Porque Angular rompe HTML.
Dan Hunsaker
3
Oh, soy un tonto. Me perdí por completo el uso de una directiva. Respuesta actualizada en consecuencia. Sinceras disculpas por ser un idiota contigo, @dmackerman.
Dan Hunsaker
Gracias por la directiva! Me dio ideas para aplicar en un proyecto en el que estoy trabajando en el que genero parte del servidor de contenido y luego tengo que usarlo como mi modelo en el cliente.
ggalmazor
Me alegro de poder ayudar. Por supuesto, en términos generales, querrás construir tu contenido del lado del servidor como JSON y hacer que tu aplicación manipule el modelo basado en eso, pero a veces es útil tener otras opciones, y esta es solo una.
Dan Hunsaker
7

Si usa la directiva ngModel de AngularJs, recuerde que el valor del valueatributo no se une al campo ngModel . Debe iniciarlo usted mismo y la mejor manera de hacerlo es

<input type="text"
       id="rootFolder"
       ng-init="rootFolders = 'Bob'"
       ng-model="rootFolders"
       disabled="disabled"
       value="Bob"
       size="40"/>
Hazarapet Tunanyan
fuente
Se siente extraño iniciarlo en la directiva / marcado en lugar del controlador.
random_user_name
5

Esta es una ligera modificación a las respuestas anteriores ...

No hay necesidad 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
fuente
tenga en cuenta que ngModelController. $ setViewValue cambiará el estado del modelo a sucio y prístino a falso, lo que también afectará el estado del formulario que puede ser doloroso en algún momento.
Atul Chaudhary
2

Hola, puedes probar los siguientes métodos con la inicialización del modelo.

Aquí puede inicializar ng-model de textbox de dos maneras

- Con el uso de ng-init

- Con el uso de $ scope en 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
fuente
0

El problema es que debe establecer el modelo ng en el elemento principal donde desea establecer el valor / valor ng. Como lo menciona Angular:

Se utiliza principalmente en los elementos de entrada [radio] y opciones, de modo que cuando se selecciona el elemento, el ngModel de ese elemento (o su elemento principal seleccionado) se establece en el valor delimitado.

Por ejemplo: este es un código ejecutado:

<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>

Nota: En este caso anterior, ya tenía la respuesta JSON al modelo ng y el valor, solo estoy agregando otra propiedad al objeto JS como "MarketPeers". Por lo tanto, el modelo y el valor pueden depender de acuerdo con la necesidad, pero creo que este proceso ayudará, tener ambos ng-model y value pero no tenerlos en el mismo elemento.

sg28
fuente
0

Tuve un problema similar. No pude usar value="something"para mostrar y editar. Tuve que usar el siguiente comando dentro de mi <input>junto con el modelo ng que se declaraba.

[(ngModel)]=userDataToPass.pinCode

Donde tengo la lista de datos en el objeto userDataToPassy el elemento que necesito mostrar y editar es pinCode.

Por lo mismo, me referí a este video de YouTube

tkrloltkr
fuente
Para este tutorial, el OP está usando AngularJS, su referencia de video YT está usando Angular 4.
Chris22