I have a text input within a directive that I want to use as a filter for displaying a list of items, but I don't want the entering of a filter to affect the containing forms $pristine value so that entering a filter doesn't enable the save and show the Reset. How do I do this in angularJS (1.6.x)?
directive template
<form name='myForm'>
<input placeholder="Filter" class='form-control' type='text' ng-model='vm.searchText'>
<ul><li ng-repeat='item in vm.list | filter:vm.searchText'/></ul>
<div>
<br>
<button class='btn btn-primary' ng-click='vm.save()' ng-disabled="myForm.$pristine || frmCrm.$invalid">Save</button>
<div class='pull-right'>
<button class='btn btn-warning' ng-click="vm.reset()" ng-hide="myForm.$pristine">Reset</button>
</div>
</div>
</form>
Yes I know I could easily put the filter input outside the form in this example, but in my actual situation that isn't feasible as I have nested forms and one that wraps basically the whole page.
here's plnkr example:
http://plnkr.co/edit/y1dJLPbyvlZuIW1f7ey9
You can override the $setDirty and $setPristine methods of the ngModel:
angular.module('xyz').directive('dontCheck', function() {
return {
restrict: 'A',
require: 'ngModel',
link: function(scope, element, attrs, ngModelCtrl) {
//set to empty functions
ngModelCtrl.$setPristine = angular.noop;
ngModelCtrl.$setDirty = angular.noop;
}
}
});
I've forked your plunker, you can try the solution:
http://plnkr.co/edit/6UVTQjJtwu4mOXVt7sPT?p=preview
Edit:
Updated plunker to follow your code style. I will leave the code here as is.
Related
I have a form and some fields get disabled with various conditions. Is there a way to determine is a model disabled (without running the same ng-disabled condition in the controller)?
If you have a form in your view, there would be a form object with the name you specified for the form on your controller scope which you can access inside your controller.
However you cannot access attributes (disabled is an attribute on your input) that from controller level (vs you can easily access input attributes from a directive):
app.directive('mydir', function ($compile) {
return {
require: '^form',
link: function(scope, element, attrs, formCtrl) {
var allDisabledInputs = $(formCtrl).find(':input:disabled');
//do stuff here
}
};
});
And on your form:
<form name="someForm" my-dir >
<input name="input1" />
<input name="input2" disabled />
</form>
I want to make a validation on the sum of two fields, both are numeric input, but the total must not be larger than 100.
So I thought I'd make a hidden input which reads the total from my controller, and create a custom validationdirective to check the value to be <= 100 and create a span which checks whether that input is valid or not and then show/hide it.
But the input is bound to a function (which adds the two fields together) on my controller, so I can not use ng-model.
So I thought I use ng-bind, but then my validation directive complained about this:
require: 'ngModel',, because I don't have a ng-model anymore.
So I deleted that require, but then the ctrl.$validators was not present anymore and that gave me an error....
And now I am lost :-)
My validationdirective is this:
angular.module(Config.name).directive('maxvalue', function () {
return {
require: 'ngModel',
link: function (scope, elm, attrs, ctrl) {
ctrl.$validators.maxvalue = function (modelValue, viewValue) {
//validation here
};
}
};
});
Can you give my a way to solve this?
EDIT
maybe my question is broader: I have more of these like alidations, where the validation is not tied to a single input field. I also have two buttons which a user can click (sort of a radio button, but then implemented with 2 buttons). I also want to show a span when no button is clicked + make the form invalid.
But I do not know how to say to the form 'you are invalid' neither from the form itself neither from the controller.
For set form or input valid\invalid you can use $setValidity.
But i recommend use special library use-form-error.
Example of using you can see on jsfiddle
angular.module('ExampleApp', ['use', 'ngMessages'])
.controller('ExampleController', function($scope) {
});
.errors {
color: maroon
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.9/angular-messages.min.js"></script>
<script src="https://cdn.rawgit.com/Stepan-Kasyanenko/use-form-error/master/src/use-form-error.js"></script>
<div ng-app="ExampleApp">
<div ng-controller="ExampleController">
<form name="myForm">
<label>Enter your digit 1:</label>
<input type="text" ng-model="digit1" name="myDigit1" />
<br>
<label>Enter your digit 2:</label>
<input type="text" ng-model="digit2" name="myDigit3" />
<div use-form-error="isGeaterHundred" use-error-expression="digit1*1+digit2*1>100" ng-messages="myForm.$error" class="errors">
<div ng-message="isGeaterHundred">Your sum is greated then 100</div>
</div>
<input type="submit" ng-disabled="myForm.$invalid">
</form>
</div>
</div>
I would like my form labels to display a red asterisk next to the label when the corresponding form control has a required attribute.
Instead of hard coding the asterisk, I desire a way to append the asterisk to the label dynamically during page load if the label's corresponding input, select or textarea is required (the element the label corresponds to).
I created the directive below, and the directive works. But is there a better, more native way to accomplish my goal? This directive finds all the div.form-group containers and adds a red * character after the label if the corresponding form control inside the div.form-group has a required attribute.
myApp.directive('labelsRequired',function(){
return {
restrict: 'A',
require: 'ngModel',
link: function(scope, elem, attrs){
elem.find('div.form-group').each(function(i, formGroup){
var formControls = $(formGroup).find('input, select, textarea');
console.log(formControls)
if (0 !== formControls.length && undefined !== $(formControls[0]).attr('required')){
jLabel = $(formGroup).find('label');
jLabel.html(jLabel.html()+ "<span class='red-color'>*</span>");
}
})
}
}
});
The directive assumes all inputs, selects, and textareas are inside a div.form-group container.
<div class='form-group'>
<label>First Name</label><!-- this label gets an asterisk -->
<input name='fname' required />
</div>
<div class='form-group'>
<label>Favorite Food</label><!-- this label does not get an asterisk -->
<input name='favFood' />
</div>
You don't need a directive, there are built-in form properties you can use with filters like ng-show, look:
<div ng-app="myApp" ng-controller="myCtrl">
<form name="userForm" novalidate>
<div class='form-group'>
<label>First Name</label>
<input name='fname' ng-model="fname" required />
<label ng-show="userForm.fname.$dirty && userForm.fname.$error.required">* Required field</label>
</div>
<button type="submit">Submit</button>
</form>
</div>
If you define an ng-model for the input you can deal with it looking if it is filled or not. You can also check it only after the user "dirty" it with userForm.fname.$dirty, so the label will be shown only after a user try to input something but then clear it. Try playing with it here JSFiddle
Building off of Corey's answer:
I just used compile rather than link, as I saw that my required attribute was not being applied to my input elements. I also included a select tag for any dropdowns that I had.
app.directive('inputRequired', function () {
return {
restrict: 'A',
compile: function (elem) {
elem.find('label').append("<sup><i class='fa fa-asterisk'></i></sup>");
elem.find('input').attr('required', 'required');
elem.find('select').attr('required', 'required');
}
};
});
If you're not using the built-in Angular validation, you could restructure your directive and attach it to your .form-group element. Like this:
app.directive('inputRequired', function() {
return {
restrict: 'A',
link: function(scope, elem, attr) {
elem.find('label').append('<span>*</span>');
elem.find('input').attr('required', 'required');
}
};
});
Your HTML would then look like:
<div class="form-group" input-required>
<label>Name</label>
<input name="name" />
</div>
<div class="form-group">
<label>Food</label>
<input name="food" />
</div>
However, if you haven't looked into the built-in validation with Angular, I would recommend using it.
This might come too late and it might not be too elegant but it works, if anyone needs it:
<label ng-show="userForm.fname.$validators.hasOwnProperty('required')">* Required field</label>
I want to have an input with text that is disabled but also selects all when you click on it.
Here's a working plnkr
http://plnkr.co/edit/o2hu8MCU2bjVPPFhhBLx?p=info
Here's my directive:
app.directive('selectAll', function () {
return {
restrict: 'A',
link: function (scope, element, attrs) {
element.on('click', function () {
this.select();
});
}
};
})
and the html:
<input type="text" disabled select-All size="60" value="http://google.com"> - directive with disabled
<br>
<input type="text" select-All size="60" value="http://google.com"> - directive without disabled
I would like for the input to not be editable but still allow for the select all directive to work.
I tried adding the disabled functionality to the directive but I sometimes use this directive for thing other than input as well.
Any guidance?
so, garuuk, use readonly instead of disabled and just style your input to look disabled. Maybe slightly opaque
I found a plunkr courtesy of #user2789093 in question AngularJS: Radio buttons do not work with Bootstrap 3 and modified it some to reflect my issue: http://plnkr.co/edit/sBfSD2?p=info
In angular, I don't think I am supposed to manipulate the DOM, so does anyone have any thoughts on how I could set the intial bootstrap3 radio button to checked without using jquery to check an ID of the inputs?
Once you bind ng-model and set the value attribute correctly, the issue doesn't seem to be the value of the resulting radio button selection. It is only that the bootstrap labels expect an active class to be applied if the selection is made. So you can fix this by adding an ng-class to each selection:
<div class="btn-group col-lg-3" data-toggle="buttons">
<label class="btn btn-default" ng-class="{active: test.currentVal == 'true'}" ng-click="setTransactionDebit('true')">
<input type="radio" value="true" ng-model="test.currentVal"></input>
True
</label>
<label class="btn btn-default" ng-class="{active: test.currentVal == 'false'}" ng-click="setTransactionDebit('false')">
<input type="radio" value="false" ng-model="test.currentVal"></input>
False
</label>
</div>
Here is a working fork of your plunker.
This directive sets the active class on a radio input's parent element when the model value equals the input value, and removes the active class otherwise.
/* Bs radio not setting active class on label because model changes too slowly
* before $render() in bsRadio inside AngularStrap. */
myAppDirectives.directive('bsRadioFix',[function() {
return {
restrict: 'A',
require: 'ngModel',
link: function(scope, elem, attrs, controller){
scope.$watch(attrs.ngModel, function(newVal, oldVal){
elem.parent().toggleClass('active', newVal == attrs.value)
})
}
}
}]);