I have a field called "decimal" and with this field, I also have a property called "precision". So my field could be 0.00 or 0.000... etc.
Now I can have a normalize function that allows only numbers and one period, but I also need to pass something that tells me the precision of the field. What can I do here?
I guess I could create precisionOne(),precisionTwo(), precisionThree() etc.. but that seems like a lot of code duplication, for what would be precision(value, previousValue, precision)
EDIT: I've added some code below. It's pretty standard and made up of a few key parts:
createField.js = this is basically my component that receives the fields.json that holds the fields object, and their keys: {row_position, id, identifier, required, min_length, max_length, field_type}
field_type could be: number, text, decimal, date etc.
const row = [];
for(let j = fields.length - 1 - 1; j > 0; j--) {
const {row_position, id, identifier, required, min_length, max_length, field_type} = fields[j];
const validations = [];
//As of now normalize can only be one fuction
let normalize = null;
/// SETUP VALIDATIONS FOR FIELDS ///
if(required) {validations.push(validationFunctions.required)}; // REQUIRED
if(field_type === 3) {validations.push(validationFunctions.email)}; //EMAIL
if(field_type === 4) {validations.push(validationFunctions.number); normalize = normalizeFunctions.number;}; //NUMBER
if(field_type === 7) {validations.push(validationFunctions.number); normalize = normalizeFunctions.decimal;}; //DECIMAL
row.unshift(<Field key={id} name={identifier} component={renderField} validate={validations} normalize={normalize} props={fields[j]}/>);
}
this is my renderField component:
import React from 'react';
import {padWithZero} from '../../helpers/objectManipulationHelpers';
//Get field to display based on type
export default function constructField(field) {
const {input, type, field_type, className, cols, precision, required, id, identifier, addOn} = field;
let fieldTypeBasedCss = '';
let typeAddOn = null;
let iconAddOn = null;
let _precision = null;
let fieldType = 'text';
switch(field_type) {
case 2:
fieldType = 'password';
typeAddOn = <span class="fa fa-asterisk" aria-hidden="true"/>;
break;
case 3:
fieldTypeBasedCss = 'email-field';
typeAddOn = <span class="fa fa-at" aria-hidden="true"/>;
break;
case 4:
fieldTypeBasedCss = 'number-field';
typeAddOn = <span class="fa fa-sort-numeric-asc" aria-hidden="true"/>;
break;
case 6:
fieldTypeBasedCss = 'money-field';
typeAddOn = '$';
break;
case 7:
fieldTypeBasedCss = 'decimal-field';
typeAddOn = padWithZero('0.', precision + 2);
_precision = precision;
break;
case 8:
fieldTypeBasedCss = 'percent-field';
_precision = precision;
typeAddOn = '%';
break;
}
const css = `${className} ${fieldTypeBasedCss}`;
switch(type) {
//Type Text
case 0:
return (
<div className={typeAddOn || addOn ? 'input-group' : ''}>
{addOn ? <span class="input-group-addon" dangerouslySetInnerHTML={{__html: addOn}} /> : ''}
<input {...input} required={required} type={fieldType} size={cols} class={`form-control ${css}`} data-field-id={id} data-field-identifier={identifier} data-precision={_precision}/>
{typeAddOn ? <span class="input-group-addon">{typeAddOn}</span> : ''}
</div>
);
//....more field types below...
//.....
}
}
Now here is the important part:
My formNormalize.js holds all my normalizer functions like so:
//Intercept user input and return valid value field
//Force uppercase
export const upper = value => value && value.toUpperCase();
//Force lowercase
export const lower = value => value && value.toLowerCase();
//Force number
export const number = function(value, previousValue) {
return value.replace(/[^\d]/g, '');
};
//Here I need another variable passed that's called "precision" or
//something that let's me use the same function to return either 0.00 or
//0.000 etc depending on the precision of the decimal field. Right now the
//function will return any valid decimal number, so 0.0 or 0.00 or 0.0000000
//anything, but I need to be able to limit the number of decimal places.
export const decimal = function(value, previousValue) {
if(value && !isNaN(Number(value))){
return value;
} else {
return previousValue;
};
};
Your normalizer can take additional parameters like so:
export const normalizeWhatever = (paramOne,paramTwo) =>
(value, previousValue, allValues) => {
console.log(paramOne,paramTwo,value)
}
Related
I'm trying to combine a onEdit script with an import range script, I tried using "if" to check if there's a single TRUE checkbox on the selected range but the import range part does not work only the checkbox part.
I need to import only after a single TRUE checkbox is enabled on column 7 otherwise the other spreadsheet glitches.
Source for the checkbox validation script: https://stackoverflow.com/a/71798583/18249133
function onEdit(e) {
const ss = SpreadsheetApp.getActiveSheet()
const { range: { columnStart, rowStart, rowEnd }, value } = e
if (value === "FALSE") return;
const checkRowStart = 4
const checkRowEnd = 200
const checkColumn = 7
if (columnStart === checkColumn && checkRowStart <= rowStart && checkRowEnd >= rowEnd) {
for (let i = 0; i < checkRowEnd; i++) {
ss.getRange(i + checkRowStart, checkColumn).setValue(false)
}
ss.getRange(rowStart, columnStart).setValue(true)
}
}
Import range script
function import(){
importRange(
"SPREADSHEET_ID",
"SHEET NAME + RANGE",
"SPREADSHEET_ID",
"SHEET NAME + RANGE",
);
};
function importRange(sourceID, sourceRange, destinationID, destinationRangeStart) {
const sourceSS = SpreadsheetApp.openById(sourceID);
const sourceRng = sourceSS.getRange(sourceRange);
const sourceVals = sourceRng.getValues();
const destinationSS = SpreadsheetApp.openById(destinationID);
const destStartRange = destinationSS.getRange(destinationRangeStart);
const destSheet = destinationSS.getSheetByName(destStartRange.getSheet().getName());
const destRange = destSheet.getRange(
destStartRange.getRow(),
destStartRange.getColumn(),
sourceVals.length,
sourceVals[0].length
);
destRange.setValues(sourceVals);
};
Thanks in advance :]
I have only started js recently, so i hope this makes sense..
I have made a simple dynamic form which starts with a table of 4 rows. After the heading row, the remaining 3 rows have +/- symbols which are to add or delete rows as necessary.
The add row functionality is currently working, however, even after assigning the correct class to the new row, the event listener wont work for the new buttons (even thought i have re-assigned the number of buttons within that class).
After adding the row, i re-assign btnAddRows and when logged to the console it is increasing with each row added. I can't figure out why it wont get captured in the for loop?
Thanks
//select elements on DOM
let btnAddRows = document.querySelectorAll('.btnADD');
let myTable = document.querySelector('#SecProp');
let myTableRows = document.querySelector('.tableRows');
for (let i = 0; i < btnAddRows.length; i++) {
btnAddRows[i].addEventListener('click', function () {
console.log(btnAddRows.length);
btnAddRows = document.querySelectorAll('.btnADD');
const rowNum = Number(btnAddRows[i].id.slice(6));
// console.log(rowNum);
// if (rowNum === myTableRows.length - 1) {
// addTableRow(rowNum);
// } else {
addTableRow(rowNum);
// }
btnAddRows = document.querySelectorAll('.btnADD');
myTable = document.querySelector('#SecProp');
myTableRows = document.querySelector('.tableRows');
});
}
const addTableRow = function (rowNum) {
//insert row into table
const addRw = myTable.insertRow(rowNum + 1);
const newRow = myTable.rows[rowNum + 1];
newRow.className = 'tableRows';
console.log(myTable.rows[rowNum + 1], typeof myTable.rows[rowNum + 1]);
const cell1 = newRow.insertCell(0);
const cell2 = newRow.insertCell(1);
const cell3 = newRow.insertCell(2);
const cell4 = newRow.insertCell(3);
const cell5 = newRow.insertCell(4);
cell1.className = 'column1';
cell2.className = 'coordsColumn';
cell3.className = 'coordsColumn';
cell4.className = 'buttons';
cell5.className = 'buttons';
cell1.innerHTML = `<td> ${rowNum + 1}</td>`;
cell2.innerHTML = '<td ><input type = "text" name="" value = ""/><td>';
cell3.innerHTML = '<td ><input type = "text" name="" value = ""/><td>';
cell4.innerHTML = `<td ><button class="btnADD btn btn-success" id="btnADD${
rowNum + 1
}"> + </button>`;
cell5.innerHTML = `<td ><button id="btnDEL${
rowNum + 1
}" class="btnDEL btn btn-success"> -</button>`;
};
Currently using:
ASP.NET Core 3.1 / EF Core
C#
Code-first approach
Postgres database
I'm building a method to support column searching on a table. I need to feed the column name to be searched by string value and build a query / lambda that can search the right column. I suspect I need to build some sort of expression and search on the expression but am having trouble with the syntax.
Here's the base code:
string search = "Search Value";
string givenColumn = "search_column";
IQueryable<MyModel> data = _dbContext.table;
data = data.Where(data => data.givenColumn.Contains(search));
I'd like to feed the column name in givenColumn and be able to build a query that searches the right column. At first I thought I wanted reflection but I'm looking to build a SQL query based off of a string, so I think I want to build an expression?
TIA!
Here is some sample code for a runtime WhereContains that operates on string columns:
public static class IQueryableExt {
// String.Contains(string)
static MethodInfo containsMI = typeof(string).GetMethod("Contains", 0, new[] { typeof(string) });
// generate r => r.{columnname}.Contains(value)
static Expression<Func<T, bool>> WhereContainsExpr<T>(string columnname, string value) {
// (T r)
var rParm = Expression.Parameter(typeof(T), "r");
// r.{columnname}
var rColExpr = Expression.Property(rParm, columnname);
// r.{columnname}.Contains(value)
var bodyExpr = Expression.Call(rColExpr, containsMI, Expression.Constant(value));
return Expression.Lambda<Func<T,bool>>(bodyExpr, rParm);
}
public static IQueryable<T> WhereContains<T>(this IQueryable<T> src, string columname, string value) => src.Where(WhereContainsExpr<T>(columname, value));
}
Just pass HTML Table id as a parameter onkeyup method of input field. HTML Code:
<input type="text" id="myInput" class="form-control search-input" onkeyup="searchData('myTable')" placeholder="Search...">
Javascript Code for exact match of any column:
function searchData(tableId) {
// Declare variables
var input, filter, table, tr, i, j, column_length, count_td;
column_length = document.getElementById(tableId).rows[0].cells.length;
input = document.getElementById("myInput");
filter = input.value.toUpperCase();
table = document.getElementById(tableId);
tr = table.getElementsByTagName("tr");
if (filter != "") {
for (i = 1; i < tr.length; i++) { // except first(heading) row
count_td = 0;
for (j = 1; j < column_length - 1; j++) { // except first column
td = tr[i].getElementsByTagName("td")[j];
/* ADD columns here that you want you to filter to be used on */
if (td) {
if (td.innerHTML.toUpperCase() === filter) {
count_td++;
}
}
}
if (count_td > 0) {
tr[i].style.display = "";
} else {
tr[i].style.display = "none";
}
}
}
else {
for (i = 1; i < tr.length; i++) {
tr[i].style.display = "";
}
}
}
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);
I would like to optimize following lines of code for Sorting.
public ViewResult Index(string sortorder, int? pagesize, int? page)
{
int pageSize = pagesize ?? 10;
if (Request.HttpMethod != "GET")
{
page = 1;
pageSize = 10;
}
ViewBag.SelectedPageSize = pageSize;
ViewBag.CurrentSort = sortorder;
ViewBag.FirstNameSortParm = String.IsNullOrEmpty(sortorder) ? "FirstName desc" : "";
ViewBag.LastNameSortParm = sortorder == "LastName" ? "LastName desc" : "LastName";
ViewBag.DepNameSortParm = sortorder == "depName" ? "depName desc" : "depName";
var joined = from tm in db.TabMasters select tm;
switch (sortorder)
{
case "FirstName":
joined = joined.OrderBy(m => m.FirstName);
break;
case "FirstName desc":
joined = joined.OrderByDescending(m => m.FirstName);
break;
case "LastName":
joined = joined.OrderBy(m => m.LastName);
break;
case "LastName desc":
joined = joined.OrderByDescending(m => m.LastName);
break;
case "depName":
joined = joined.OrderBy(m => m.depName);
break;
case "depName desc":
joined = joined.OrderByDescending(m => m.depName);
break;
default:
joined = joined.OrderBy(m => m.FirstName);
break;
}
int pageIndex = (page ?? 1) - 1;
int start = (pageIndex * pageSize);
ViewBag.TotalRecord = joined.Count();
ViewBag.StartRecord = start + 1;
ViewBag.EndRecord = ((start + pageSize) >= ViewBag.TotalRecord) ? ViewBag.TotalRecord : (start + pageSize);
return View(joined.ToPagedList(pageIndex, pageSize));
}
Because this is very tedious way if i have more the 10 fields to perform sort.
Thanks,
Imdadhusen
It's a bit vague to me what your actual goal is but for the switch part you could use an extension method as the below.
public static class SortExtensions
{
public static IEnumerable<T> SortByField<T>(this IEnumerable<T> sequence, string sortOrder)
{
var tokens = sortOrder.Trim().Split(' ');
var field = tokens[0];
var direction = tokens.Skip(1).Single().ToLower();
var prop = typeof(T).GetProperty(field);
return direction == "desc"
? sequence.OrderByDescending(m => prop.GetValue(m, null))
: sequence.OrderBy(m => prop.GetValue(m, null));
}
}
It will make a very simplified parsing of the sort order. It puts the responsibility on the calling party which is generally not what you want to do, so you might want some error handling in case the sortorder string does not fulfill the requirements.
from the sortorder string it fetches a name used to identify a property which can be used to fetch the value used for sorting.
you can use it like this:
db.TabMasters.SortByField(sortOrder)
EDIT based on comment:
The line typeof(T).GetProperty(field) is fragile in the absence of any error handling. It relies on the first token to be a name of a public property of the type T. It will return null if the name doesn't match a property. Including if it matches a Field name. A similar function exist for getting a FieldInfo
prop.GetField(field) will return a fieldinfo object of there's a public field with the given name otherwise null. To get the value of a field simply omit the last parameter to the GetValue call.
You should take a look at Linq.DynamicQuery.
There's more info in this blogpost http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx
The library lets you write following code:
var query = northwind.Products
.Where("CategoryID = 3 AND UnitPrice > 3")
.OrderBy("SupplierID");
instead of
var query = from p in northwind.Products
where p.CategoryID == 3 && p.UnitPrice > 3
orderby p.SupplierID
select p;
If you want to add the sortdirection:
var query = northwind.Products.OrderBy("SupplierID Descending");