222

Using AngularJS if I set a simple input text box value to something like "bob" below. The value does not display if the ng-model attribute is added.

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

Anyone know of a simple work around to default this input to something and keep the ng-model? I tried to use a ng-bind with the default value but that seems not to work either.

Robert Koritnik
  • 103,639
  • 52
  • 277
  • 404
HelloWorld
  • 4,251
  • 8
  • 36
  • 60

10 Answers10

224

That's desired behavior, you should define the model in the controller, not in the view.

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


function Main($scope) {
  $scope.rootFolders = 'bob';
}
Vojta
  • 23,061
  • 5
  • 49
  • 46
  • 11
    Thanks. But in this case, the model is set in the controller. And in the Angular docs, it's always the same, data is set in controller. But my controller is in a JS file. How to do when on an "edit" form ? How to pass default form data to controller "the angular way"? – Byscripts Dec 04 '13 at 11:06
  • 8
    This doesn't work for me however adding additional attribute ng-init shown by Mark Rajcok (ng-init="rootFolders='Bob'") works fine. – Kaizar Laxmidhar Sep 11 '14 at 13:24
  • And how do I set the default value if I have an input field like: ? – shish Dec 03 '15 at 22:17
189

Vojta described the "Angular way", but if you really need to make this work, @urbanek recently posted a workaround using 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
  • 362,217
  • 114
  • 495
  • 492
  • 33
    You may not need the 'value="Bob"' part. – Mark Rajcok Dec 08 '12 at 06:35
  • 2
    +1 but, As mentioned in one of the posts on the linked discussion, it should be avoided (as logically it's less correct & it makes testing harder). – 0xc0de Mar 13 '13 at 05:24
  • 1
    This method works fine if you use a model value as well on v1.2. <... ng-init="rootFolders=someModelAttribute"...> – dmcqu314 Apr 29 '14 at 16:54
  • @MarkRajcok, you have so many great AngularJS postings on Stack Overflow! Thank you for all of the time you've devoted to sharing your insights with the S.O. community. I'm sure I speak for many relieved developers when I say that we sincerely appreciate all of the hours you've saved us! – Jeremy Moritz Sep 12 '14 at 15:19
  • 1
    Really appreciate Mark's answer as that solved my issue. I do confirm that we DONT need `value="Bob"` part in the input tag. – Devner Nov 17 '14 at 13:44
  • Plz dont use value ='something' => just for being careful.. dont spoil the concept – Sami Nov 24 '15 at 15:50
68

Overriding the input directive does seem to do the job. I made some minor alterations to Dan Hunsaker's code:

  • Added a check for ngModel before trying to use $parse().assign() on fields without a ngModel attributes.
  • Corrected the assign() function param order.
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);
      }
    }
  };
});
Bourbia Brahim
  • 14,459
  • 4
  • 39
  • 52
Ivan Breet
  • 680
  • 5
  • 5
  • This is the best answer I found!... solves my problem in an elegant way. I had to capture a value on a hidden input (a Symfony form token, generated in the server). – PachinSV Jul 26 '14 at 16:58
  • This is not only clever but the best solution. In my case, I can't set the default value of ng-model on the controller because is a PHP form, if server-side validation fails, the form will refresh and whatever is in ng-model will be lost deleting the input value too. – Luis Elizondo Sep 30 '14 at 23:39
  • 2
    This seems the best solution if you also want a basic version of your HTML form to work without JavaScript. – Darren Dec 02 '14 at 21:31
  • Excellent solution that really should be a non-default configurable option within angular itself. – Gracie Nov 06 '15 at 15:18
  • Thanks for your solution. How would you solve number input issue? It throws an error https://docs.angularjs.org/error/ngModel/numfmt?p0=20.12 – mate.gvo Dec 06 '17 at 14:33
  • @mate.gwozdz Maybe check for `attrs.type` like `if(attrs.type && attrs.type === 'number') $parse(attrs.ngModel).assign(scope, parseFloat(attrs.value)); else $parse(attrs.ngModel).assign(scope, attrs.value); ` – David R. Jan 18 '18 at 19:29
21

The Angular way

The correct Angular way to do this is to write a single page app, AJAX in the form template, then populate it dynamically from the model. The model is not populated from the form by default because the model is the single source of truth. Instead Angular will go the other way and try to populate the form from the model.

If however, you don't have time to start over from scratch

If you have an app written, this might involve some fairly hefty architectural changes. If you're trying to use Angular to enhance an existing form, rather than constructing an entire single page app from scratch, you can pull the value from the form and store it in the scope at link time using a directive. Angular will then bind the value in the scope back to the form and keep it in sync.

Using a directive

You can use a relatively simple directive to pull the value from the form and load it in to the current scope. Here I've defined an initFromForm directive.

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

You can see I've defined a couple of fallbacks to get a model name. You can use this directive in conjunction with the ngModel directive, or bind to something other than $scope if you prefer.

Use it like this:

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

Note this will also work with textareas, and select dropdowns.

<textarea name="test" ng-model="toaster.test" init-from-form>hello</textarea>
{{toaster.test}}
superluminary
  • 47,086
  • 25
  • 151
  • 148
  • Here's a packed module that implements a solution similar to what is described here https://github.com/platanus/angular-keep-values – Agustin Jun 23 '15 at 20:38
  • 1
    Great solution, but it will only work with `input="text"`. If you have a `number` it will throw _Model is not of type `number`_ https://docs.angularjs.org/error/ngModel/numfmt?p0=333 – smoksnes Jul 25 '16 at 07:51
  • 2
    To support numbers you may add `if (attrs.type === "number") val = parseInt(val);` – smoksnes Jul 25 '16 at 07:55
  • @smoksnes - you are absolutely correct. I have updated the answer :) – superluminary Jul 26 '16 at 19:04
7

Update: My original answer involved having the controller contain DOM-aware code, which breaks Angular conventions in favor of HTML. @dmackerman mentioned directives in a comment on my answer, and I completely missed that until just now. With that input, here's the right way to do this without breaking Angular or HTML conventions:


There's also a way to get both - grab the value of the element and use that to update the model in a directive:

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

and then:

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

You can of course modify the above directive to do more with the value attribute before setting the model to its value, including using $parse(attrs.value, scope) to treat the value attribute as an Angular expression (though I'd probably use a different [custom] attribute for that, personally, so the standard HTML attributes are consistently treated as constants).

Also, there is a similar question over at Making data templated in available to ng-model which may also be of interest.

Community
  • 1
  • 1
Dan Hunsaker
  • 309
  • 2
  • 6
  • You shouldn't be doing any DOM manipulation/discovery in your controllers. Should use a directive instead. – dmackerman Sep 20 '13 at 14:43
  • 2
    I explicitly mentioned that drawback in my answer. You *shouldn't*, but you *can*. It all depends on whether you find it more important to follow Angular's or HTML's conventions. Because Angular does break HTML. – Dan Hunsaker Oct 18 '13 at 17:14
  • 3
    Oh, I *am* a dummy. Completely missed the bit about using a directive. Answer updated accordingly. Sincerest apologies for being a jerk to you, @dmackerman. – Dan Hunsaker Dec 04 '13 at 23:02
  • Thanks for the directive! It gave me ideas to apply in a project I'm working on where I generate some content server side and then have to use it as my model in the client. – ggalmazor Mar 12 '14 at 11:26
  • Glad I could help. Of course, generally speaking, you'll want to build your server-side content as JSON and have your app manipulate the model based on that, but sometimes it's useful to have other options, and this is but one. – Dan Hunsaker Mar 13 '14 at 23:22
7

If you use AngularJs ngModel directive, remember that the value of value attribute does not bind on ngModel field.You have to init it by yourself and the best way to do it,is

<input type="text"
       id="rootFolder"
       ng-init="rootFolders = 'Bob'"
       ng-model="rootFolders"
       disabled="disabled"
       value="Bob"
       size="40"/>
Hazarapet Tunanyan
  • 2,809
  • 26
  • 30
5

This is a slight modification to the earlier answers...

There is no need for $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
  • 419
  • 3
  • 8
  • keep in mind that ngModelController.$setViewValue will change the model state to dirty and pristine to false which will also effect the form state which can be pain some time. – Atul Chaudhary May 26 '15 at 02:27
2

Hi you can try below methods with initialize of model.

Here you can initialize ng-model of textbox two way

- With use of ng-init

- With use of $scope in 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:'bhatt.bhaskar88@gmail.com',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
  • 1,399
  • 13
  • 19
0

The issue is that you have to set the ng-model to the parent element to where you want to set the ng-value/value . As mentioned by Angular:

It is mainly used on input[radio] and option elements, so that when the element is selected, the ngModel of that element (or its select parent element) is set to the bound value.

Eg:This is an executed code :

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

Note: In this above case I alreday had the JSON response to the ng-model and the value, I am just adding another property to the JS object as "MarketPeers". So the model and value may depend according to the need, but I think this process will help, to have both ng-model and value but not having them on the same element.

Tunaki
  • 132,869
  • 46
  • 340
  • 423
sg28
  • 1,363
  • 9
  • 19
0

I had similar issue. I was not able to use value="something" to display and edit. I had to use the below command inside my <input>along withe ng model being declared.

[(ngModel)]=userDataToPass.pinCode

Where I have the list of data in the object userDataToPass and the item that I need to display and edit is pinCode.

For the same , I referred to this YouTube video

trupthi
  • 51
  • 3