unable to set validity on form - angularjs

I am trying to set a validation token "fooname" for a form through its controller, on the click of a button based on a condition.
However it looks like form.$error.fooname is not getting set. {{form.$error.fooname}} is parsed as null.
javascript:
angular.module('app', [])
.controller('controller', ['$scope', function ($scope) {
$scope.data={};
$scope.data.validate=function () {
if ($scope.data.name=="foo") {
$scope.form.$setValidity("fooname",true);
}
};
}]);
html:
<form name="form" ng-controller="controller"
ng-submit="data.validate()" ng-init="form.$setValidity('fooname',false)"
novalidate>
<input type="text" ng-model="data.name" name="name"/>
<button type="submit">Submit</button><br/>
{{data}}<br/>
{{form.$error.fooname}}
</form>

The $setValidity function defined on form controller, takes three parameter as per the source code:
form.$setValidity = function(validationToken, isValid, control) {
Also to fail a validation you need to set the value to false not true. Change your expression to
$scope.form.$setValidity("fooname",true,$scope.form);
Also the $error for FormController returns the list of controllers that are failing the validation, so you need to adjust you code accordingly.

Related

Can't access form from inside AngularJS controller

I am trying to manually reset a form from inside an AngularJS controller but I can't access it using either $scope, or using controllerAs. When I log $scope.SupportForm, it returns undefined.
HTML
<form name="supportForm" id="supportForm" novalidate>
<label for="message">Message</label>
<textarea name="message" id="message" model="$ctrl.formData.message" maxlength="5000" required></textarea>
<button type="submit" data-ng-click="$ctrl.submitForm($ctrl.formData)" data-ng-disabled="supportForm.$invalid">
Request support
</button>
</form>
Contoller
function GeneralSupportController($scope, $state, $timeout, $stateParams, SupportService, $uibModal) {
var vm = this;
vm.formData = {};
vm.submitForm = submitForm;
function submitForm(data) {
console.log('$scope.supportForm : ', $scope.supportForm)
}
}
I have also tried adding ngModel to the form, but it also doesn't work.
Question
Any idea why the form isn't being assigned to the scope?
Form is assigned to scope in your code. (https://plnkr.co/edit/7eYvApaW36DrRmvK >> it works) I guess actually you have following:
<div ng-if="...">
<form name=...
In this case form is assigned to nested scope of ng-if not controller scope. You have several solutions:
pass form to submit function $ctrl.submitForm(supportForm... useful when u have several forms
put form into controller <form name="$ctrl.supportForm" do it when u have one form

Angular, how to conditionally style a required field?

I do not want to display validation of my form until the submit button is pressed. When the button is pressed the form should be submitted if valid, and if not submitted invalid fields should become highlighted in red.
For legacy reasons, I am importing a css file which defines input:invalid with a red background, as a result any input field marked as required will always display as red.
I attempt to make this work in the below fiddle by conditionally setting ng-required. Which somewhat works, with the exception that the first time the submit button is clicked the form $valid evaluates to true.
How can I conditionally set ng-required such that my field is only styled after the submit button has been clicked, and the form $valid consistently evaluates correctly based on the field being empty/non-empty?
https://jsfiddle.net/dk89dhp2/19/
You have two issues. The first is simply a typo.
this:
ng-required="myForm.showErrors"
should be:
ng-required="showErrors"
to match what's in the model.
Once you fix this, you will notice it almost works except the dialog says the form is valid when it should not. To give the digest cycle a chance to run, you can wrap whatever you need to do in a $timeout. (Could also use a proxy function that sets the value of showErrors then calls the submit function from a $timeout)
$scope.myForm.submit = function() {
$scope.showErrors = true;
$timeout(function() {
alert("form validity is: " + $scope.myFormNg.$valid);
});
};
updated jsfiddle
This works:
https://jsfiddle.net/q6ur26mt/
I just changed the ng-required value to true.
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.5/angular.min.js"></script>
<body ng-app="myapp">
<div ng-controller="MyController" >
<form name="myFormNg">
<input type="text" ng-class="myForm.getCssClassForField(myFormNg.id)" ng-required="true"
name="id" ng-model="myForm.id" />
ID
<br/><br/>
<button type="button" ng-click="myForm.submit()">submit</button>
</form>
</div>
</body>
<script>
angular.module("myapp", [])
.controller("MyController", function($scope) {
$scope.myForm = {};
$scope.showErrors = false;
$scope.myForm.submit = function() {
$scope.showErrors = true;
alert("form validity is: " + $scope.myFormNg.$valid);
};
$scope.myForm.getCssClassForField = function(field) {
return field.$invalid && $scope.showErrors ? 'invalid' : '';
};
});
</script>

Form object undefined when using Angularjs blockUI

I'm using Angularjs, version 1.5, and i have specified a form in my html as follows:
<div class="row" ng-show="showForm">
<form class="form-horizontal" name="myForm" novalidate role="form">
</form>
</div>
In the corresponding controller i have a function that resets the form and calls pristine:
$scope.myForm.$setPristine();
Until now everything works fine.
I then try to use blockUI (https://github.com/McNull/angular-block-ui)
by changing the above div to:
<div class="row" ng-show="showForm" block-ui="myBlock">
so the only addition is: block-ui="myBlock"
however, when the controller code runs i get:
TypeError: Cannot read property '$setPristine' of undefined
When debugging i see that the form object does not exist! When removing block-ui="myBlock", everything works fine again.
Any ideas?
Thanks in advance
Try something like these:
function MyCtrl($scope, $timeout, blockUI) {
$scope.form = {};
$scope.submit = function() {
var myBlockUI = blockUI.instances.get('myForm');
$scope.form.myForm.$setPristine();
myBlockUI.start();
$timeout(function() {
// Stop the block after some async operation.
myBlockUI.stop();
}, 3000);
};
}
and view:
<form name="form.myForm" novalidate ng-submit="submit()" block-ui="myForm">
<input type="text">
<button>
Submit
</button>
</form>
I have same trouble like you with undefined form on $scope, but found these trick with using additional object form on SO. Plunk here.

injecting error manually to form

Is there any way to inject error manually to form, I know the way via directive but not sure how can inject error from the controller.
<div ng-controller="myController">
<form name="createForm">
<div ng-repeat="item in someItems">
<input type="text" ng-change="customValidation()" />
</div>
<input type="button" ng-disabled="createForm.$invalid" value="Submit" />
</form>
</div>
controller
function myController($scope) {
$scope.customValidation = function() {
//do some validation and made createForm valid/invalid based on it
};
}
Yes, You can do it in two ways.
instead of Creaeform.$invalid. You can use some value inside your scope.
You should set the value true or false depending on the validation result of the input. If this doesn't make sense to you, give a comment. I'll give some code.
another way is passing the form object itself to the controller and set the createForm.$valid = false; in the controller.

Angular JS - Change path, Same controller, don't reload scope

I know it's been asked so many times here and I found it too. But it could not solve my problem.
Here is the case. I have one AngularJS application.
I have a list page. I have a button to add. When I click on add button, a pop-up window will come with a form. I want to change the URL when the pop-up comes but in the same controller.
Also I would like to add some other buttons on each, some html display as popup-or other location, but same controller without reloading all scope when url changes.
What I have tried.
app.js
var WebClientApp = angular.module('WebClientApp', [
'ngCookies',
'ngResource',
'ngSanitize',
'ui.bootstrap',
'ngRoute'
]);
WebClientApp.config(function ($routeProvider) {
$routeProvider
.when('/groups/:template', {
templateUrl: 'groups.html',
controller: 'GroupCtrl'
}
groups.html
<div>
<button ng-click="showAdd()">Add Group</button>
<div ng-include src="views/listpage.html">
<div ng-if="addGroupModal" class="popup-modal">
<form name="addGroup" ng-submit="addandEditGroup()">
<input type="text" ng-model="group.name">
</form>
<div>
<div ng-if="editGroupModal" class="popup-modal">
<form name="editGroup" ng-submit="saveGroup()">
<input type="text" ng-model="group.name">
<input type="text" ng-model="group.desc">
<input type="text" ng-model="group.id">
</form>
<div>
Controllers.js
WebClientApp.controller('GroupCtrl', function ($scope,$http, $location, $routeParams) {
$scope.group = {};
$scope.showAdd=function(){
$location.path('/groups/add');
}
var template = $routeParams.template;
switch(template){
case 'add':
loadAddPage();
break;
case 'edit':
loadEditPage();
break;
default:
loadListPageHideAll();
break;
}
function loadAddPage() {
$scope.addGroupModal=true;
$scope.editGroupModal=false;
}
function loadEditPage(){
$scope.addGroupModal=false;
$scope.editGroupModal=true;
}
function loadListPageHideAll() {
$scope.addGroupModal=false;
$scope.editGroupModal=false;
// connect to server and list all groups
}
$scope.addandEditGroup = function() {
$location.path('/groups/edit');
}
$scope.saveGroup = function() {
// Save group with $scope.group.
$location.path('/groups');
}
});
When I click on add button, it will show the add form. When I enter group name, and submit, it should show edit form after changing url with the group name filled in the form. But when I try, the value of group object becomes empty since the url is changing. I added the following in controller, but don't know what to do exactly after.
$scope.$on('$routeChangeStart', function(event, present, last) {
console.log(event,present,last);
});
How to assign the scope variables of last route to present route scope. I tried reload on search to false also, But it didnt work.
There might be an error here :
function loadEditPage(){
$scope.addGroupModal=false;
$scope.editGroupModal=true;
}
There are probably some typos in the HTML template code you posted, but what you are basically doing is hiding the parent addGroupModal and showing the child editGroupModal. Remove the nesting and the tags like this:
<div ng-if="addGroupModal" class="popup-modal">
<form name="addGroup" ng-submit="addandEditGroup()">
<input type="text" ng-model="group.name">
</form>
</div>
<div>
<div ng-if="editGroupModal" class="popup-modal">
<form name="editGroup" ng-submit="saveGroup()">
<input type="text" ng-model="group.name">
<input type="text" ng-model="group.desc">
<input type="text" ng-model="group.id">
</form>
</div>
</div>
Here is the plunkr ( hit enter to submit the form): http://plnkr.co/edit/MGT8HZ4lpgVWCkWlt8Ak?p=preview
If this is what you want to acheive, honestly you are complicating things ... There are simpler solutions.
I see! What you want to acheive is to have a reference of the old group variable before the route was changed... And you want to do that using the same controller...
Ok, to get the group from the last controller, you are half way there . You have to store the group somewhere because the targetScopes and currentScopes you receive in the $routeChange listeners don't point to the scopes.
http://plnkr.co/edit/HfK3fhVtZ4bxHtpiFR3B?p=preview
$scope.group = $rootScope.group || {};
$scope.$on('$routeChangeStart', function(event, present, last) {
console.log('start change route');
$rootScope.group = event.currentScope.group;
console.log('target scope group ',event.currentScope.group);
});
I agree the rootScope might not be the best place to keep that variable, but you can also put it inside an angular constant of variable.

Resources