I am trying to implement custom validation to check user typed entry is valid or not.
EX: Existing row
ORIG DEST DESK REGION
HYD MAS 20 34
Scenario's:
1)When user enter new row with same values i need to show validation error.
2)When user enter same orig, dest and region with different desk then also i need to validation error.
I have created custom validation which will check current row with all rows in list and return false if any scenario found.
I need to call this directive on any value change of ORIG or DEST or DESK or REGION and show error message at single place.
I tried with giving directive for all fields, but getting error for every filed not common.
Is there any possibility to do this?
HTML:
<form novalidate id="ODDRForm" name="ODDRForm">
<table>
<thead>
<tr>
<th >
<span>ORIG</span>
</th>
<th >
<span>DEST</span>
</th>
<th >
<span>DESK</span>
</th>
<th >
<span>REGION</span>
</th>
</tr>
</thead>
<tbody class="tbody_border_bottom">
<tr ng-repeat="row in List" ng-form="rowForm">
<td >
<input check-duplicate type="text" name="origin" ng-model="row.orig" required /><br/>
<div ng-messages="rowForm.orig.$error" ng-if="ODDRForm.$submitted || rowForm.orig.$touched">
<span ng-message="required">Required</span>
<span ng-message="checkDuplicate">Not a valid entry</span>
</div>
</td>
<td >
<input check-duplicate type="text" name="dest" ng-model="row.dest" required /><br/>
<div ng-messages="rowForm.dest.$error" ng-if="ODDRForm.$submitted || rowForm.dest.$touched">
<span ng-message="required">Required</span>
<span ng-message="checkDuplicate">Not a valid entry</span>
</div>
</td>
<td >
<input check-duplicate type="text" name="desk" ng-model="row.desk" required /><br/>
<div ng-messages="rowForm.desk.$error" ng-if="ODDRForm.$submitted || rowForm.desk.$touched">
<span ng-message="required">Required</span>
<span ng-message="checkDuplicate">Not a valid entry</span>
</div>
</td>
<td >
<input check-duplicate type="text" name="region" ng-model="row.region" required /><br/>
<div ng-messages="rowForm.region.$error" ng-if="ODDRForm.$submitted || rowForm.region.$touched">
<span ng-message="required">Required</span>
<span ng-message="checkDuplicate">Not a valid entry</span>
</div>
</td>
</tr>
</tbody>
</table>
JavaScript:
app.directive('checkDuplicate', [ '$http', function($http) {
return {
require : '^ngModel',
link : function(scope, element, attrs, ngModel) {
var bool = true;
ngModel.$parsers.push(function(value) {
for(var i in scope.List) {
if(scope.List[i].orig == scope.row.orig && scope.List[i].dest == scope.row.dest
&& scope.List[i].desk == scope.row.desk && scope.List[i].region == scope.row.region
&& scope.List[i].$$hashkey != scope.row.$$hashkey) {
bool = false;
}
}
ngModel.$setValidity('checkDuplicate', bool);
return value;
})
},
}
} ]);
In your case there is no reason to add directives, you can just watch model changes and validate, give me the sample code I can show you how
Related
So I have 2 scenarios, from different pages on the application I'm testing:
Scenario 1:
<tbody>
<tr>
<td class="colLabel90 colCampo">
<label style="font-weight: bold">* Nome:</label>
</td>
<td>
<input type="text" class="ui-inputfield ui-inputtext ui-widget ui-state-default ui-corner-all requiredColor role="textbox" aria-disabled="false" aria-readonly="false">
</td>
</tr>
<tr>
.....
</tr>
</tbody>
Scenario 2:
<tr role="row">
<th id="dataTableFormId:DataTableId:j_idt169" class="ui-state-default ui-sortable-column ui-filter-column ui-resizable-column colFilterSize" role="columnheader" aria-label="Nome: activate to sort column ascending" scope="col" style="width:90%" aria-sort="other">
<span class="ui-column-resizer ui-draggable ui-draggable-handle"> </span>
<span class="ui-column-title">Name</span>
<span class="ui-sortable-column-icon ui-icon ui-icon-carat-2-n-s"> </span>
<input id="dataTableFormId:DataTableId:j_idt169:filter" name="dataTableFormId:DataTableId:j_idt169:filter" class="ui-column-filter ui-inputfield ui-inputtext ui-widget ui-state-default ui-corner-all" autocomplete="off" role="textbox" aria-disabled="false" aria-readonly="false">
</th>
<th id="dataTableFormId:DataTableId:j_idt171" class="ui-state-default ui-sortable-column ui-filter-column ui-resizable-column colFilterSize" role="columnheader" aria-label="Fabricante: activate to sort column ascending" scope="col" style="width:90%">
<span class="ui-column-resizer ui-draggable ui-draggable-handle" style="display: none;"> </span>
<span class="ui-column-title">Manufacturer</span>
<span class="ui-sortable-column-icon ui-icon ui-icon-carat-2-n-s"></span>
<input id="dataTableFormId:DataTableId:j_idt171:filter" name="dataTableFormId:DataTableId:j_idt171:filter" class="ui-column-filter ui-inputfield ui-inputtext ui-widget ui-state-default ui-corner-all" autocomplete="off" role="textbox" aria-disabled="false" aria-readonly="false">
</th>
</tr>
Here is what I'm trying to do on Cypress:
Cypress.Commands.add("typeOnFields", (field, value) => {
cy.get('#center').contains(field).parent().find('input').clear().type(value)
})
//Where field is the name of the field in <label> or <span>, in this case it's 'Name'
This is not working, find() won't find the input in any scenario.
Because the two scenarios have different structures and parent elements, you would need to use a variant of .parents() that keeps moving up to the first parent that contains an input
cy.contains(field) // return the <label> or <span> with "field"
.parents(':has(input)') // move up until element has an <input> inside
.eq(0) // take first (multiple are returned)
.find('input') // find the <input> element
.clear().type(value)
To avoid complexity, I would actually use two commands here one for the table header and one for the table body.
I have a search filter in table and I given ng-model name as selectedGcode for it. I am calling ng-click =viewAccount() inorder to call the function on click. But I am getting $scope.selectedGcode in my controller as undefined.
HTML :
<table class="table table-striped">
<thead>
<tr class="myheading">
<th class="col-sm-2"> Code
</th>
<th class="col-sm-2">Name
</th>
</tr>
<tr>
<th class="col-sm-2" >
<input type="text" class="form-control" ng-model="selectedGcode" placeholder="Search" ng-click="viewAccount()" /></th>
<th class="col-sm-2" >
<input type="text" class="form-control" /></th>
<tr>
<tbody>
<tr data-ng-repeat="data in tableData">
<td class ="stylethecontent" >{{ data.groupzcode}}</td>
<td class ="stylethecontent" >{{data.groupzname}}</td>
</tr>
</tbody>
</table>
JS:
$scope.viewAccount = function(){
var json = {
"json": {
"request": {
"servicetype": "6",
"functiontype": "6014",
"session_id": $rootScope.currentSession,
"data": {
"shortname": $scope.selectShortName,
"groupzcode":$scope.selectedGcode
}
}
}
};
UserService.viewListAccount(json).then(function(response) {
console.log(json);
if (response.json.response.statuscode == 0 && response.json.response.statusmessage == 'Success')
$scope.tableData = response.json.response.data;
});
};
If you want to trigger viewAccount() every time something is typed you should use ng-change.
<input type="text" class="form-control" ng-model="selectedGcode" placeholder="Search" ng-change="viewAccount()" /></th>
If you want to trigger viewAccount() specifically on a click, you should use a button instead.
<input type="text" class="form-control" ng-model="selectedGcode" placeholder="Search"/></th>
<button type="button" class="btn btn-default" ng-click="viewAccount()"></button>
You should use "ng-model", or "data-ng-model", not just "model="selectedGcode""
And you can use ngKeyup instead of ngClick. Because ngClick will be triggered just when the user will click on the input form and not when it will write something.
Use 'ng-model' instead of 'model' keyword in <input> to get the value in controller.
I want to have a table consisting of 3 columns, the code looks like this
<table class="table-striped table-bordered table-condensed">
<tbody>
<tr ng-if="$index%3==0" ng-repeat="permission in vm.parent.getAllPermissions(category)">
<td ng-repeat="i in [0,1,2]" class="col-xs-2">
<span>
<input type="checkbox" checklist-model="vm.data.permissions" checklist-value="vm.parent.getPermission(category,$parent.$index+i)"> {{vm.parent.getPermissionTitle(category,$parent.$index+i) || " "}}
</span>
</td>
</tr>
</tbody>
</table>
That works great except for a small issue.
There's simply not enough json data to fill 3 rows, so 2 checkboxes are displayed empty
What I tried, is writing something like
vm.hasPermission = function(category, index) {
var permissions = vm.getAllPermissions(category);
return permissions && index < permissions.length
};
And then something like
<span>
<input ng-if="vm.parent.hasPermission(category,$parent.$index+i)"type="checkbox"
checklist-model="vm.data.permissions" checklist-
value="vm.parent.getPermission(category,$parent.$index+i)"> {{vm.parent.getPermissionTitle(category,$parent.$index+i) || " "}}
</span>
It fixes the problem but not on all tables, some tables would still have empty checkboxes.
I get the permission titles like this
vm.getPermissionTitle = function(category, index) {
var permissions = vm.getAllPermissions(category);
if (index < permissions.length) {
return i18n.get(permissions[index]);
} else {
return '';
}
};
I tried removing the return, didn't fix it.
change:
<td ng-repeat="i in [0,1,2]" class="col-xs-2">
<span>
<input type="checkbox" checklist-model="vm.data.permissions" checklist-value="vm.parent.getPermission(category,$parent.$index+i)"> {{vm.parent.getPermissionTitle(category,$parent.$index+i) || " "}}
</span>
</td>
for:
<td ng-repeat="i in [0,1,2]" class="col-xs-2">
<span ng-if="vm.parent.getPermissionTitle(category,$parent.$index+i)!=''">
<input type="checkbox" checklist-model="vm.data.permissions" checklist-value="vm.parent.getPermission(category,$parent.$index+i)"> {{vm.parent.getPermissionTitle(category,$parent.$index+i)}}
</span>
</td>
if I understood well your code and your problem, vm.parent.getPermission(category,$parent.$index+i) returns the text (permission) so just check that is not empty... it may also work like:
<td ng-repeat="i in [0,1,2]" class="col-xs-2">
<span ng-if="vm.parent.getPermissionTitle(category,$parent.$index+i)">
<input type="checkbox" checklist-model="vm.data.permissions" checklist-value="vm.parent.getPermission(category,$parent.$index+i)"> {{vm.parent.getPermissionTitle(category,$parent.$index+i)}}
</span>
</td>
because vm.parent.getPermission(category,$parent.$index+i) returning nothing could evaluate false.
I haven't try it.
The solution is
<table class="table-striped table-bordered table-condensed">
<tbody>
<tr ng-if="$index%3==0" ng-repeat="permission in vm.parent.getAllPermissions(category)">
<td ng-repeat="i in [0,1,2]" class="col-xs-2">
<span ng-if="vm.parent.getPermission(category,$parent.$index+i)">
<input type="checkbox" checklist-model="vm.data.permissions" checklist- value="vm.parent.getPermission(category,$parent.$parent.$index+i)">
{{vm.parent.getPermissionTitle(category,$parent.$parent.$index+i)}}
</span>
</td>
</tr>
</tbody>
</table>
So basically {{vm.parent.getPermissionTitle(category,$parent.$parent.$index+i)}}
Using angular-strap v2.2.1, I have a scenario where I have list of periods every period use min-date and max-date attribute and when set a period in the change of end date ,I should disable this period here is the html :
<div class="row">
<div class="table-responsive">
<table class="table table-bordered">
<thead>
<tr>
<th colspan="4" style="border: none"></th>
<th colspan="10" class="text-center">Series Closed</th>
</tr>
<tr>
<th>Period</th>
<th>Period Name</th>
<th>Start Date</th>
<th>End Date</th>
<th>Financial</th>
<th>Sales</th>
<th>Purchasing</th>
<th>Inventory</th>
<th>Payroll</th>
<th>Manufacturing</th>
<th>Expense Management</th>
<th>POS</th>
<th>Bank</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="period in AllPeriods">
<td>1</td>
<td class="col-md-3">
<input type="text" id="PeriodName{{$index}}" class="form-control input-sm"
placeholder="Period Name" ng-model="period.PeriodName">
</td>
<td class="col-md-2">
<div class="input-group">
<input type="text" id="StartDate{{$index}}" class="form-control" ng-model="period.StartDate"
data-date-format="dd/MM/yyyy" data-max-date="{{period.EndDate}}"
data-disabled-dates="{{unavailableDates}}"
autoclose="true"
placeholder="Start Date" bs-datepicker>
<span class="input-group-addon">
<i class="fa fa-calendar"></i>
</span>
</div>
</td>
<td class="col-md-2">
<div class="input-group">
<input type="text" id="EndDate{{$index}}" class="form-control" ng-model="period.EndDate"
data-date-format="dd/MM/yyyy" data-min-date="{{period.StartDate}}"
data-disabled-dates="{{unavailableDates}}"
autoclose="true"
placeholder="End Date" ng-change="DisableDate(period.StartDate,period.EndDate)" bs-datepicker>
<span class="input-group-addon">
<i class="fa fa-calendar"></i>
</span>
</div>
</td>
<td class="text-center">
<input type="checkbox" class="form-control" name="IsClosed{{$index}}" ng-model="period.IsClosed" style="position:static;opacity:10;">
</td>
<td class="text-center">
<input type="checkbox" class="form-control" name="IsSalesClosed{{$index}}" ng-model="period.IsSalesClosed" style="position:static;opacity:10;">
</td>
<td class="text-center">
<input type="checkbox" class="form-control" name="IsPurchaseClosed{{$index}}" ng-model="period.IsPurchaseClosed" style="position:static;opacity:10;">
</td>
<td class="text-center">
<input type="checkbox" class="form-control" name="IsInventoryClosed{{$index}}" ng-model="period.IsInventoryClosed" style="position:static;opacity:10;">
</td>
<td class="text-center">
<input type="checkbox" class="form-control" name="PayrollClosed{{$index}}" ng-model="period.PayrollClosed" style="position:static;opacity:10;">
</td>
<td class="text-center">
<input type="checkbox" class="form-control" name="IsManufacturingClosed{{$index}}" ng-model="period.IsManufacturingClosed" style="position:static;opacity:10;">
</td>
<td class="text-center">
<input type="checkbox" class="form-control" name="IsExpenseManagementClosed{{$index}}" ng-model="period.IsExpenseManagementClosed" style="position:static;opacity:10;">
</td>
<td class="text-center">
<input type="checkbox" class="form-control" name="IsPOSClosed{{$index}}" ng-model="period.IsPOSClosed" style="position:static;opacity:10;">
</td>
<td class="text-center">
<input type="checkbox" class="form-control" name="IsBankClosed{{$index}}" ng-model="period.IsBankClosed" style="position:static;opacity:10;">
</td>
</tr>
</table>
</div>
</div>
in the JS :
$scope.AllPeriods = [];
$scope.NumberOfPeriodsChanged = function () {
$scope.AllPeriods = [];
var num = $("#Num").val();
for (var i = 0; i < num; i++) {
var temp = {
YearCode: '',
PeriodName: '',
StartDate: '',
EndDate: '',
IsClosed: '',
IsSalesClosed: '',
IsPurchaseClosed: '',
IsInventoryClosed: '',
PayrollClosed: '',
};
$scope.AllPeriods.push(temp);
}
};
$scope.unavailableDates = [];
$scope.DisableDate = function (start, end) {
$scope.unavailableDates.push({
start: new Date(start),
end: new Date(end)
});
};
i solved this problem by making two functions to return date_to and date_from :
$scope.ToCustomDate = function (index) {
if (index == 0) {
return;
}
var dt = new Date($scope.AllPeriods[index].StartDate);
dt.setDate(dt.getDate() + 1);
return dt;
};
$scope.FromCustomDate = function (index) {
if (index == 0) {
return;
}
var dt = new Date($scope.AllPeriods[index - 1].EndDate);
dt.setDate(dt.getDate() + 1);
return dt;
};
I have tried your example and it seems that it doesn't work dynamically, You can put the disabled dates in advance and add the next period when the user finish editing the first one, or you might forward your question as issue in angular-strap
btw you don't need brackets to set the disabled dates
data-disabled-dates="unavailableDates"
and you need to refactor your function to take index as it keep adding dates to the array
$scope.DisableDate = function( index, start, end ) {
if ( angular.isDate( start ) && angular.isDate( end ) ) {
$scope.unavailableDates[index] = {
start: new Date( start ).toISOString(),
end: new Date( end ).toISOString()
};
}
};
Hello i have a form inside a table row within an ng-repeat, inside that form i have a number field and a button(custom directive named "action") now when that button is clicked i want the form to do validation before submitting but when i try nothing happens i get no errors.
<table class="table schedules">
<thead>
<tr>
<th style="text-align:center;" > Ticket Type</th>
<th style="text-align:center;" > Ticket Price (GHS)</th>
<th style="text-align:center;" > How many?</th>
<th></th>
</tr>
</thead>
<tbody>
#if (count($ticketTypes) <= 0))
<tr ng-hide="d.ticketTypes.length > 0">
<td style="text-align:center;" colspan="5">
<h4 style="">There are no tickets available.</h4>
</td>
</tr>
#endif
<tr ng-repeat="type in d.ticketTypes">
<form name="ticketForm" ng-submit="ticketForm.$valid && addToCart('event', d, type.id, $index)" novalidate>
<td style="text-align:center;" ><b><% type.fee_cat_desc %></b></td>
<td style="text-align:center;" ><b><% type.event_fee | currency : '₵' %></b></td>
<td style="text-align:center;" ><b><input type="number" ng-model="line.d.ticket_no" class="form-control" min="1" max="30" style="width:80px !important;" ng-required/></b></td>
<td>
<action text='Buy Ticket' state='<% state %>' index='<% $index %>' selected='<% selectedIndex %>'></action>
</td>
</form>
</tr>
</tbody>
</table>
This is my action directive:
html:
<button type="submit" ng-class="{ 'btn-set': isReady === true || isWorking === true || isComplete === true || hasFailed === true, 'btn-ready-state': isReady === true || selected != index, 'btn-working-state': isWorking === true && selected == index, 'btn-failed-state': hasFailed === true }" ng-cloak>
<i ng-if="isReady === true || selected != index" class="fa fa-shopping-cart"></i>
<img ng-src="/images/loading - small.png" class="img" ng-show="isWorking && selected == index "></span>
<i ng-if="isComplete && selected == index " class="fa fa-check"></i>
<span class="text">
<span ng-if="isReady === true || selected != index"><% text %></span>
</span>
</button>
One of the thing you missed to name="" attribute on a form, it is needed to start form validation on field by angular
<input type="number" name="ticket_no-{{$index}}" ng-model="line.d.ticket_no"
class="form-control" min="1" max="30" style="width:80px !important;" ng-required/>
Refer this SO Answer for more Explaination
You've got multiple <form>s with the same name. This is a problem for angular because it references each form by its name. A quick fix would be to use $index or type to make the names different.
<tr ng-repeat="type in d.ticketTypes">
<form name="ticketForm_{{type}}" ng-submit="ticketForm.$valid && addToCart('event', d, type.id, $index)" novalidate>
<td style="text-align:center;" ><b><% type.fee_cat_desc %></b></td>
<td style="text-align:center;" ><b><% type.event_fee | currency : '₵' %></b></td>
<td style="text-align:center;" ><b><input type="number" ng-model="line.d.ticket_no" class="form-control" min="1" max="30" style="width:80px !important;" ng-required/></b></td>
<td>
<action text='Buy Ticket' state='<% state %>' index='<% $index %>' selected='<% selectedIndex %>'></action>
</td>
</form>
</tr>
Make sure that you have a input field with the type="button" and the name="submit"