resuable validator for multiple cases - validation

I made a date validator. It validates existing dates. I need multiple date validator with other restrictions, for ex : a max date validator that won't let the user put in a future date or a date validator that only takes past dates. This is my current validator.
export function dateValidator(group) {
const {day, month, year} = group.value;
const fullDate = `${day}/${month}/${year}`;
const dobPattern = /^(\d{1,2})[-\/](\d{1,2})[-\/](\d{4})$/;
const isStringValid = dobPattern.test(fullDate);
let isValid = false;
if (isStringValid) {
const intDay = Number(day);
const intMonth = Number(month);
const intYear = Number(year);
const jsMonth = intMonth - 1;
const date = new Date(intYear, jsMonth, intDay);
isValid = (date.getFullYear() === intYear && date.getMonth() === jsMonth && date.getDate() === intDay ;
}
return isValid ? null : { invalid: 'Invalid date' };
};
How can I restrict the user from putting in future dates.
I used this code with the following line:
isValid = (date.getFullYear() === intYear && date.getMonth() === jsMonth && date.getDate() === intDay ;
But I wonder if there is an easier way without having to copy and past this code over and over again to make small restrictions to it.

Your dateValidator() function should be a function factory (i.e. a function that returns a function) instead of a function that returns the error directly:
export function dateValidator(maxDate: string): ValidatorFn {
// Return a validator function.
return (group: FormGroup): {[key: string]: any} => {
// Re-use your existing validation code here and return the error if any.
// Optionally, use the `maxDate` param to customize the validation:
// entered dates should not go beyond `maxDate`.
};
}
As you can see, you can customize the validator function by passing parameters to the function factory. In my example, I used a maxDate parameter to indicate the furthest date in time that the validator should allow.
In your form model, use this validator by calling the factory with the appropriate value, e.g. :
this.myForm = fb.group({
'date': ['', [Validators.required(), dateValidator('02/20/2017')]]
});
You can see another example of a function factory for a validator in the doc: https://angular.io/docs/ts/latest/cookbook/form-validation.html#custom-validation

Related

MatDatepickerFilter - Filter function can't access class variable

A MatDatePicker with a filter defined as followed:
<mat-form-field class="example-full-width">
<input matInput [matDatepickerFilter]="myFilter" [matDatepicker]="picker" placeholder="Choose a date">
<mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
<mat-datepicker #picker></mat-datepicker>
</mat-form-field>
export class DatepickerFilterExample {
someDateToBlock: number = 3;
myFilter = (d: Date): boolean => {
const day = d.getDay();
// THIS FUNCTION CANNOT ACCESS THE VARIABLE 'someDateToBlock'
return day !== 0 && day !== 6;
}
}
I would like to access the variable someDateToBlock (or any other) in the filter function. Is there a workaround to make this possbile?
I had the same issue, seems like material date picker doesn't have access to "this" of the component for filter function. For me changing:
[matDatepickerFilter]="myFilterFunction"
to
[matDatepickerFilter]="myFilterFunction.bind(this)"
did the trick.
This is working, here is plunkr link: https://plnkr.co/edit/oRGfxLSrn6GdfRhYO1rr?p=preview
export class DatepickerOverviewExample {
someDateToBlock: number = 3;
myFilter = (d: Date): boolean => {
const day = d.getDay();
// THIS FUNCTION CANNOT ACCESS THE VARIABLE 'someDateToBlock'
return this.someDateToBlock;
}
}
I checked with alert(this.someDateToBlock) also
Type '(d: Date) => boolean' is not assignable to type 'DateFilterFn<Date | null>'
myFilter = (d: Date ** |null **): boolean => {
const day = (d || new Date()).getDay();
// Prevent Saturday and Sunday from being selected.
return day !== 0 && day !== 6;
};
You can
myLegalDate = (d: Date): boolean => {
//Your code
//You can see the variable someDateToBlock
console.log(this.someDateToBlock);
}
myFilter = this.myLegalDate.bind(this);

NetSuite / Suitescript - Why does this Validate Field script enter an infinite loop?

My script is entering into an infinite loop and I have no idea why. I am running this on validate field and I am preventing a change to the field if another vendor bill exists with the same reference number, forcing the user to change the "Reference Number" to be unique. Here is my code:
function validateField(type, name) {
if (uniqueReferenceNum(type, name) === false) {
return false;
}
return true;
}
function uniqueReferenceNum(type, name) {
if (name !== 'tranid') {
return true;
}
var tranID = nlapiGetFieldValue('tranid');
var vendor = nlapiGetFieldValue('entity');
var vendorName = nlapiGetFieldText('entity');
var filters = new Array();
var columns = new Array();
filters[0] = new nlobjSearchFilter('entity', null, 'is', vendor);
filters[1] = new nlobjSearchFilter('tranid', null, 'is', tranID);
filters[2] = new nlobjSearchFilter('mainline', null, 'is', 'T');
columns[0] = new nlobjSearchColumn('internalid');
results = nlapiSearchRecord('vendorbill', null, filters, columns);
if (!results) {
return true;
}
alert("There is already a vendor bill with reference # " + tranID + " for " + vendorName + ". Please verify and change the reference number before continuing.");
return false;
}
For those still facing this issue, you can set the field in question - in this case, Reference Number - to a 'falsy' value such as an empty string. Only return false after checking that the field contains a 'truthy' value. Then display the alert or dialog to the user. This should break the validation loop.

rxjs ofObjectChanges obsolete

As ofObjectChanges is built on Object.observe() which is obsolete (https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/observe) I'm looking for an alternative for watching object property changes. Anyone know of one?
Perhaps using a Proxy is an option, though it's needed to replace the original object
const { Subject } = require('rxjs');
// Take an object, and return a proxy with an 'observation$' stream
const toObservableObject = targetObject => {
const observation$ = new Subject();
return new Proxy(targetObject, {
set: (target, name, value) => {
const oldValue = target[name];
const newValue = value;
target[name] = value;
observation$.next({ name, oldValue, newValue });
},
get: (target, name) => name == 'observation$' ? observation$ : target[name]
});
}
const observableObject = toObservableObject({ });
observableObject.observation$
.filter(modification => modification.name == 'something')
.subscribe(({ name, oldValue, newValue }) => console.log(`${name} changed from ${oldValue} to ${newValue}`));
observableObject.something = 1;
observableObject.something = 2;
The output
something changed from undefined to 1
something changed from 1 to 2
Look for Proxy in the compatibility table current node versions has full support)
https://kangax.github.io/compat-table/es6/
And documentation of the Proxy at
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Proxy

ASP.NET MVC jQGrid client side and server side validation

I cant find any examples how to do client side validation with MVC jQGrid.
For client side I can see that i need to assign the column property EditClientSideValidators
public List<JQGridEditClientSideValidator> EditClientSideValidators { get; set; }
But i cant understand how to assign validation to that.
But how to do server validation it is also a question
UPDATE
I think i found something client side validation http://www.trirand.net/aspnetmvc/grid/editclientsidevalidation
If you grabbed up the license that includes support you can ask the developer... otherwise, the link you showed has the documentation... the grid needs to request the validators when it gets the data, like so:
public void SetUpGrid_EditClientSideValidation(JQGrid grid)
{
// Setting the DataUrl to an action (method) in the controller is required.
// This action will return the data needed by the grid.
// EditUrl will point to the editing action
grid.DataUrl = Url.Action("EditClientSideValidation_DataRequested");
grid.EditUrl = Url.Action("EditClientSideValidation_EditRow");
var integerColumn = grid.Columns.Find(c => c.DataField == "Integer");
integerColumn.EditClientSideValidators.Add(new RequiredValidator());
integerColumn.EditClientSideValidators.Add(new MinValueValidator { MinValue = 10 });
integerColumn.EditClientSideValidators.Add(new MaxValueValidator { MaxValue = 100 });
var numberColumn = grid.Columns.Find(c => c.DataField == "Number");
numberColumn.EditClientSideValidators.Add(new RequiredValidator());
numberColumn.EditClientSideValidators.Add(new MinValueValidator { MinValue = 0.1 });
numberColumn.EditClientSideValidators.Add(new MaxValueValidator { MaxValue = 100.1 });
var emailColumn = grid.Columns.Find(c => c.DataField == "Email");
emailColumn.EditClientSideValidators.Add(new RequiredValidator());
emailColumn.EditClientSideValidators.Add(new EmailValidator());
var linkColumn = grid.Columns.Find(c => c.DataField == "Link");
linkColumn.EditClientSideValidators.Add(new RequiredValidator());
linkColumn.EditClientSideValidators.Add(new UrlValidator());
var customColumn = grid.Columns.Find(c => c.DataField == "Custom");
customColumn.EditClientSideValidators.Add(new Trirand.Web.Mvc.CustomValidator { ValidationFunction = "validateCustomField" });
}
// This method is called when the grid requests data. You can choose any method to call
// by setting the JQGrid.DataUrl property
public JsonResult EditClientSideValidation_DataRequested()
{
// Get both the grid Model
// The data model in our case is an autogenerated linq2sql database based on Northwind.
var gridModel = new EditValidationModel();
SetUpGrid_EditClientSideValidation(gridModel.ValidatedGrid);
// return the result of the DataBind method, passing the datasource as a parameter
// jqGrid for ASP.NET MVC automatically takes care of paging, sorting, filtering/searching, etc
List employees = GetClientValidatedEmployeeData();
return gridModel.ValidatedGrid.DataBind(employees.AsQueryable());
}

jQuery.validator.unobtrusive.adapters.addMinMax round trips, doesn't work in MVC3

I am creating a day range validator using DataAnnotations, jQuery.validate and jquery.validate.unobtrusive. I've already read the following:
http://bradwilson.typepad.com/blog/2010/10/mvc3-unobtrusive-validation.html
http://weblogs.asp.net/mikaelsoderstrom/archive/2010/10/06/unobtrusive-validation-in-asp-net-mvc-3.aspx
and other but can't post them (noob)
As well as most of the post on SO. I'm baning my head against a wall, any help could be rewardde with beer/food/code/etc ;) Anyway here's the code:
I have a model object with the following parameter:
[Display(Name = "Start date"),
DayRange(0, 5, ErrorMessage = "The Start Date must be between today and 5 days time.")]
public DateTime StartDate { get; set; }
DayRange is a custom attribute class :
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class DayRangeAttribute : RangeAttribute, IClientValidatable
{
private int _minimumDays;
private int _maximumDays;
public DayRangeAttribute(int minimumDays, int maximumDays) : base(minimumDays, maximumDays)
{
_minimumDays = minimumDays;
_maximumDays = maximumDays;
}
public override bool IsValid(object value)
{
var dateToBeTested = value as DateTime?;
return dateToBeTested.HasValue && dateToBeTested.Value >= DateTime.Today.AddDays(_minimumDays) && dateToBeTested.Value <= DateTime.Today.AddDays(_maximumDays);
}
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
var rule = new ModelClientValidationRule
{
ErrorMessage = this.ErrorMessage,
ValidationType = "dayrange"
};
rule.ValidationParameters.Add("min", _minimumDays);
rule.ValidationParameters.Add("max", _maximumDays);
yield return rule;
}
}
I have the following in my web.config:
<appSettings>
<add key="ClientValidationEnabled" value="true"/>
<add key="UnobtrusiveJavaScriptEnabled" value="true"/>
</appSettings>
I have have following JS trigger before the document is ready (have tried triggering it when the doc is ready too ):
jQuery.validator.addMethod('dayrange', function (value, element, param) {
if (!value) return false;
var now = Date();
var dateValue = Date.parse(value);
var minDate = now.setDate(now.getDate() - param.min);
var maxDate = now.setDate(now.getDate() + param.max);
return this.optional(element) && dateValue >= minDate && dateValue <= maxDate;
}, 'Must fall in range');
jQuery.validator.unobtrusive.adapters.addMinMax('dayrange', 'minlength', 'maxlength', 'dayrange');
What am I doing wrong? Thanks in advance, Jol
Solved! I forgot/didn't understand that you have to pass jQuery itself into the function closure. Therefore the custom validator on the client side should look like this:
$(function () {
jQuery.validator.addMethod('dayRange', function (value, element, param) {
if (!value) return false;
var valueDateParts = value.split(param.seperator);
var minDate = new Date();
var maxDate = new Date();
var now = new Date();
var dateValue = new Date(valueDateParts[2],
(valueDateParts[1] - 1),
valueDateParts[0],
now.getHours(),
now.getMinutes(),
(now.getSeconds()+5));
minDate.setDate(minDate.getDate() - parseInt(param.min));
maxDate.setDate(maxDate.getDate() + parseInt(param.max));
return dateValue >= minDate && dateValue <= maxDate;
});
jQuery.validator.unobtrusive.adapters.add('dayrange', ['min', 'max', 'dateseperator'], function (options) {
var params = {
min: options.params.min,
max: options.params.max,
seperator: options.params.dateseperator
};
options.rules['dayRange'] = params;
if (options.message) {
options.messages['dayRange'] = options.message;
}
});
}(jQuery));
I also change the way I add the adapter to unobtrusive so I can add additional properties. Never send to server-side dev to do a front-end engineers job ;) Hope this helps someone.
Referenceļ¼š
http://bradwilson.typepad.com/blog/2010/10/mvc3-unobtrusive-validation.html
adapters.addMinMax()'s param is orderby this:
adapterName, minRuleName, maxRuleName, minMaxRuleName, minAttribute, maxAttribute
so you need this:
jQuery.validator.unobtrusive.adapters.addMinMax('dayrange', '', '', 'dayrange','minlength', 'maxlength');
AND,,,
param.min, param.max be sure to undefine. param is an purely array as: ['111','000'].
so you need:
var minDate = now.setDate(now.getDate() - param[0]);
var maxDate = now.setDate(now.getDate() + param[1]);

Resources