AngularJS - O atributo Value em uma caixa de texto de entrada é ignorado quando há um modelo ng usado?

218

Usando AngularJS se eu definir um valor simples da caixa de texto de entrada para algo como "bob" abaixo. O valor não será exibido se o ng-modelatributo for adicionado.

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

Alguém sabe de uma solução simples para usar como padrão essa entrada e manter o ng-model? Tentei usar a ng-bindcom o valor padrão, mas isso também parece não funcionar.

Olá Mundo
fonte

Respostas:

223

Esse é o comportamento desejado, você deve definir o modelo no controlador, não na visualização.

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


function Main($scope) {
  $scope.rootFolders = 'bob';
}
Vojta
fonte
11
Obrigado. Mas, neste caso, o modelo é definido no controlador. E nos documentos angulares, é sempre o mesmo, os dados são definidos no controlador. Mas meu controlador está em um arquivo JS. Como fazer quando em um formulário "editar"? Como passar dados de formulário padrão para o controlador "da maneira angular"?
ByScripts
8
Isso não funciona para mim, no entanto, a adição de atributo adicional ng-init mostrado por Mark Rajcok (ng-init = "rootFolders = 'Bob'") funciona bem.
Kaizar Laxmidhar
E como defino o valor padrão se tenho um campo de entrada como: <input type = "number" ng-model = "newTransaction [$ index] [user.email]" />?
shish
188

Vojta descreveu o "caminho angular", mas se você realmente precisar fazer isso funcionar, o @urbanek postou recentemente uma solução alternativa usando o 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
fonte
33
Você pode não precisar da parte 'value = "Bob"'.
precisa saber é o seguinte
2
+1 mas, como mencionado em uma das postagens na discussão vinculada, deve ser evitado (como logicamente é menos correto e torna os testes mais difíceis).
0xc0de 13/03/2013
1
Este método funciona bem se você usar um valor de modelo também na v1.2. <... ng-init = "rootFolders = someModelAttribute" ...>
dmcqu314
@ MarkRajcok, você tem muitas postagens excelentes do AngularJS no Stack Overflow! Obrigado por todo o tempo que você dedicou a compartilhar suas idéias com a comunidade SO. Tenho certeza de que falo por muitos desenvolvedores aliviados quando digo que agradecemos sinceramente todas as horas que você nos salvou!
Jeremy Moritz
1
Realmente aprecio a resposta de Mark, pois isso resolveu meu problema. Confirmo que NÃO precisamos value="Bob"participar da tag de entrada.
Devner
68

A substituição da diretiva de entrada parece fazer o trabalho. Fiz algumas pequenas alterações no código de Dan Hunsaker :

  • Foi adicionada uma verificação do ngModel antes de tentar usar $parse().assign()nos campos sem os atributos ngModel.
  • Corrigida a assign()ordem dos parâmetros da função.
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
fonte
Esta é a melhor resposta que encontrei! ... resolve meu problema de maneira elegante. Eu tive que capturar um valor em uma entrada oculta (um token de formulário Symfony, gerado no servidor).
PachinSV
Isso não é apenas inteligente, mas a melhor solução. No meu caso, não consigo definir o valor padrão do ng-model no controlador porque é um formulário PHP; se a validação no servidor falhar, o formulário será atualizado e o que estiver no ng-model será perdido, excluindo o valor de entrada também.
Luis Elizondo
2
Essa parece a melhor solução se você também quiser que uma versão básica do seu formulário HTML funcione sem JavaScript.
Darren
Excelente solução que realmente deve ser uma opção configurável não padrão dentro do próprio angular.
Gracie
Obrigado pela sua solução. Como você resolveria o problema de entrada de números? Ele lança um erro docs.angularjs.org/error/ngModel/numfmt?p0=20.12
mate.gwozdz
21

O caminho angular

A maneira angular correta de fazer isso é escrever um aplicativo de página única, o AJAX no modelo de formulário e preenchê-lo dinamicamente a partir do modelo. O modelo não é preenchido do formulário por padrão porque o modelo é a única fonte de verdade. Em vez disso, o Angular seguirá o outro caminho e tentará preencher o formulário a partir do modelo.

Se, no entanto, você não tiver tempo para começar do zero

Se você tiver um aplicativo escrito, isso poderá envolver algumas mudanças arquiteturais bastante pesadas. Se você estiver tentando usar o Angular para aprimorar um formulário existente, em vez de construir um aplicativo de página única inteiro do zero, poderá extrair o valor do formulário e armazená-lo no escopo no momento do link usando uma diretiva. O Angular vinculará o valor no escopo ao formulário e o manterá sincronizado.

Usando uma diretiva

Você pode usar uma diretiva relativamente simples para extrair o valor do formulário e carregá-lo no escopo atual. Aqui eu defini uma diretiva 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);
      }
    };
  });

Você pode ver que eu defini algumas alternativas para obter um nome de modelo. Você pode usar esta diretiva em conjunto com a diretiva ngModel ou vincular a algo diferente de $ scope, se preferir.

Use-o assim:

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

Observe que isso também funcionará com áreas de texto e selecione menus suspensos.

<textarea name="test" ng-model="toaster.test" init-from-form>hello</textarea>
{{toaster.test}}
superluminário
fonte
Aqui está um módulo embalado que implementa uma solução semelhante ao que é descrito aqui github.com/platanus/angular-keep-values
Agustin
1
Ótima solução, mas funcionará apenas com input="text". Se você tem um numberque vai jogar de modelo não é do tipo number docs.angularjs.org/error/ngModel/numfmt?p0=333
smoksnes
2
Para números de suporte você pode adicionar if (attrs.type === "number") val = parseInt(val);
smoksnes
@smoksnes - você está absolutamente correto. Eu atualizei a resposta :)
superluminary
7

Atualização: minha resposta original envolvia que o controlador contivesse código compatível com DOM, o que quebra as convenções angulares em favor do HTML. @dmackerman mencionou diretivas em um comentário sobre a minha resposta, e eu perdi completamente isso até agora. Com essa entrada, eis a maneira correta de fazer isso sem violar as convenções Angular ou HTML:


Também há uma maneira de obter os dois - pegue o valor do elemento e use-o para atualizar o modelo em uma diretiva:

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

e depois:

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

É claro que você pode modificar a diretiva acima para fazer mais com o valueatributo antes de definir o modelo com seu valor, inclusive usando $parse(attrs.value, scope)para tratar o valueatributo como uma expressão Angular (embora eu provavelmente usaria um atributo [personalizado] diferente para isso, pessoalmente, para que os atributos HTML padrão sejam tratados consistentemente como constantes).

Além disso, há uma pergunta semelhante em Disponibilizar dados modelados em disponíveis para o modelo ng, que também pode ser interessante.

Dan Hunsaker
fonte
Você não deveria estar fazendo nenhuma manipulação / descoberta de DOM em seus controladores. Deve usar uma diretiva.
dmackerman
2
Mencionei explicitamente essa desvantagem na minha resposta. Você não deveria , mas você pode . Tudo depende se você acha mais importante seguir as convenções do Angular ou do HTML. Porque o Angular quebra o HTML.
Dan Hunsaker
3
Oh, eu sou um boneco. Perdeu completamente o uso de uma diretiva. Resposta atualizada em conformidade. Sinceramente, desculpe-me por ser um idiota para você, @dmackerman.
Dan Hunsaker
Obrigado pela diretiva! Isso me deu idéias para aplicar em um projeto no qual estou trabalhando, onde eu gero algum lado do servidor de conteúdo e depois preciso usá-lo como modelo no cliente.
ggalmazor
Ainda bem que pude ajudar. É claro que, de um modo geral, você desejará criar seu conteúdo do servidor como JSON e fazer com que seu aplicativo manipule o modelo com base nisso, mas às vezes é útil ter outras opções, e essa é apenas uma.
Dan Hunsaker
7

Se você usar a diretiva AngularJs ngModel, lembre-se de que o valor do valueatributo não se liga ao campo ngModel . É necessário iniciá -lo sozinho e a melhor maneira de fazê-lo é

<input type="text"
       id="rootFolder"
       ng-init="rootFolders = 'Bob'"
       ng-model="rootFolders"
       disabled="disabled"
       value="Bob"
       size="40"/>
Hazarapet Tunanyan
fonte
Parece estranho iniciá-lo na diretiva / marcação em vez do controlador.
Random_user_name 5/05
5

Esta é uma ligeira modificação nas respostas anteriores ...

Não há necessidade 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
fonte
lembre-se de que ngModelController. $ setViewValue alterará o estado do modelo para sujo e intocado para falso, o que também afetará o estado do formulário, que pode ser problemático por algum tempo.
Atul Chaudhary
2

Oi, você pode tentar os métodos abaixo com a inicialização do modelo.

Aqui você pode inicializar o modelo ng da caixa de texto em dois sentidos

- Com o uso de ng-init

- Com o uso de $ scope em 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
fonte
0

O problema é que você precisa definir o ng-model como o elemento pai para onde deseja definir o ng-value / value. Conforme mencionado pela Angular:

É usado principalmente na entrada [radio] e nos elementos de opção, para que quando o elemento for selecionado, o ngModel desse elemento (ou seu elemento pai de seleção) seja definido como o valor associado.

Por exemplo: este é um código executado:

<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: Neste caso acima, eu já tive a resposta JSON para o ng-model e o valor, estou apenas adicionando outra propriedade ao objeto JS como "MarketPeers". Portanto, o modelo e o valor podem depender de acordo com a necessidade, mas acho que esse processo ajudará a ter o modelo ng e o valor, mas não os tendo no mesmo elemento.

sg28
fonte
0

Eu tive um problema semelhante. Não pude usar value="something"para exibir e editar. Eu tive que usar o comando abaixo dentro do meu <input>junto com o modelo sendo declarado.

[(ngModel)]=userDataToPass.pinCode

Onde tenho a lista de dados no objeto userDataToPasse o item que preciso exibir e editar épinCode .

Para o mesmo, me referi a este vídeo do YouTube

tkrloltkr
fonte
Para este tutorial, o OP está usando o AngularJS, sua referência de vídeo do YT está usando o Angular 4. #
2222