AngularJS default value for ng-model - angularjs

Is it possible to make ng-models get default values, like ''?
I have a form on which I have used jQuery's serialize function, and whenever a a value is not present, it will still include it in the serialized data, E.g. {name: '', age: ''}.
However, when I use try using posting it by using Angular's $http and getting the model from $scope, it appears as undefined when it is empty.

You may also try:
<div ng-init="foo={}">
<input type="text" ng-model="foo.name=''"/>
</div>
or:
<input type="text" ng-init="foo.name=''"/>
it will present:
foo = { name: '', .... }

You can simply define the properties on the model in the scope in advance of using them in your view.
If you show your controller code I'll show you what you need to update to add them to the scope.
It should look something like:
In your js file that defined the app
angular.module("MyModule", []).controller('MyCtrl', ['$scope', function ($scope) {
$scope.myModel = {name:""};
}]);
In your HTML
<input type="text" ng-model="myModel.name"/>
Note I prefer not having global variables/functions so I'm using a different syntax provided by Angular to avoid this and to allow for minification.

You shouldn't need to use jQuery serialize.
Your form should be bound to the scope like this:
<form ng-controller="MyCtrl" ng-submit="submit()">
<input type="text" name="name" ng-model="formData.name">
<input type="text" name="age" ng-model="formData.age">
<input type="submit" value="Submit Form">
</form>
function MyCtrl($scope) {
$scope.formData = {};
$scope.submit = function() {
$http.post('/someUrl', $scope.formData)
};
}
So that in $http you can simply pass $scope.formData.
Is there a more effective way to serialize a form with angularjs?

Sometimes, you don't know if the value is set or not. That's what defaults are for.
I use this when I need to make sure a variable has some value. You can set it in your controller
$scope.possiblyEmptyVariable = $scope.possiblyEmptyVariable || "default value";
Works great without Angular as well
// some object that may or may not have a property 'x' set
var data = {};
// Set default value of "default"
// carefull, values like 'null', false, 0 will still fall to defaults
data.x = data.x || "default";
// Set default value of "default"
// this will not fall to defaults on values like 'null', false, 0
data.x = !"x" in data || "default";
If you need to set a bunch of values, use angular.extend or jQuery.extend
data.z = "value already set";
var defaults = { x: "default", y: 1, z: "default" };
var newData = angular.extend({}, defaults, data);
// { x: "default, y: 1, z: "value already set" }
Hope that helps

Related

AngularJS - How to pass data from View (HTML) to Controller (JS)

I am really new to AngularJS. I want to pass some object from View (HTML) to my controller (JS).
Actually my Client will send me data in HTML and I have to take that data and process that data in my controller and then display the processed output on screen. He will be using some back-end technology called ServiceNow - https://www.servicenow.com/ .
All the solutions I saw had some event like click event or change event, but in my case this has to be done on page load.
I m using Input type hidden for passing the data to the controller, seems like it's not working.
So is there any other way I can do this ?
Here's the code I am trying to use
<div ng-controller="progressController" >
<input type="hidden" value="ABCD" ng-model="testingmodel.testing">
</div>
app.controller('progressController', function($scope) {
console.log($scope.testingmodel.testing);
});
It says undefined when I console.log my variable in Controller.
You're doing console.log(...) too early. At this time your controller doesn't have any information from the view.
The second problem is that you're binding the view to a variable in controller and not the other way around. Your $scope.testingmodel.testing is undefined and it will obviously the value in the view to undefined.
Solution
Use ng-init to initialize the model and the controller's hook $postLink to get the value after everything has been initialized.
Like this
<div ng-controller="progressController" >
<input type="hidden" ng-model="testingmodel.testing" ng-init="testingmodel.testing = 'ABCD'">
</div>
app.controller('progressController', function($scope) {
var $ctrl = this;
$ctrl.$postLink = function() {
console.log($scope.testingmodel.testing);
};
});
Edit: extra tip
I don't recomment using $scope for storing data since it makes the migration to newer angular more difficult.
Use controller instead.
Something like this:
<div ng-controller="progressController as $ctrl" >
<input type="hidden" ng-model="$ctrl.testingmodel.testing" ng-init="$ctrl.testingmodel.testing = 'ABCD'">
</div>
app.controller('progressController', function() {
var $ctrl = this;
$ctrl.$postLink = function() {
console.log($ctrl.testingmodel.testing);
};
});
You should use the ng-change or $watch
<div ng-controller="progressController" >
<input type="hidden" value="ABCD" ng-model="testingmodel.testing" ng-change="change()">
</div>
app.controller('progressController', function($scope) {
$scope.change = function(){
console.log($scope.testingmodel.testing);
}
});
Or:
app.controller('progressController', function($scope) {
$scope.$watch('testingmodel.testing', function(newValue, olValue){
console.log(newValue);
}
});
If you use ng-change, the function is only called if the user changes the value in UI.
If you use $watch anyway, the function is called.
You can't use value attribute for set or get value of any control, angularJS use ngModel for set or get values.
Here You should try like this way
app.controller('progressController', function($scope) {
//from here you can set value of your input
$scope.setValue = function(){
$scope.testingmodel = {}
$scope.testingmodel.testing = 'ABCD';
}
//From here you can get you value
$scope.getValue = function(){
console.log($scope.testingmodel.testing);
}
});
if you want to bind from html side then you should try like below
<input type="text" ng-model="testingmodel.testing">
<input type="hidden" ng-model="testingmodel.testing">

$scope.formName.$setPristine() does not work ; How to reset form in angular?

create a form in angular 1.5
< form name="movieForm" ng-submit="addMovie(movie) ../>
and when I try to reset the form after form submission using
$scope.movieForm.$setPristine()
BUT it gives error in console : Cannot read property '$setPristine' of undefined
form.html
<form name="movieForm" novalidate role="form" ng-submit="movieForm.$valid && addMovie(movie)">
<input type="text" ng-model="movie.name" name="mName" required />
<input type="text" ng-model="movie.star" name="mStar" />
<input type="number" ng-model="movie.year" name="mYear" required />
<input type="submit" value="Save" />
<input type="button" value="Reset" ng-disabled="movieForm.$pristine" ng-click="reset()" />
</form>
app.js
(function() {
var app = angular.module('app', []);
app.controller('movieController', function($scope) {
$scope.title = "Home Page";
$scope.movieData = [{
name: 'PiKu',
star: 'Irrfan Khan',
releaseYear: '2015'
}];
$scope.addMovie = function(movie) {
if(movie && movie.name) {
$scope.movieData.push({
name : movie.name,
star : movie.star,
releaseYear : movie.year
});
}
};
$scope.reset = function() {
$scope.movieForm.$setPristine();
$scope.movieForm.$setUntouched();
};
// **un-commenting below line gives error in console**
//$scope.reset();
});
}());
also checked $scope.movieForm() in console but its undefined ?
What is the issue?
see the DEMO
You're trying to access $scope.movieForm before bindings actually initialized.
Edit
To be clear: $setPristine - not clears form fields. For clearing form fields you can just reset the object that form controls are bound to:
$scope.movie = {};
here's working demo
I think you are using $setPristine wrong.
"This method can be called to remove the 'ng-dirty' class and set the form to its pristine state (ng-pristine class). This method will also propagate to all the controls contained in this form."
So this only clears classes but not the $scope variables. You have to reset $scope.movie variable.
for example I added this default form variable
var defaultForm={
name: "",
star: "",
year: ""
}
and modified your reset code
$scope.reset = function() {
$scope.movie = angular.copy(defaultForm);
$scope.movieForm.$setPristine();
};
This works fine.
Check out the fiddle.
http://output.jsbin.com/hugiye/2
As per the angular docs $setPristine():
"This method can be called to remove the 'ng-dirty' class and set the form to its pristine state (ng-pristine class). This method will also propagate to all the controls contained in this form."
This only reset classes not the actual scope variable.
If you want to set scope variable to default state then you should reset scope variable too.
`
var movie = {
name: '',
star: '',
year: ''
};
and in your reset function you have to add this
$scope.movie = angular.copy(movie);
`

ng-init does not initialize my selected model

I have a select option where I get a list of titles i.e. Mr, Mrs, Dr etc. from an API, the code looks like this in the front end:
<select class="form-control" name="titleSelect" id="titleSelect" ng-options="option.value for option in titleData.availableOptions track by option.key" ng-model="adult[$index].selectedTitle" ng-init="adult[$index].selectedTitle = titleData.availableOptions[0]"></select>
And this in the controller:
var getPassengerTitle = PassengerDetailsAndCardDetailsService.getPassengerTitle();
PassengerDetailsAndCardDetailsService is service, where I get the API data i.e. the title data. Furthermore this service returns a promise.
This is where I set the title Data:
getPassengerTitle.then(function(result){
$scope.availableTitles = angular.fromJson(result.titleList);
$scope.tempListOfTitles = [];
for(var key in $scope.availableTitles){
$scope.tempListOfTitles.push({key : key, value : $scope.availableTitles[key]});
};
$scope.titleData = {
availableOptions: $scope.tempListOfTitles,
};
});
When I try to ng-init to the first option (that is Mr.) it does not work as in a blank option is shown. However when I tried statically defining the titleData in an object it works, could you please help me?
UPDATE:
I failed to mention that the title data is inside an ng-repeat to support input for multiple people/passengers in this case. Therefore I'm using adult[$index] where it creates an ng-model for each person/passenger.
I am not sure if this is the required behavior you want, but if you want to initialise the title on selecting an option you can either use the value from ng-model or use the event handler ng-change. Here is an example jsbin which handles the change and assigns the new value to ng-model. Let me know if this is what you were looking for
try like this.
var myapp = angular.module('app', []);
myapp.controller('Main', function ($scope) {
var vm = this;
vm.adult = {
'selectedTitle':'1'
};
vm.titleData = [
{'key':'0','value':'Mr'},
{'key':'1','value':'Ms'},
{'key':'2','value':'Dr'}
];
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app = "app">
<div ng-controller="Main as ctrl">
<div class="select-style">
<select ng-options="option.key as option.value for option in ctrl.titleData" ng-model="ctrl.adult.selectedTitle"></select>
</div>
</div>
</div>

pre-populated form data is undefined in service

jQuery:
$("#inputParentName").val(response.name);
HTML/Angular Form:
<form role="form" ng-submit="addParentService.addParent()">
<div class="form-group">
<label for="inputParentName">Name</label><input class="form-control" id="inputParentName" value="" type="text" ng-model="addParentService.inputParentName" />
</div>
...
<button class="btn btn-default" type="submit">Submit</button>
</form>
The following code when run diplays my name correctly in the input box.
However in my service when I try to see what the value is for inputParentName I get an undefined error. But, when I type something in to the textbox for inputParentName the typed in value displays.
Controller Code:
myapp.controller('AddParentController', function ($scope, addParentService) {
$scope.addParentService = addParentService;
});
Service Code:
myapp.service('addParentService', function () {
var vm = this;
vm.parent = [];
vm.addParent = function () {
alert(vm.inputParentName);
};
});
What can I do differently so I can get the pre-loaded data to register so that my service recognizes the data?
This is just basic code that I'm trying to get working. I realize it isn't pure AngularJS. I am just trying to see how I can get this to work. I will refactor with directives after everything works as I think it should.
If you want the initial value to be "something" when the view displays, you can (technically) use ng-init, though the docs tell us expressly NOT to do this.
The only appropriate use of ngInit is for aliasing special properties
of ngRepeat, as seen in the demo below. Besides this case, you should
use controllers rather than ngInit to initialize values on a scope.
But if you're just trying to test something, ng-init would look like:
<input ng-model="test.val" ng-init="test.val='something'" />
The preferred way though would be to add the value to the controller $scope.
<input ng-model="test.val" />
Then in your controller:
myapp.controller('MyCtrl', function ($scope) {
$scope.test = {
val: 'something'
}
});
#jme11 and This Answer gave me the insight to the following way I figured out how to get this to work:
jQuery code for Facebook logic:
$("#inputParentName").val(response.name);
$("#inputParentEmail").val(response.email);
$("#inputParentBirthday").val(response.birthday);
angular.element(document.getElementById('inputParentName')).scope().$apply();
angular.element($('#inputParentName')).scope().setName(response.name);
angular.element($('#inputParentEmail')).scope().setEmail(response.email);
angular.element($('#inputParentBirthday')).scope().setBirthday(response.birthday);
My Controller code:
$scope.setName = function (val) {
addParentService.inputParentName = val;
}
$scope.setEmail = function (val) {
addParentService.inputParentEmail = val;
}
$scope.setBirthday = function (val) {
addParentService.inputParentBirthday = val;
}
Service Code:
vm.addParent = function () {
alert(vm.inputParentName);
alert(vm.inputParentBirthday);
alert(vm.inputParentEmail);
alert(vm.inputParentCellPhone);
alert(vm.inputParentCarrier);
};
Now when I'm adding my Parent the values pre-populated from Facebook are usable in my service code.
Again - Thanks to jme11 for helping me solve this.

Angular.js. Two-way data binding breaks when using services

The problem is that SecondName attribute is not updating when I input text in the field.
please look at this code at jsfiddle: http://jsfiddle.net/HEdJF/253/
HTML:
<div ng-app="myApp">
<div ng-controller="FirstCtrl">
<div>
<input type="text" ng-model="Data.FirstName"><!-- Input entered here -->
<br>FirstName is : <strong>{{Data.FirstName}}</strong><!-- Successfully updates here -->
</div>
<hr>
<div ng-controller="SecondCtrl as Second">
SecondName: {{Second.Data.SecondName}}<!-- How do I automatically updated it here? -->
</div>
</div>
</div>
JS:
var myApp = angular.module('myApp', []);
myApp.service('Data', function(){
var obj;
return obj = { FirstName: '54',
SecondName: '22',
f: function(){
obj.FirstName = '1';
obj.SecondName = obj.FirstName;
}
};
});
myApp.controller('FirstCtrl', function( $scope, Data ){
Data.f();
$scope.Data = Data;
});
myApp.controller('SecondCtrl', function( Data ){
Second = this;
Second.Data = Data;
});
It's not going to work like you think it should. This line:
obj.SecondName = obj.FirstName;
creates a new property SecondName equal by value to the FirstName. However since both properties are primitive types (String) there is no connection between them. In other words obj.SecondName does not reference obj.FirstName.
You have two options.
Option 1. (bad) Set up additional watcher on FirstName change, and once that happens update SecondName respectively
$scope.$watch('Data.FirstName', function() { Data.SecondName = Data.FirstName; });
http://jsfiddle.net/HEdJF/254/
Option 2. Don't introduce additional watchers and change your architecture. For example, use FirstName in the second controller too, since they are supposed to be equal.
http://jsfiddle.net/HEdJF/255/
This is a scoping issue because of your nested scopes. Take a look at this website for a clear explanation: http://toddmotto.com/digging-into-angulars-controller-as-syntax/. There's a few different solutions to solve your problem under the Nested Scopes section.
The problem with your code is that the First Controller is just changing the value of Data.FirstName object, hence the changes are not reflecting on your second controller because the value of SecondName does not change after it is initialized in the first controller. So you have to set your Data.SecondName
in your data as well.
Alternatively, you can do this.
<div>
<input type="text" ng-model="Data.FirstName"><!-- Input entered here -->
<br>FirstName is : <strong>{{Data.SecondName=Data.FirstName}}</strong><!-- Successfully updates here -->
</div>
You can also use directives to achieve this functionality, but I guess you are just looking for the above solution.
Cheers!

Resources