How do I toggle field required attribute after ng-click? - angularjs

I have a dropdown list in a repeater that should toggle my custom "required" attribute. I tried ng-show but the display="none" attribute is all that was added. My options are:-
1- Add/remove the input field and set bird.Stuff, not just hide it because it is still required.
2- Add/remove 'required' attribute on the input field.
js
$scope.validateParticipants = function (type) {
if (type == "Single") {
this.donation.Participants = "1";
}
else
this.donation.Participants = "";
}
html
<div ng-repeat="bird in animalTest.birds">
#(Html.DropDownList("Type", (IEnumerable<SelectListItem>)ViewBag.BirdList, new { ng_model = "bird.Type", ng_change = "validateRequired(bird.Type)", required = "Type is required" }))
...
<input data-ng-show="bird.Type == 'Endangered'" id="stuff" type="number" data-ng-model="bird.Stuff" required = "Number of Volunteers required"/>
</div>
Thanks for the help in advance!

Use ng-required. This takes an angular expression and adds the required attribute if the expression is true.
<input type="number" data-ng-model="bird.Stuff" ng-required="donation.Participants > 0"/>

Related

Remove empty option in the select using ng-model

I am new to angular js. In my code user changes the value of radio buttons. And depending on the value of the selected radio button, a piece of code is loaded from the ng-switch
HTML:
<body ng-app="">
<div ng-repeat="button in modes">
<label>
<input type="radio" ng-model="data.mode" value="{{button.value}}" ng-click="clearObjectIdModal()" name="e_modes">
{button.label}}
</label>
</div>
<div ng-switch on="data.mode">
<div ng-switch-when="client">
<label for="e_selected_object_item_id">Select Client name: </label>
<select id="e_selected_object_item_id" name="e_selected_object_item_id" ng-model="currentDataItem.object_id" required>
<option ng-repeat="item in customersListArr" value="{{ item.id }}">{{ item.Name }}</option>
</select>
</div>
<div ng-switch-when="agent">
// This part is similar to the previous one
</div>
</div>
</body>
Controller part:
$scope.data = {};
$scope.setFile = function () {
if ($scope.data.mode == 'client')
return 'client';
else if ($scope.data.mode == 'agent')
return 'agent';
$scope.modes = [{
value: 'client',
label: 'Client'
},{
value: 'agent',
label: 'Agent'
}];
$scope.currentDataItem = data; // data is preloaded from inputs in form
There is also a ng-click="clearObjectIdModal()" that clears the model when switching radio buttons:
$scope.clearObjectIdModal = function() {
$scope.currentDataItem = "";
}
The problem is that every time when the radio button is switched to the select value, which dynamically changes, the value of the first option in it becomes equal to undefined. Because in the array from where these options are built there is no such object_id (This is the id that is not there, so an empty field is drawn).
That is, there are all works. But the first option in the select(after switching to another radio button) is rendered as an empty string.
There are thoughts, how it can be fixed?
I'm not sure if I understand you problem correctly but I would suggest a few improvements.
change your setFile function to as follows
$scope.setFile = function (){return $scope.data.mode;}
I also do not see the closing brackets for your function in your code. Besides if your function will only return the data.mode then why need the function?
I would suggest initialize your data object properly like:
$scope.data = {mode:'client'};
Change your clearObjectIdModal function as:
$scope.clearObjectIdModal = function(mode)
{
$scope.currentDataItem = "";
$scope.data.mode=mode;
}
and in your HTML use it as ng-click="clearObjectIdModal(button.mode)"
So in function clearObjectIdModal() I wrote:
$scope.clearObjectIdModal = function() {
if ($scope.e_data["mode"] == 'client') {
if ($scope.customersListArr.length > 0) {
$scope.currentDataItem.object_id = $scope.customersListArr[0]['id'];
}
}
else if ($scope.e_data["mode"] == 'agent') {
if ($scope.agentsListArr.length > 0) {
$scope.currentDataItem.object_id = $scope.agentsListArr[0]['id'];
}
}
}
And after this when I change radio buttons the first option in current select(which every time is changed) will be not empty.
Also the problem with an additional empty option is possible to solve when you add a title as the first item in the list:
<option value="" disabled>Select</option>

How to add css class dynamically to input type html element in angular js controller function?

Requirement: Create a generic controller function in Angular JS that will cater to all the input types.
What you want then is to:
add the filled css class when the form field has a value, and
remove the filled css class when the form field doesn't have a value
do both of the above using a reusable function in an angular controller.
You can achieve this using Angular's built-in ng-class directive:
HTML:
<input
id="renewccCVV"
type="number"
class="form-control"
ng-class="isFilled(RenewCard.cvv)"
ng-model="RenewCard.cvv"
maxlength="4" />
JS:
$scope.isFilled = function(value){
return (!!value) ? "filled" : "";
}
Example Plunk
Add the below code to Angular js controller.
'filled' is the css class that I want to make use of. I am passing the $event from my ng-blur event in HTML input control.
$scope.addCssClass = function (event) {
if (event !== null && event.target !== null) {
if (event.target.value !== "") {
if (event.target.className.search('filled') < 0) {
var classes = event.target.className;
classes += ' filled';
event.target.className = classes;
}
}
else {
event.target.classList.remove('filled');
}
}
};
Here is the snippet of HTML code.
<input id="renewccCVV" type="number" class="form-control" ng-blur="addCssClass($event)" ng-model="RenewCard.cvv" maxlength="4" />
If my input control has value and css class 'filled' is not added to ng-class , then add the css class, if the input already has css class and value is not null, do not add the class. When the value from input control is removed, then remove the css class from the classList.

How to enable/disable validations dynamically in angular js

My form have two buttons say "Draft" and "Submit", so for draft some validations are applicable and same for submit button. I have one variable cmpnStatus it is initialised with value 1. For draft value of cpmnStatus is 0 and for submit it is 1.
<div class="form-group">
<label>Short Description<span class="red-ast">*</span></label><br/>
<textarea ng-model="shortdesc" ng-change="shortchange(shortdesc)" class="form-control b-rad3" ng-required="cmpnStatus == 0"></textarea>
</div>
<button type="submit" ng-click="campform.$valid && submitDraft(campform)" class="btn btn-draft">Save as draft</button>
<button type="submit" class="btn btn-launch" ng-click="campform.$valid && submitCampaign()">Submit for Approval</button>
Below is the code of submitDraft function.
$scope.submitDraft = function(form){
$scope.cmpnStatus = 0;
if(form.$valid) {
alert("valid");
} else {
alert("invalid");
}
//Then call to save data in db
};
My problem is when I click on draft form shows valid and save data in db and after that it points the required validation because initially value of cpmnStatus is 1 and according to condition required validation condition fails. Again I click on draft button now required validation is working fine because value of cpmnStatus changes from 1 to 0. I want that when user click on draft button and when the value of cpmnStatus changes it should be show me required validation (even in first click) according to condition(ng-required="cmpnStatus == 0"). Is there any other way to do the same ?
1st change the html to be like this :
<button type="submit" ng-disabled="campform.$error" ng-click="submitDraft(campform)" class="btn btn-draft">Save as draft</button>
<button type="submit" class="btn btn-launch" ng-disabled="campform.$error" ng-click="submitCampaign()">Submit for Approval</button>
Disabling button for user when form is invalid is better.
About the cmpnStatusThings i suggest you to use a checkbox or radio button to switch between draft or approval mode :
<input type="checkbox" ng-model="cmpnStatus" ng-true-value="1" ng-false-value="0"/>
Radio sample :
<input type="radio" ng-model="cmpnStatus" ng-value="1"/>
<input type="radio" ng-model="cmpnStatus" ng-value="0" />
Thank you for the clarification. Here is a function I am currently using:
$scope.checkIfSaveAllowed = function() {
var timer = setTimeout(function() {
var validControls = document.getElementsByClassName('has-feedback ng-scope has-success');
var modalSaveBtn = document.getElementById('eventModalSaveBtn');
if (validControls.length >= 3) {
if (validControls.length == 4) {
modalSaveBtn.disabled = false;
}
else if (validControls[0].id != "commentFormGroup" && validControls[1].id != "commentFormGroup" && validControls[2].id != "commentFormGroup") {
modalSaveBtn.disabled = false;
}
}
else {
modalSaveBtn.disabled = true;
}
}, 50);
}
I call this function on every field in the form using an ng-change. That else if in the middle is how I accomplish what you are asking about. The commentFormGroup is not required in my code. I check if (1) there are only three valid fields and (2) none of those valid fields are the optional field, then the button should be enabled.
In your case, you could have two functions called by the ng-change, one for each button or you could specify when one should be disabled and the other enabled.
Alternatively, you could display a customized error message instead of disabling the button. I hope this helps.

Adding a custom type to angular-schema-form - datepicker

I'm trying to add a custom type to angular-schema-form for the ui-bootstrap datepicker.
I've followed the instructions, but my field isn't rendered when opening the form.
My module, loaded into the page:
angular.module('schemaForm-datepicker', ['schemaForm']).config(
[
'schemaFormProvider', 'schemaFormDecoratorsProvider', 'sfPathProvider',
function (schemaFormProvider, schemaFormDecoratorsProvider, sfPathProvider) {
var picker = function (name, schema, options) {
console.log(schema.type);
if (schema.type === 'date') {
console.log("found");
var f = schemaFormProvider.stdFormObj(name, schema, options);
f.key = options.path;
f.type = 'datepicker';
options.lookup[sfPathProvider.stringify(options.path)] = f;
return f;
}
};
schemaFormProvider.defaults.object.unshift(picker);
//Add to the bootstrap directive
schemaFormDecoratorsProvider.addMapping('bootstrapDecorator', 'datepicker',
'template/datepicker.html');
schemaFormDecoratorsProvider.createDirective('datepicker',
'template/datepicker.html');
}
]);
My template:
<div class="form-group" ng-class="{'has-error': hasError()}">
<label class="control-label" ng-show="showTitle()">{{form.title}}</label>
<input type="text"
class="form-control"
schema-validate="form"
ng-model="$$value$$"
placeholder="Date" />
<span class="help-block" sf-message="form.description"></span>
</div>
Schema Data:
{"type":"object","properties":{"FirstName":{"type":"string","title":"FirstName"},"LastName":{"type":"string","title":"LastName"},"CompanyName":{"type":"string","title":"CompanyName"},"EmailAddress":{"type":"string","title":"EmailAddress"},"JoinDate":{"type":"date","title":"JoinDate"}}}
Any ideas?
Assuming you are making changes date type.
You have to include your type of field in schema.
To implement add on, you have to
Add a new type of field
Add a new decorator
As it states in documentation, your new type should be second parameter to addMapping, then provide template and make sure you declare that type in your schema to display.
$scope.form =
[
{
key: "birthday",
type: "datepicker"
}
];
In your case, you have to change date to:
"JoinDate": {"type":"datepicker","title":"JoinDate"}.
note: datepicker already exists you can use that form type. but your custom impelementation will work as long as you dont include angular-schema-form-datepicker
documentation does have some information but it is confusing for first time.
https://github.com/json-schema-form/angular-schema-form/blob/master/docs/extending.md.
sorry, i cant comment so posting as answer.

How can I validate an ng-repeated dropdown category selector?

I created a nested category model. In order to select a category for a product, you see a dropdown with the main categories. When you select one, a new dropdown is added to the right with the child categories to the one you selected. This repeats until you reach the last level. When this happens $scope.product.category_id is set. I want to invalidate the whole set of fields when $scope.product.category_id is null.
I've been using angular-bootstrap-show-errors for validation and I tried to mix it with ui-utils to achieve this one, using a custom function: validate_category().
Here's the HTML I used:
<span ng-repeat="parent_id in category_dropdown_parents" show-errors="{ skipFormGroupCheck: true }">
<select class="form-control" name="category_id"
ng-init="selected_category[$index] = init_select($index);"
ng-model="selected_category[$index]"
ng-options="category.name for category in (categories | filter : { parent_id: parent_id } : true ) track by category.id "
ng-change="select_category(selected_category[$index], $index)"
ui-validate="'validate_category()'" // added this to work with ui-utils
>
</select>
<span ng-if="$index+1 != category_dropdown_parents.length">/</span>
</span>
And this is my simple validation function:
$scope.validate_category = function() {
return ( $scope.product.category_id !== null
&& $scope.product.category_id !== undefined);
}
But this is not working. Ideas?
EDIT: I just realized, that the problem with this is that the validation function on ui-validate is executed after the ng-change function, so it's never able to check the $scope.product.category_id update.
Your select is using
ng-model="selected_category[$index]"
but the validation function is using
$scope.product.category_id
Shouldn't it be using
ui-validate="'validate_category($index)'"
and
$scope.validate_category = function($index) {
return($scope.selected_category[$index] !== null
&& $scope.selected_category[$index] !== undefined);
}
This is not the ideal answer but it's the best I could get. Shame on me, this was too simple:
<select class="form-control" name="category_id"
ng-init="selected_category[$index] = init_select($index);"
ng-model="selected_category[$index]"
ng-options="category.name for category in (categories | filter : { parent_id: parent_id } : true ) track by category.id "
ng-change="select_category(selected_category[$index], $index)"
required // !!!
>
</select>
That's it, just added the required attribute. The problem with this is that since the I'm not validating product.category_id but just validating all the dropdowns to be not empty. I guess I
'll have to rely on the code on select_category().

Resources