Angular js init ng-model from default values

The question:

Say you have a form that has values loaded from database. How do you initialize ng-model?

Example:

<input name="card[description]" ng-model="card.description" value="Visa-4242">

In my controller, $scope.card is undefined initially. Is there a way besides doing something like this?

$scope.card = {
  description: $('myinput').val()
}

The Solutions:

Below are the methods you can try. The first solution is probably the best. Try others if the first one doesn’t work. Senior developers aren’t just copying/pasting – they read the methods carefully & apply them wisely to each case.

Method 1

If you can’t rework your app to do what @blesh suggests (pull JSON data down with $http or $resource and populate $scope), you can use ng-init instead:

<input name="card[description]" ng-model="card.description" ng-init="card.description='Visa-4242'">

See also AngularJS – Value attribute on an input text box is ignored when there is a ng-model used?

Method 2

This is a common mistake in new Angular applications. You don’t want to write your values into your HTML on the server if you can avoid it. If fact, if you can get away from having your server render HTML entirely, all the better.

Ideally, you want to send out your Angular HTML templates, then pull down your values via $http in JSON and put them in your scope.

So if at all possible, do this:

app.controller('MyController', function($scope, $http) {
    $http.get('/getCardInfo.php', function(data) {
       $scope.card = data;
    });
});

<input type="text" ng-model="card.description" />

If you absolutely MUST render your values into your HTML from your server, you could put them in a global variable and access them with $window:

In the header of your page you’d write out:

<head>
   <script>
       window.card = { description: 'foo' };
   </script>
</head>

And then in your controller you’d get it like so:

app.controller('MyController', function($scope, $window) {
   $scope.card = $window.card;
});

I hope that helps.

Method 3

This is an obviously lacking, but easily added fix for AngularJS. Just write a quick directive to set the model value from the input field.

<input name="card[description]" value="Visa-4242" ng-model="card.description" ng-initial>

Here’s my version:

var app = angular.module('forms', []);

app.directive('ngInitial', function() {
  return {
    restrict: 'A',
    controller: [
      '$scope', '$element', '$attrs', '$parse', function($scope, $element, $attrs, $parse) {
        var getter, setter, val;
        val = $attrs.ngInitial || $attrs.value;
        getter = $parse($attrs.ngModel);
        setter = getter.assign;
        setter($scope, val);
      }
    ]
  };
});

Method 4

IMHO the best solution is the @Kevin Stone directive, but I had to upgrade it to work in every conditions (f.e. select, textarea), and this one is working for sure:

    angular.module('app').directive('ngInitial', function($parse) {
        return {
            restrict: "A",
            compile: function($element, $attrs) {
                var initialValue = $attrs.value || $element.val();
                return {
                    pre: function($scope, $element, $attrs) {
                        $parse($attrs.ngModel).assign($scope, initialValue);
                    }
                }
            }
        }
    });

Method 5

You can use a custom directive (with support to textarea, select, radio and checkbox), check out this blog post https://glaucocustodio.github.io/2014/10/20/init-ng-model-from-form-fields-attributes/.

Method 6

You can also use within your HTML code:
ng-init="card.description = 12345"

It is not recommended by Angular, and as mentioned above you should use exclusively your controller.

But it works 🙂

Method 7

I have a simple approach, because i have some heavy validations and masks in my forms. So, i used jquery to get my value again and fire the event “change” to validations:

$('#myidelement').val('123');
$('#myidelement').trigger( "change");

Method 8

As others pointed out, it is not good practice to initialize data on views.
Initializing data on Controllers, however, is recommended. (see http://docs.angularjs.org/guide/controller)

So you can write

<input name="card[description]" ng-model="card.description">

and

$scope.card = { description: 'Visa-4242' };

$http.get('/getCardInfo.php', function(data) {
   $scope.card = data;
});

This way the views do not contain data, and the controller initializes the value while the real values are being loaded.

Method 9

If you like Kevin Stone’s approach above https://stackoverflow.com/a/17823590/584761
consider an easier approach by writing directives for specific tags such as ‘input’.

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

If you go this route you won’t have to worry about adding ng-initial to every tag. It automatically sets the value of the model to the tag’s value attribute. If you do not set the value attribute it will default to an empty string.

Method 10

Here is a server-centric approach:

<html ng-app="project">
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
    <script>
        // Create your module
        var dependencies = [];
        var app = angular.module('project', dependencies);

        // Create a 'defaults' service
        app.value("defaults", /* your server-side JSON here */);

        // Create a controller that uses the service
        app.controller('PageController', function(defaults, $scope) {
            // Populate your model with the service
            $scope.card = defaults;
        });
    </script>

    <body>
        <div ng-controller="PageController">
            <!-- Bind with the standard ng-model approach -->
            <input type="text" ng-model="card.description">
        </div>
    </body>
</html>

It’s the same basic idea as the more popular answers on this question, except $provide.value registers a service that contains your default values.

So, on the server, you could have something like:

{
    description: "Visa-4242"
}

And put it into your page via the server-side tech of your choice. Here’s a Gist: https://gist.github.com/exclsr/c8c391d16319b2d31a43

Method 11

This one is a more generic version of the ideas mentioned above…
It simply checks whether there is any value in the model, and if not, it sets the value to the model.

JS:

function defaultValueDirective() {
    return {
        restrict: 'A',
        controller: [
            '$scope', '$attrs', '$parse',
            function ($scope, $attrs, $parse) {
                var getter = $parse($attrs.ngModel);
                var setter = getter.assign;
                var value = getter();
                if (value === undefined || value === null) {
                    var defaultValueGetter = $parse($attrs.defaultValue);
                    setter($scope, defaultValueGetter());
                }
            }
        ]
    }
}

HTML (usage example):

<select class="form-control"
        ng-options="v for (i, v) in compressionMethods"
        ng-model="action.parameters.Method"
        default-value="'LZMA2'"></select>

Method 12

I tried what @Mark Rajcok suggested. Its working for String values (Visa-4242).
Please refer this fiddle.

From the fiddle:

The same thing that is done in the fiddle can be done using ng-repeat, which everybody could recommend. But after reading the answer given by @Mark Rajcok, i just wanted to try the same for a form with array of profiles.
Things work well untill i have the $scope.profiles = [{},{}]; code in the controller. If i remove this code, im getting errors.
But in normal scenarios i cant print $scope.profiles = [{},{}]; as i print or echo html from the server.
Will it be possible to execute the above, in a similar fashion as @Mark Rajcok did for the string values like <input name="card[description]" ng-model="card.description" ng-init="card.description='Visa-4242'">, without having to echo the JavaScript part from the server.

Method 13

Just added support for select element to Ryan Montgomery “fix”

<select class="input-control" ng-model="regCompModel.numberOfEmployeeId" ng-initial>
    <option value="1af38656-a752-4a98-a827-004a0767a52d"> More than 500</option>
    <option value="233a2783-db42-4fdb-b191-0f97d2d9fd43"> Between 250 and 500</option>
    <option value="2bab0669-550c-4555-ae9f-1fdafdb872e5"> Between 100 and 250</option>
    <option value="d471e43b-196c-46e0-9b32-21e24e5469b4"> Between 50 and 100</option>
    <option value="ccdad63f-69be-449f-8b2c-25f844dd19c1"> Between 20 and 50</option>
    <option value="e00637a2-e3e8-4883-9e11-94e58af6e4b7" selected> Less then 20</option>
</select>

app.directive('ngInitial', function () {
return {
    restrict: 'A',
    controller: ['$scope', '$element', '$attrs', '$parse', function ($scope, $element, $attrs, $parse) {
        val = $attrs.sbInitial || $attrs.value || $element.val() || $element.text()
        getter = $parse($attrs.ngModel)
        setter = getter.assign
        setter($scope, val)
    }]
}

});

Method 14

If you have the init value in the URL like mypage/id, then in the controller of the angular JS you can use location.pathname to find the id and assign it to the model you want.


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Comment