Push values to array in controller - angularjs

I have input fields on the DOM that I'm capturing using ng-model.
In my controller, I have an array:
app.controller('mainCtrl', function() {
// set an empty array
self.manualEntry = [];
/**
* ensure form validation
* #returns boolean - ng-disabled value
*/
self.disableForm = function() {
if (self.manualEntry.length <= 0) {
return true;
}
else {
return false;
}
};
});
In my view, I have input fields:
<form>
<input placeholder="John" ng-model="mainCtrl.manualEntry.firstName"/>
<input placeholder="Smith" ng-model="mainCtrl.manualEntry.lastName"/>
</form>
<button type="submit"
ng-disabled="mainCtrl.disableForm()"
title="Submit">Submit
</button>
I thought that $scope automatically updated the model for use in the controller. I thought using dot notation in the DOM would push these values to the array.
When I update these values, the submit button on the form remains disabled (i.e. disableForm() returns true).
How can I push these values to self.manualEntry when they change or are updated on the DOM?

I am making a large assumption on what you want but it seems regular form validation is the way to go for this. Demo at http://plnkr.co/edit/Nzmk3R8eU0fmbBZRrTBa?p=info.
Controller Code
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
// set an empty array
var self = this;
self.manualEntry = {};
//Let HTML5 handle the form validation itself
self.printInfo = function() {
console.log(self.manualEntry);
};
});
HTML Code:
<body ng-controller="MainCtrl as mainCtrl">
<form ng-submit="mainCtrl.printInfo()">
<input placeholder="John" ng-model="mainCtrl.manualEntry.firstName" ng-required="true" />
<input placeholder="Smith" ng-model="mainCtrl.manualEntry.lastName" ng-required="true" />
<button type="submit" title="Submit">Submit
</button>
</form>
</body>

Related

textarea two way binding not working with ng-model

i am facing a weird issue with angular js.
I am using a textarea and have a default value for that. But when i change the value in the textarea manually its not being updated in my controller.
Also the other scope is not being binded into the default value.
my Html
<div ng-controller="req" class ="ng-cloak">
<form name="dynamic_fields_tm" ng-submit="goDynamicTm()">
<input type="text" ng-model="tmDynam.one">
<input type="submit" value="Go!" ng-show="tm_dynamic1">
</form>
<div class="request" ng-if="postrequest_disp">
<textarea>{{postrequest}}</textarea>
</div>
</div>
Js
app.controller('req', function($scope ,$rootScope ,$http ,$location ,$window, $timeout) {
$scope.postrequest = "{'event':{'event_id':" + $scope.tmDynam.one+"} ,'note':'Testing', 'is_display_price': 'true', 'ticket_ids':["+$scope.tmDynam.two+"] }";
$scope.postrequest_disp = true;
$scope.tm_dynamic1 = true;
$scope.goDynamicTm = function()
{
console.log($scope.postrequest);
}
});
First Issue. in the console i am only receiving the default value..but not the updated value when i update in textarea.
Second is the $scop.tmDynam.one is not being updated with the $scope.postrequest.
ALso i have used ng-model instead of {{}}. BUt still issue persists
Please help
Since you are using textarea inside ng-if it creates an isolated scope.So you need to access the parent scope. Use the ng-model in textarea with the $parent.postrequest.
Demo
var app = angular.module("myApp",[]);
app.controller('req', function($scope ,$rootScope ,$http ,$location ,$window, $timeout) {
$scope.tmDynam = {one:'', two: ''}
$scope.postrequest = "{'event':{'event_id':" + $scope.tmDynam.one+"} ,'note':'Testing', 'is_display_price': 'true', 'ticket_ids':["+$scope.tmDynam.two+"] }";
$scope.postrequest_disp = true;
$scope.tm_dynamic1 = true;
$scope.goDynamicTm = function()
{ $scope.postrequest = "{'event':{'event_id':" + $scope.tmDynam.one+"} ,'note':'Testing', 'is_display_price': 'true', 'ticket_ids':["+$scope.tmDynam.two+"] }";
console.log($scope.postrequest);
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="req" class ="ng-cloak">
<form name="dynamic_fields_tm" ng-submit="goDynamicTm()">
<input type="text" ng-model="tmDynam.one">
<input type="submit" value="Go!" ng-show="tm_dynamic1">
</form>
<div class="request" ng-if="postrequest_disp">
<textarea ng-model="$parent.postrequest"></textarea>
</div>
</div>
</div>

How Can I set the ng-disabled value of a button based on the original value of a model

I am attempting to disable a button which is next to a checkbox, but only if the underlying model of the checkbox is different from the original value. Pristine on it's own doesn't work because technically the form has been changed. My solution was to grab the original value and toggle the pristine value of the form based on whether current value is equal to that value.
I'm assuming there is a better way which I am unaware of.
<div ng-controller="MyCtrl">
<div ng-form="form">
<div class="checkbox">
<label>
<input type="checkbox" ng-click="toggle(form)" ng-model="foo.bar">{{ foo.bar }}
</label>
</div>
<button class="btn btn-primary" ng-disabled="form.$pristine" ng-click="save(form)">Button</button>
</div>
</div>
angular.module("app", [])
.controller("MyCtrl", function($scope, $timeout){
//catch when scope is first set
$scope.$watch("foo", function(curr, prev){
if(curr && !prev)
$scope.original = curr.bar;
});
//assume this is being set by some other scope
$timeout(function(){
$scope.foo = {
bar: true
};
}, 500);
$scope.toggle = function(form){
if($scope.original == $scope.foo.bar)
form.$setPristine();
console.log(form.$pristine);
};
$scope.save = function(form){
$scope.original = $scope.foo.bar;
form.$setPristine();
};
});
I don't understand why you use $pristine, or a $watch.
Just store the original value in a scope variable when the controller is instantiated, and use
ng-disabled="foo.bar != original"

Is there a better way to gather angular form data (for submit)

this is my solution, but I do not know if it is the right way.
html:
<div ng-controller='myctrl as mc'>
<form name='mc.form' ng-submit='mc.submit'>
<input type='email' name='email' />
<input type='user' name='user' />
<button type='submit'>submit</button>
</form>
</div>
javascript:
angular.module('myapp').controller('myctrl', ['$scope', function myctrl($scope) {
var th = this
this.submit = function(form) {
if(!th.form.$invalid) postToServer(getFormData())
}
//I checked the form object, no helper method like this
function getFormData() {
var res = {}
angular.forEach(th.form, function(value, key) {
if(key[0] !== '$') res[key] = value.$modelValue
})
return res
}
function postToServer(data) {
//do post to server
console.log(data)
}
}])
This is an example of basic Angular Forms usage. You want to use ng-modal and within your Controller $scope you should have a Object for your form data that you will be processing. If you give the form a name attribute, it will bind this to your Controller $scope so that you can access within your controller, for example <form name="myForm"> == $scope.myForm.
Please find this live example below, if you open your Console F12 menu you will see the form data when it is submitted.
http://plnkr.co/edit/XSiPnDdB5umxOzu0V3Pf?p=preview
<form name="myForm" ng-submit="submitForm()">
Email: <input name="email" type="email" ng-model="formData.email" />
<br />
User: <input name="user" type="text" ng-model="formData.user" />
<br />
<button type="submit">Submit</button>
</form>
<script>
angular.module('myApp', [])
.controller('mainCtrl', function($scope) {
$scope.formData = {};
$scope.submitForm = function() {
// do form submit logic
// this is the object declared in the controller
// binded with ng-model
console.log('$scope.formData');
console.log($scope.formData);
// this is the ng-form $scope binded into
// the Controller via <form name="name">
// this hold more that just the form data
// validation errors form example
console.log('$scope.myForm');
console.log($scope.myForm);
};
});
</script>
You should use ng-model, it will all the form data will be sent as an object
<div ng-controller='myctrl as mc'>
<form name='mc.form' ng-submit='mc.submit'>
<input ng-model='formData.email' name='email' />
<input ng-model='formData.user' name='user' />
<button type='submit'>submit</button>
</form>
</div>
The input value will bind to the properties of an object call formData in controller
angular.module('myapp').controller('myctrl', ['$scope',
function myctrl($scope) {
var th = this;
$scope.formData= {}; //Initialise the object
this.submit = function(form) {
if (!th.form.$invalid) postToServer();
}
function postToServer() {
//do post to server
console.log($scope.formData); //The value of input will bind to the property of formData
}
}
])

Dynamically add input fields with Angular and perform validation on blur

Form at start has 1 input field for address. Bellow there is a link that when clicked adds another input and so on. There is no limitation in number of fields.
Is there more elegant way of adding new elements in model collection in Angular? I'm currently using an array of null elements, and on the link click I just push another null in that array so ng-repeat picks it up. And when I want to submit form I go through that array and filter out elements that are not null.
When input field is focused out/blurred there should be validation performed. I'm currently calling a function from controller on ng-blur event but I'm having trouble passing it current input text value.
Fiddle
HTML:
<div ng-app="TestApp">
<div ng-controller="MainCtrl">
<div ng-repeat="field in fields track by $index">
<input type="text" placeholder="enter the address" ng-model="fields[$index]" ng-blur="validate()" />
</div>
+ Add another input
<br/>
<br/>
List addresses
</div>
</div>
JS:
var app = angular.module("TestApp", []);
app.controller("MainCtrl", function($scope){
$scope.fields = [null];
$scope.addresses = [];
$scope.addField = function(){
$scope.fields.push(null);
};
$scope.listAddresses = function(){
for(var i in $scope.fields){
if($scope.fields[i] !== null){
$scope.addresses[i] = $scope.fields[i];
}
}
alert("Addresses: " + $scope.addresses);
};
$scope.validate = function(){
console.log("Should validate current input");
};
});
Instead of using two arrays, use one and store objects:
$scope.items =
[
{ address: '' }
];
It will now be clearer what the model of the input is, as you don't have to use $index. You can also pass the item to the validate function:
<div ng-repeat="item in items">
<input type="text" ng-model="item.address" ng-blur="validate(item)" placeholder="enter the address" />
</div>
Adding item:
$scope.addItem = function() {
$scope.items.push({ address: '' });
};
Demo: http://plnkr.co/edit/sPlPO2DfrgNHf5AasYlH?p=preview

Validate Input fields only on submit angularjs

I am trying to show a Validation Summary, a Div on top of the page with all the Validation error messages in angularjs, on form submit.
I am using the below logic to show/ hide the top div with validation messages,
<div class="alert alert-error" ng-show="submitted && myForm.$invalid">
</div>
I am setting the variable submitted to true on save button click. It's working Okay the first time, but after the first submission, if enter the value for the input field(required field) and clear it, it's kicking off the validation(the top div shows).
Is there a way to show the validation div, only on the submit of the form and not when the user clears the input field ?
UPDATE
$scope.save = function (myForm) {
$scope.submitted = true;
if (myForm.$invalid) {
return;
}
$scope.submitted = false;
}
Thanks !
Hmm one way to do it would be to watch the FormController's property $dirty and $setPristine() method, and use a variable hasError to show the error or not.
See this plunker as an example
JAVASCRIPT
controller('AppController', ['$scope', function($scope) {
$scope.hasError = false;
$scope.$watch('theForm.$dirty', function() {
$scope.hasError = false;
$scope.theForm.$setPristine();
});
$scope.save = function() {
$scope.hasError = $scope.theForm.$invalid;
if($scope.hasError) {
// perform error routine
} else {
// perform save routine
}
};
}]);
HTML
<body ng-controller="AppController">
<div class="error" ng-show="hasError">This is an error</div>
<form name="theForm" ng-submit="save()" novalidate>
<input type="text" name="text1" ng-model="text1" required>
<input type="text" name="text2" ng-model="text2" required>
<button type="submit">Submit</button>
</form>
</body>
Make sure you are setting submitted to false upon display of your validation div else it'll show up after each additional validation call.
$scope.save = function (myForm) {
$scope.submitted = true;
if (myForm.$invalid) {
$scope.submitted = false;
return;
}
}

Resources