Disable Angular Form Validation on single input (url) - angularjs

I'm building an Angular form with a URL field that can be formatted either with a prefix (http://) or without. Using Angular's default url validation requires http://, so I plugged in the following regex, which accepts with and without a prefix:
<input type="text" id="siteAddress" name="siteAddress" ng-model="user.url" ng-pattern="/^(https?:\/\/)?([\dA-Za-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$/" required>
This works great, but when I set type="url", Angular's validation overwrites my custom ng-pattern. This form is for mobile users only, so the type="url" is important so that they receive the correct keyboard, and so their mobile OS does not attempt to autocorrect their input.
Is it possible to use type="url" without Angular applying its default validation, or is it possible to modify Angular's default validation so that it accepts no url prefix?
Thanks!

It seems like there is no official API to do that but you always can override default directive or use your directive with higher priority to change the standard behavior.
For example, angular's input directive gets the type from $attributes object, so you may remove this attribute.
directive('ignoreType', function() {
return {
priority: 500,
compile: function(el, attrs) {
attrs.$set('type',
null, //to delete type from attributes object
false //to preserve type attribute in DOM
);
}
}
});
Here is jsfiddle for it.
Of course this solution may also break behavior of other directives which work with type attribute, so use it carefully.

An idea would be to test the $removeControl method from the FormController to see if the native url validation would go off...
http://docs.angularjs.org/api/ng.directive:form.FormController
Inside your controller you would do something like this:
$scope.form.$removeControl('siteAddress');
Im not sure exactly what it will do, since I haven't got the chance to test it out and the docs about this are incomplete... let me know if this works please.
Hope that could give you some help.

Related

ng-change not working after first upload

http://embed.plnkr.co/keaGc3Y4Pmgfs04HJgnC/
Here is the link of my code.I am trying to validate my upload by disabling the load data button when the file is empty.
It is working for the first time,but when the next time I upload the file,ng-change is not working and the button is still showing disabled although I have uploaded the next file.
I am a beginner in AngularJS,so i might be doing some basic mistake.please help.
Since you are trying to upload the same file again, the onChange event will not fire, because it is the same file. To resolve this issue, you need to unset the input field after you uploaded the file. Unfortunately, you have to use jQuery (or get the element wit vanilla js) for this. So, in your onFileLoad function you could do something like this:
angular.element("input[type='file']").val(null); // Unset Input
$scope.filename = undefined; // Unset $scope property
Note that this is not the "angular" way of doing this. It would be better to move this into a directive, cause you should not manipulate the DOM within a Controller.
Update:
As said before, you need to include jQuery for this to work. Angular's jqLite does not support selecting DOM elements by its type. So, either you include jQuery (needs to be loaded before angular!) or you modify the code so you can use vanilla JS or jqlite.
Please change, initially
vm.foo = 'Monthly'
<input type="radio" name="{{item.deviceId}}" ng-model="renew.foo" ng-value="'Monthly'" ng-click="renew.updatePref(item, 'Monthly')">Monthly
<input type="radio" name="{{item.deviceId}}" ng-model="renew.bar" ng-value="'Yearly'" ng-click="renew.updatePref(item, 'Yearly')">Yearly
you have use ng-change, change event never happen as value for these input remains always same. use,
var vm = this;
you are also using ng-value="Monthly", Monthly is variable (undefiend) for ng-value. either use value="Monthly" or ng-value="'Monthly'".

ui-bootstrap pagination with filter

after some research and study of examples I implemented a pagniation with a filter function.
Im very new to angular, so I need your help if this application is ok or it has some bugs/logical errors.
The target is to select a collection (in this application load1 or load2) and create new objects, manipulate existing, or delete some of them. On every update of the data, it has to be checked if the pagination is synchronous to the collection size.
If the user enters something into the search field, a watcher in the controller is fired for updating the filtered data:
$scope.$watch('search.name', function (newVal, oldVal) {
$scope.filtered = filterFilter($scope.items, {name: newVal});
}, true);
I would be very happy if some of you angular pros can look into this code and give me some feedback. I want to use this in a productive system, so every answer would be great!
Here is a working plunkr: http://plnkr.co/edit/j9DVahEm7y1j5MfsRk1F?p=preview
Thank you!
Watchers are heavy if you use them explicitly throughout your large application.
Use ng-change instead. Also, by passing true to that watcher means you're deep watching which is really a bad thing to do, since it will check each property of the object in the array which is performance intensive.
Since I can't see that you need old and new value for a reason, you can simply use $scope.search.name. Whenever you type in something, $scope.search.name has the updated value. Just need to call a function on ng-change.
DEMO: http://plnkr.co/edit/TWjEoM3oPdfrHfcru7LH?p=preview
Remove watch and use:
$scope.updateSearch = function () {
$scope.filtered = filterFilter($scope.items, {name: $scope.search.name});
};
In HTML:
<label>Search:</label> <input type="text" ng-model="search.name" placeholder="Search" ng-change="updateSearch()" />
Previous answer is still the correct, but you will have to make sure to replace the "page" inside the pagination tag and change it to ng-model.
From the changelog (https://github.com/angular-ui/bootstrap/blob/master/CHANGELOG.md)
Since 0.11.0:
Both pagination and pager are now integrated with ngModelController.
page is replaced from ng-model.

Using a variable for ng-required doesn't re-evaluate fields

I have a form where my intent is for required fields to not always be enforced. For example if the user is saving the document as a draft they can enter as little information as they like, if they try and publish the document then they have to enter all the required fields. I'm using a boolean on the controller which changes according to which button has been pressed e.g.
<input type="text" ng-model="field2" ng-required="enforceRequired" />
The problem is that the fields are not re-evaluated when the boolean changes so the form is submitted and then it becomes invalid. Please see this JSFiddle to see what I mean. If you fill in field1 and then click publish it will succeed on the first click and THEN become invalid.
How can I force the validation to run before the form is submitted?
Yarons is right, you are changing the value too late, by late I mean after the form validations has been run. What you can do as a workaround is, after changing the required value, let angular do another cycle and then show your alert. This can be done via $timeout service, although I must mention that it is usually not a good practise to change the flow of your digest actions. It gets pretty messy pretty soon.
Change your publish function like this (and don't forget to inject $timeout)
$scope.publish = function () {
$scope.enforceRequired = true;
$timeout(function () {
if ($scope.form.$valid) {
alert("Published!");
}
});
};
Working fiddle: http://jsfiddle.net/bh9q00Le/14/
The problem is that you are changing the value of enforceRequired in the middle of the digest loop, so the watchers are not re-rendered before you check the input fields' validity (read about digest here).
If you want to get around it, I suggest one of the following methods:
change the value of enforceRequired before you call saveDraft or publish. see example.
call $scope.$apply() after you change the value of enforceRequired. see another example.

Form validation with AngularJS and dynamic fields

I'm stuck with strange problem regarding AngularJS form validation. If a dynamically added control (a textbox, for instance) requires validation and is removed from the form, the form will remain invalid if the removed control was invalid.
That last sentence is a bit confusing. See it in action with this plnkr preview (or see the plnkr editor).
I've checked the FormController API. Based on the documentation, there's no method to provoke any kind of form validation status refresh, although the AngularJS source code defines methods like $removeControl() and $setValidity() in the FormController.
Is there a standard way to circumvent the validation issue?
I came across this before, see this answer for more detail: https://stackoverflow.com/a/15192773/317180
Apparently this is an active bug.
A workaround is to provide a hidden counter that is incremented when elements are changed, this forces the form to revalidate:
In template:
<input type="hidden" ng-bind="abc" />
In controller:
$scope.remove = function(position) {
$scope.items.splice(position, 1);
$scope.abc += 1;
}

Angular - Form validation issues when using form input directive

I have been trying to build a form input directive which will generate a form input based on the model and the model attributes .
For example,
if the field is name and type is text, the directive will return a input html control,
if the field is a list, then it will return a select box
and so on
These inputs are generated using ng-repeat in the view. The inputs are bound to the model in the scope. This is working fine. However, the form validation fails; i.e if the input controls are invalid, the main form still shows the form is valid.
I have put up a simple plunkr to illustrate the issue - http://plnkr.co/edit/R3NTJK?p=preview
NOTE : I have actually nested the form, as the input name field is also dynamically generated from the scope model.
I have been trying to a get hold on this from the past 2 days and this is really driving me nuts.
I m not sure if I m missing something.
I would really appreciate if some one could help me out with this.
Update:
Use the following link function:
link: function linkFn(scope,elem,attr){
var jqLiteWrappedElement =
angular.element('<input type="url" name="socialUrl" ng-model="social.url">');
elem.replaceWith(jqLiteWrappedElement);
$compile(jqLiteWrappedElement)(scope);
}
Plunker.
For reasons I don't understand, the replaceWith() must be executed before the call to $compile. If someone can explain why this is so, we'd appreciate it!
Update2: in the comments below, Artem mentioned that the DOM must be modified before the linking function is called, so this also works:
var myElem = angular.element('some html');
var linkFn = $compile(myElem);
element.replaceWith(myElem);
linkFn(scope);
Original answer:
Instead of the link function, just use a template in your directive:
template: '<input type="url" name="socialUrl" ng-model="social.url">'

Resources