Angular js init ng-model from default values
AngularjsAngularjs Problem Overview
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()
}
Angularjs Solutions
Solution 1 - Angularjs
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'">
Solution 2 - Angularjs
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.
Solution 3 - Angularjs
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);
}
]
};
});
Solution 4 - Angularjs
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);
}
}
}
}
});
Solution 5 - Angularjs
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/.
Solution 6 - Angularjs
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 :)
Solution 7 - Angularjs
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");
Solution 8 - Angularjs
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.
Solution 9 - Angularjs
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.
Solution 10 - Angularjs
Here is a server-centric approach:
<html ng-app="project">
<script src="http://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
Solution 11 - Angularjs
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>
Solution 12 - Angularjs
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.
Solution 13 - Angularjs
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)
}]
}
});
Solution 14 - Angularjs
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.