Yup allow a certain amount of digits after comma based on user input - formik

I want to add validation for decimal with a given amount based on user input.
I looked for this question https://stackoverflow.com/questions/71659724/yup-allow-two-digits-after-comma-minimum-and-maximum-for-a-decimal#:~:text=company%20blog-,yup%20%2D%20allow%20two%20digits%20after%20comma%2C%20minimum,and%20maximum%20for%20a%20decimal and while it works for 2 digits which is hardcoded, I tried to make the regular expression dynamic by including a variable instead of 2.
Returns false and showing the Formik error message for every number after comma.
const getNumberValidation = (config: any) => {
let dynamicRegex = new RegExp(`/^\d+(\.\d{0,${config.decimals}})?$/`)
if (config.min && config.max && config.decimals)
return Yup.number()
.min(config.min, `Entered value must be greater or equal to ${config.min}`)
.max(config.max, `Entered value must be lower or equal to ${config.max}`)
.test(
'is-decimal',
`Number of decimal places cannot exceed ${config.decimals} digits`,
(val: any) => {
if (val !== undefined) {
return dynamicRegex.test(val)
}
return false
}
)
}

Related

Is it possible to remove warning from Data validation while using criteria - list from a range?

I have set a data validation as a list from a range but when I enter a text that does not match the list, I am getting a red warning in the cell.
My question is: How to use both methods, but avoiding the red warning? How to make datavalidation accept both which is available in range list, and that which is not available in range list, but also keep the dropdown?
Using onEdit(e), I have a script that will compare the value input to the data validation rule and if its not in the list, the error may be displayed momentarily but the value will be replaced with "" which is a valid input.
My data validation is Sheet1!C5:D5 merged cell for a range, Sheet!C7:D7 for a list.
DataValidation.getCriteriaValues() returns an array of objects the first element of that array is an array of the values displayed in the dropdown for a list or a range object.
function onEdit(e) {
try {
if( e.range.getSheet().getName() === "Sheet1") {
if( ( e.range.getA1Notation() === "C5" ) || ( e.range.getA1Notation() === "C7" ) ) {
let valid = e.range.getDataValidation();
if( valid != null ) {
let criteria = valid.getCriteriaValues();
let values = criteria[0];
if( valid.getCriteriaType() === SpreadsheetApp.DataValidationCriteria.VALUE_IN_RANGE ) {
values = values.getValues().flat();
}
if( values.indexOf(e.value) < 0 ) e.range.setValue("");
}
}
}
}
catch(err) {
SpreadsheetApp.getUi().alert(err);
}
}
Reference
Range.getDataValidation()
DataValidation.getCriteriaValues()

How to do natural sort/alpha numeric sort over columns for y-dimension in jqGrid pivot table

For columns in y-dimension how to do natural sort for alpha numeric column names ?
For example:
consider column names AA1, AA2, AA3, AA10, AA11.
These are listed in order AA1, AA10, AA11, AA2, AA3 in pivot table y-dimension.
Desired order of columns is AA1, AA2, AA3, AA10, AA11
Free jqGrid 4.9 contains full rewritten version of jqPivot. I tried to hold compatibility with the previous version, but it contains many advanced features. I tried to describe there in wiki.
Not so many people uses jqPivot. So I remind what it do. It gets an input data as source and generate new data, which will be input data for jqGrid. Additionally jqPivot generates colModel based on input data and yDimension parameter. During analyzing of input data jqPivot sorts input data by xDimension and by yDimension. The order or sorting of xDimension defines the order of rows of resulting grid. The order or sorting of yDimension defines the order of columns of resulting grid and the total number of resulting columns. The options compareVectorsByX and compareVectorsByY of allows to specify callback function which will be used for custom sorting by the whole x or y vector. It's important to understand that sorting function not only specify the the order of columns, but it informs jqPivot which vectors should be interpreted as the same. For example it can interpret the values 12, 12.0 and 012.00 as the same and specify that 12.0 is larger as 6.
I describe below some ways which can be used to customize sorting by xDimension and yDimension.
First of all one can specify skipSortByX: true or skipSortByY: true parameters. In the case the input data have to be already sorted in the order which you want. The next important options are Boolean options caseSensitive (with default value false) and trimByCollect (default value true). caseSensitive: true can be used to distinguish input data by case and trimByCollect: false can be used to hold trailing spaces in the input data.
Some other important option can be specified in xDimension or yDimension: sorttype and sortorder. sortorder: "desc" can be used to reverse the order of sorted data. The option sorttype can be "integer" (or "int") which means to truncate (Math.floor(Number(inputValue))) input data during sorting; The values "number", "currency" and "float" means that the input data should be converted to numbers during sorting (Number(inputValue)). Finally one can don't specify any sorttype, but specify compare callback function instead. The compare callback is function with two parameters and it should return well known -1, 0 or 1 values.
For example I created the demo for one issue. One asked my about the following situation. The web site contains login, which identifies the country of the user. One want to set the user's country as the first in the sorting order. The demo uses the following yDimension parameter:
yDimension: [
{ dataName: "sellyear", sorttype: "integer" },
{ dataName: "sell month",
compare: function (a, b) {
if (a === "Germany") { return b !== "Germany" ? -1 : 0; }
if (b === "Germany") { return 1; }
if (a > b) { return 1; }
if (a < b) { return -1; }
return 0;
}}
]
It sets "Germany" first in the sorting order. As the results one sees the results like on the picture below
You can use the same approach using the code for natural compare from the answer and you will implements your requirements.
In more advanced cases one can use the options compareVectorsByX and compareVectorsByY. The requirement was to place specific country only in one specific year on the first place holding the standard order on all other cases. The corresponding demo uses compareVectorsByY to implement the requirement. It displays
and uses the following compareVectorsByY:
compareVectorsByY: function (vector1, vector2) {
var fieldLength = this.fieldLength, iField, compareResult;
if (fieldLength === 2) {
if (vector1[0] === "2011" && vector1[1] === "Germany") {
if (vector2[0] === "2011" && vector2[1] === "Germany") {
return {
index: -1,
result: 0
};
}
return {
index: vector2[0] === "2011" ? 1 : 0,
result: -1
};
}
// any vector1 is larger as vector2 ("2011", "Germany")
if (vector2[0] === "2011" && vector2[1] === "Germany") {
return {
index: vector2[0] === "2011" ? 1 : 0,
result: 1
};
}
}
for (iField = 0; iField < fieldLength; iField++) {
compareResult = this.fieldCompare[iField](vector1[iField], vector2[iField]);
if (compareResult !== 0) {
return {
index: iField,
result: compareResult
};
}
}
return {
index: -1,
result: 0
};
}
It's important to mention that compareVectorsByY callback function should return object with two properties: index and result. The value of result property should be -1, 0 or 1. The value of index property should be -1 in case of result: 0 and be 0-based index of vectors where vector1 and vector2 are different.

Using IEqualityComparer to check specific values

So this is the first time I've tried using IEqualityComparer and I'm running into an issue.
It's likely I just don't understand exactly what the code is doing behind the scenes.
The list I'm providing it looks like this:
Test Run | SN | Retest
1 185 0
2 185 1
3 185 1
4 185 1
I'm trying to use Distinct() to find the number of items which have a unique SN, and 'retest==1'.
var result = testRunList.Distinct(new UniqueRetests());
And the derived IEqualityCompare class looks like this:
public class UniqueRetests : IEqualityComparer<TestRunRecord>
{
// Records are equal if their SNs and retest are equal.
public bool Equals(TestRunRecord x, TestRunRecord y)
{
//Check whether any of the compared objects is null.
if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null))
return false;
//Check whether it's a retest AND if the specified records' properties are equal.
return x.retest == 1 && y.retest == 1 && x.boardSN == y.boardSN;
}
// If Equals() returns true for a pair of objects
// then GetHashCode() must return the same value for these objects.
public int GetHashCode(TestRunRecord record)
{
//Check whether the object is null
if (Object.ReferenceEquals(record, null)) return 0;
//Get hash code for the board SN field.
int hashRecordSN = record.boardSN.GetHashCode();
//Get hash code for the retest field.
int hashRecordRetest = record.retest.GetHashCode();
//Calculate the hash code for the product.
return hashRecordSN ^ hashRecordRetest;
}
}
Problem is that this seems to produce a which includes the first two items, whereas what I'm looking for is a list that includes only a single item where 'retest==1'.
Any idea what I'm doing wrong here? How is it that a record with 'retest == 0' is being returned?
Answer
If the condition is false, the objects are treated as if they are not equal. Distinct returns not-equal rows. Btw, you are violating the contract of IEqualityComparer with this type of code. The results are actually undefined. – usr
With "violating the contract" I mean (for example) than an object with retest==0 will compare unequal to itself. – usr
You need to filter out items with retest = 0. Put a .Where(x => x.retest != 0) in front of the Distinct.

Getting a column value

private string FindTaxItemLocation(string taxItemDescription)
{
if (!templateDS.Tables.Contains(cityStateTaxesTable.TableName))
throw new Exception("The schema dos not include city state employee/employer taxes table");
var cityStateTaxes =
templateDS.Tables[cityStateTaxesTable.TableName].AsEnumerable().FirstOrDefault(
x => x.Field<string>(Fields.Description.Name) == taxItemDescription);//[x.Field<string>(Fields.SteStateCodeKey.Name)]);
if (cityStateTaxes != null)
return cityStateTaxes[Fields.SteStateCodeKey.Name].ToString();
return null;
}
cityStateTaxes is a DataRow, why/how I cannot get the column value inside FirstOrDefault()?
Thanks,
FirstOrDefault() selects the first item in the collection (optionally that satisfies a predicate) or returns null in the case there it is empty (or nothing satisfies the predicate). It will not do projections for you. So if you use it, it can be awkward to access a field of the item since you must include default value checks.
My suggestion is to always project to your desired field(s) first before using FirstOrDefault(), that way you get your field straight without needing to perform the check.
var cityStateTaxes = templateDS.Tables[cityStateTaxesTable.TableName]
.AsEnumerable()
.Where(row => row.Field<string>(Fields.Description.Name) == taxItemDescription) // filter the rows
.Select(row => row.Field<string>(Fields.SteStateCodeKey.Name)) // project to your field
.FirstOrDefault(); // you now have your property (or the default value)
return cityStateTaxes;

How can I validate Ext.form.DateField using min/maxValue, without using time?

I'm having the following problem: I want to validate a DateField so that it has a value between the minValue / maxValue range. (greater or equal, lower or equal)
The problem is that I think the framework takes the time in milliseconds.
I've tried using a custom vtype such as:
Ext.apply(Ext.form.VTypes,{
dates: function(val, field){
try{
if(this.disabled){
return true;
}
if(Ext.value(val,null,false)==null){
this.datesText = "This field is required.";
return this.allowBlank; //the text message won't be shown in case blank is allowed.
}
if(Ext.value(field.minValue,null,false)!=null){
if(Ext.util.Format.date(val,"Ymd")<Ext.util.Format.date(field.minValue,"Ymd")){
this.datesText = "The value is invalid.<br/>";
this.datesText = "it must be greater or equal than " + field.minValue;
return false;
}
}
if(Ext.value(field.maxValue,null,false)!=null){
if(Ext.util.Format.date(val,"Ymd")>Ext.util.Format.date(field.maxValue,"Ymd")){
this.datesText = "The value is invalid.<br/>";
this.datesText = "It must be lower or equal than " + field.maxValue;
return false;
}
}
return true;
}catch(e){
return false;
}
},
datesText: 'The value is invalid.', //error message
datesMask: / / //regexp to filter the characters allowed
});
Basically what it does is convert the values to a 'Ymd' format and then compare values as numbers.
If I debug this code, the validation goes okay, but for some reason I still get an error message. I believe the framework is trying to validate the field again after my validation.
Thank you!
Sebastián
minValue : Date/String
The minimum allowed date. Can be either a Javascript date object or a string date in a valid format (defaults to null).
maxValue : Date/String
The maximum allowed date. Can be either a Javascript date object or a string date in a valid format (defaults to null).
and in case you needed to disable some dates
disabledDates : Array
An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular expression so they are very powerful. Some examples:
// disable these exact dates:
disabledDates: ["03/08/2003", "09/16/2003"]
// disable these days for every year:
disabledDates: ["03/08", "09/16"]
// only match the beginning (useful if you are using short years):
disabledDates: ["^03/08"]
// disable every day in March 2006:
disabledDates: ["03/../2006"]
// disable every day in every March:
disabledDates: ["^03"]
Instead of fixed dates mentioned above, use this:
//doesn't allow past today
maxValue: new Date()
//Only allows 7 days in the past from current date.
minValue: Ext.Date.add(new Date(), Ext.Date.DAY, -7)

Resources