I am using angular.js 1.6.4 version. I created a directive for server-side validation and I see that it's firing when I am loading the form, which is wrong. I only want to fire my code when I changed the value. My HTML code is
<div class="col-xs-6">
<div class="controls">
<label class="control-label"
ng-hide="editRetailTrackingForm.barcode.$dirty && editRetailTrackingForm.barcode.$error">
#Labels.barcode:
</label>
<input type="text" name="barcode"
ng-model="currentItem.barcode"
sm-code-unique-validator
table-name="items"
column-to-test="barcode"
error-message="itemBarcodeErrorMessage"
primary-key="currentItem.itemId"
ng-model-options="{ updateOn: 'blur', debounce: { default : 500, blur: 0 }}"
class="form-control"
ng-maxlength="100" />
<div ng-class="{loading:editRetailTrackingForm.barcode.$pending}">#String.Format(Messages.validatingX, Labels.barcode)</div>
<div ng-if="editRetailTrackingForm.barcode.$dirty">
<div ng-messages="editRetailTrackingForm.barcode.$error">
<div ng-message="maxlength">
<label class="field-validation-error control-label-error animate-show">
#String.Format(Messages.cannotExceed, Labels.barcode, "100")
</label>
</div>
<div ng-message="smCodeUnique">
<div class="info-text-block-error">
{{itemBarcodeErrorMessage}}
</div>
</div>
</div>
</div>
</div>
</div>
and my directive code is very similar to http://www.codelord.net/2014/11/02/angularjs-1-dot-3-taste-async-validators/
return {
require: "ngModel",
scope: {
primaryKey: "=?",
tableName: "#",
columnToTest: "#",
errorMessage: "=?"
},
link: function ($scope, element, attrs, ngModel) {
ngModel.$asyncValidators.smCodeUnique = function (modelValue, viewValue) {
if (!viewValue) {
return true;
}
let codeObject = {
id: $scope.primaryKey, tableName: $scope.tableName,
columnToTest: $scope.columnToTest, code: viewValue
};
return services.Http.put('api/items/checkCodeUniqueness', codeObject).then(
function (response) {
if (!response.data.isValid) {
$scope.errorMessage = response.data.errorMessage;
return services.Deferred.reject(response.data.errorMessage);
}
return true;
}
);
};
}
};
When I am debugging my code I see that server side code is running multiple times when I only instantiate my form (and not even open the correct tab where this field is).
So, how should I change my directive or ng-options to only fire validations when I changed my value?
Related
HTML Code :
<div id="createConfigManagementDivId"
class="panel-portal">
<h1 class="titlebar ng-binding">
GUI Configuration Data</h1>
<div class="grid span-20 centered vlead-2">
<ul class="tabs">
<li>
Boolean Data
<div class="content">
<h2> Boolean Data</h2>
<div>
<div ng-repeat="chk in boolchkbxs">
<label>{{chk.label}}</label>
<input type="checkbox" ng-change="GetBoolValue(chk)" ng-model="chk.Selected" />
</div>
</div>
</div>
</li>
</ul>
</div>
<div class="text-right buttonbar">
<button id="applyButton">Apply</button>
<button id="updateCacheButton">Update GUI cache</button>
<button id="clearButton" ng-click="clearForm()" >Cancel</button>
</div>
<script type="text/javascript">
$(document).ready(function(){
});
</script>
Controller:
$scope.boolchkbxs = [{ label: "XXXX", Selected: true }];
$scope.GetBoolValue = function () {
var message = "";
for (var i = 0; i < $scope.boolchkbxs.length; i++) {
console.log($scope.boolchkbxs[i].Selected);
if ($scope.boolchkbxs[i].Selected) {
var lableName = $scope.boolchkbxs[i].label;
message += lableName + ",";
}
}
}
But I am unable to get the latest value modified by user in checkbox in the above code. $Scope.boolchkbxs[i].Selected always returns true (which is a default value);
Can someone please help me to solve the issue ??
Even I have tried samething for a single checkbox without ng-repeat, still the value it returns default and not the updated value.
The function GetBoolValue is not getting called when i change the value of checkbok
GetBoolValue should be called when change the chackbox value. i think this should be you expect. Now you can get the value of selected check box and find the label and calculate message.
The issue is due to setting the value of checkbox using jQuery. So ng-model value doesn't get updated.
To solve the issue, I have written checkboxWithChangeHandler in my controller (jsfiddle).
html
<div class="btn-group" data-toggle="buttons">
<label class="btn btn-primary">
<input type="checkbox" ng-model="check"/> Default
</label>
<label class="btn btn-primary">
<input type="checkbox" ng-model="check" checkbox-with-change-handler/> Checkbox with change handler
</label>
</div>
<div class="btn-group" data-toggle="buttons">
<label class="btn btn-primary">
<input type="radio" name="options" ng-model="radio" value="onclick"/> Default
</label>
<label class="btn btn-primary">
<input type="radio" name="options" ng-model="radio" value="onchange" radio-with-change-handler/> Radio with change handler
</label>
</div>
<br/>
Checkbox: <span ng-bind="check"></span><br/>
Radio: <span ng-bind="radio"></span>
javascript:
var app = angular.module('app', []);
app.directive('checkboxWithChangeHandler', [function checkboxWithChangeHandler() {
return {
replace: false,
require: 'ngModel',
scope: false,
link: function (scope, element, attr, ngModelCtrl) {
$(element).change(function () {
scope.$apply(function () {
ngModelCtrl.$setViewValue(element[0].checked);
});
});
}
};
}]);
app.directive('radioWithChangeHandler', [function checkboxWithChangeHandler() {
return {
replace: false,
require: 'ngModel',
scope: false,
link: function (scope, element, attr, ngModelCtrl) {
$(element).change(function () {
if (element[0].checked) {
scope.$apply(function() {
ngModelCtrl.$setViewValue(attr.value);
});
}
});
}
};
}]);
I've written a filter in AngularJS, which was working fine when using it with ng-options on an input select.
Since I needed a more powerful select box with additional functionality, I've written a directive.
The directive has an isolated scope with the filtered options being passed via a two-way binding. Unfortunately, my filter produces a "10 $digest() iterations reached"-error.
This is my filter:
angularAMD.filter('gasUsableInSpacer', function(){
return function(gasTypes, isSealed) {
var filtered = [];
angular.forEach(gasTypes, function(gasType){
if(isSealed){
if(gasType.usableInSealedSpacer)
filtered.push(gasType);
}
if(!isSealed){
if(gasType.usableInSecondarySpacer)
filtered.push(gasType);
}
});
return filtered;
};
});
and this is how I included my directive:
<filter-select options="allGasTypes | gasUsableInSpacer:element.sealed" element="element.gasType" id="gasTypeX"></filter-select>
The above way isn't working, while this is working fine:
<select class="form-control" ng-model="element.gasType" ng-options="gasType as gasType.naturalName for gasType in allGasTypes | gasUsableInSpacer:element.sealed track by gasType.id" name="gasTypeX" id="gasTypeX">
</select>
This is my directives controller:
angularAMD.directive("filterSelect", function (angularLoad) {
return {
templateUrl: 'rmlModMainApp/directives/filterSelect.html',
restrict: 'E',
scope: {
options : '=',
element: '='
},
link: function(scope, element, attr) {
angularLoad.loadCSS(requirejs.toUrl('rmlModMainApp/directives/filterSelect.css'));
scope.listVisible = false;
scope.selectOption = function(option){
scope.element = option;
scope.toggleList();
};
scope.toggleList = function(){
scope.listVisible = !scope.listVisible;
}
}
}
});
});
And the part of the view that is supposed to render the options:
<div class="filterSelect">
<div class="filterSelectContent" ng-show="listVisible">
<form class="filterSelectSearch">
<div class="input-group col-xs-12">
<input type="text" class="form-control" id="filterText" ng-model="search.text" placeholder="filter" ng-model-options="{debounce: {'default':500, 'blur':0}}">
<span class="input-group-addon"><i class="fa fa-lg fa-filter"></i></span>
</div>
</form>
<div class="filterSelectList">
<ul>
<li ng-repeat="option in options track by option.id" ng-click="selectOption(option)">{{option.x}} <span ng-if="option.y">({{option.y}}mm)</span> [{{option.z}}] </li>
</ul>
</div>
</div>
</div>
I have no idea what I'm doing wrong.
First of all I'm kinda new to Angular. I've created a directive that is being used in my form-group div in the HTML. This contains a required input. The ideia of this directive is to check if the entire div will be shown based on a scope value.
Visually, this works as expected but... when setting the ng-if directive to a false value, the form submission still gives an error as a required value is missing when the form doesn't even contain that input anymore.
This is my code:
// My Directive
app.directive("showCountry", function ($compile) {
var linkFunction = function (scope, element, attributes) {
var testingVariable = scope.testingVariable;
if (testingVariable) {
switch (testingVariable.toLowerCase()) {
case "A":
// Do nothing, keep the div visible.
break;
default:
// Hide the entire div.
attributes.$set("ngIf", false);
compile(element)(scope);
break;
}
}
};
return {
restrict: "A",
link: linkFunction
};
});
<!-- My HTML with required field using my directive -->
<div class="form-group" show-country>
<label class="col-lg-6 col-md-6 control-label">
Country
</label>
<div class="col-lg-6 col-md-6">
<input name="country" type="text" placeholder="Country" ng-model="country" ng-required="true"/>
</div>
</div>
Thank you guys.
Take a scope variable validateand make it false in the condition,
if (testingVariable.toLowerCase()) {
switch (testingVariable.toLowerCase()) {
case "A":
// Do nothing, keep the div visible.
break;
default:
// Hide the entire div.
scope.validate = false;
attributes.$set("ngIf", false);
$compile(element)(scope);
break;
}
}
<!DOCTYPE html>
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<body ng-app="myApp" ng-controller="test">
<form name="myForm">
The country input is hided and animation wil not occur
<div class="form-group" show-country validate="validate">
<label class="col-lg-6 col-md-6 control-label">
Country
</label>
<div class="col-lg-6 col-md-6">
<input name="country" type="text" placeholder="Country" ng-model="country" ng-required="true" ng-if="validate"/>
</div>
</div>
</form>
<h1>{{myForm.country.$error}}
<script>
var app = angular.module("myApp", []);
app.directive("showCountry", function ($compile) {
var linkFunction = function (scope, element, attributes) {
var testingVariable = scope.testingVariable;
console.log(testingVariable.toLowerCase())
if (testingVariable.toLowerCase()) {
switch (testingVariable.toLowerCase()) {
case "A":
// Do nothing, keep the div visible.
break;
default:
// Hide the entire div.
scope.validate = false;
attributes.$set("ngIf", false);
$compile(element)(scope);
break;
}
}
};
return {
restrict: "A",
link: linkFunction
};
});
app.controller("test", function ($scope) {
$scope.testingVariable = 'false';
});
</script>
</body>
</html>
Here is the DEMO with validation Occuring, Your scenario
DEMO with novalidation, Required answer
I have a directive for comment input as follows, I want to reset the form after the user posted the comment. However, I can not get the newComment value of ng-model in link function. How to solve such problem.
commenting.html
<div class="directive__commenting">
<div class="col-content">
<h4>{{title}}({{count}})</h4>
<form class="form" name="commentForm" ng-submit="createComment(commentForm, newComment)" ng-if="isLoggedIn()">
<div class="form-group">
<textarea class="form-control" name="newComment" rows="3" placeholder="你怎么看?" ng-model="newComment" required></textarea>
</div>
<div class="right">
<span id="count-words" ng-class="{'red': isWordsExceeded(newComment)}">{{140 - newComment.length}}</span>
<button class="send-button btn btn-default" type="submit" ng-disabled="isWordsExceeded()">{{btnActionTitle}}</button>
</div>
</form>
</div>
</div> <!-- #create-comment -->
commenting.directive.js
'use strict';
angular.module('myapp')
.directive('commenting', function (Auth) {
return {
templateUrl: 'components/directive/commenting/commenting.html',
restrict: 'EA',
scope: {
title: '=',
count: '=',
btnActionTitle: '=',
action: '='
},
link: function (scope) { //, element, attrs
scope.isLoggedIn = Auth.isLoggedIn;
scope.isWordsExceeded = function (newComment) {
return newComment && newComment.length > 140;
}; //- isWordsExceeded
scope.createComment = function (form, newComment) {
scope.action(form, newComment)
.then(function () { //success
// clear the form, however here scope.newComment is undefined
})
.catch(function () { //fail
});
};
}
};
});
The directive is added in a html file as follows.
<div class="row" id="create-comment">
<commenting title="'Comments'" count="model.comments.length" btn-action-title="'Submit comment'" action="createComment"></commenting>
</div> <!-- #create-comment -->
Try to access through scope like
scope.newComment
I want to create a custom form validation, using AngularJS. That form should have input and select elements. The form should be valid, when either imputs are empty or both filled with some values. Here is the view:
<form name="recipientsForm" novalidate>
<md-input-container>
<label>Name</label>
<input name="name" type="text" ng-model="relationship.name" value="" empty-or-both-filled="relationship.relationshipType">
<div ng-messages="recipientsForm.name.$error">
<div ng-message="emptyOrBothFilled">Enter name.</div>
</div>
</md-input-container>
<md-input-container>
<md-select name="type" placeholder="Select your relation... " ng-model="relationship.relationshipType" empty-or-both-filled="relationship.name">
<md-option ng-repeat="type in relationshipTypes" value="{{type.relationshipType}}">
{{type.name}}
</md-option>
</md-select>
<div ng-messages="recipientsForm.type.$error">
<div ng-message="emptyOrBothFilled">Pick relationship.</div>
</div>
</md-input-container>
</form>
And here is the directive:
(function () {
'use strict';
angular
.module('app')
.directive('emptyOrBothFilled', [emptyOrBothFilled]);
function emptyOrBothFilled() {
return {
restrict: 'A',
required: 'ngModel',
scope: {
targetNgModel: '=emptyOrBothFilled'
},
link: function($scope, element, attrs, ngModel) {
ngModel.$validators.emptyOrBothFilled = function(val) {
var isValueEmpty = !val;
var isTargetEmpty = !$scope.targetNgModel;
return (isTargetEmpty && isValueEmpty) || (!isTargetEmpty && !isValueEmpty);
}
$scope.$watch('targetNgModel', function() {
ngModel.$validate();
})
}
}
}
})();
Prompt, please, why do I get this error:
TypeError: Cannot read property '$validators' of undefined
at link (http://localhost:3000/app/shared/directives/EmptyOrBothFilled.js:17:24)
It should be
require: 'ngModel',
not
required: 'ngModel',
in the directive specification.