Select form and validate input - forms

There are three different forms for product types and static form for typing the general info. When I select given form I need to validate the inputs if there are only numbers. I already have the code for evaluate the static part of form. For chosing forms I used vue.js.
In the dynamic forms when Im selecting the specified form and than assigning to it an eventListener it only works for the first selection than it shows error:
Cannot read properties of null (reading 'addEventListener')
var selectElement = document.getElementById("productType");
selectElement.addEventListener("change", function() {
var selectedValue = selectElement.value;
> //The div to show notification
var notsize = document.getElementById("notifications");
if (selectedValue === "DVD") {
> //The input field in form
var dvd2 = document.getElementById("size");
dvd2.addEventListener("input", () => {
> //Validating
var contain2 = /^[a-zA-Z]+$/.test(dvd2.value);
if (contain2) {
notsize.textContent = "Please provide the data of indicated type";
} else {
notsize.textContent = "";
}
});
} else if (selectedValue === "Furniture") {
> //Also need to validate when switched
} else if (selectedValue === "Book") {
}
});
> //Here is the vue element
<select id="productType" v-model="selectedOption">
<option v-for="option in options" :key="option.value">{{ option.text }}</option>
</select>
How can I chose the form and implement the validation dynamically?

Related

Filter list based on more than one field

I'm iterating a list of jobs and there's a search implemented on this list.
Search is working but now it only filters list based on one field.
Here's my list:
<ion-card *ngFor="let job of allJobs | search : searchTerm">
<ion-grid>
<ion-row>
<ion-col>
<div>
<span> {{job.day | uppercase}}</span>
<span> {{job.month | uppercase}}</span>
</div>
</ion-col>
<ion-col>
<div>
<span>{{job.time}}</span>
<span>{{job.name}}</span>
</div>
</ion-col>
</ion-row>
</ion-grid>
</ion-card>
I made a pipe for implementing search. Here's the code for it.
transform(items: any[], terms: string): any[] {
if(!items) return [];
if(!terms) return items;
terms = terms.toLowerCase();
return items.filter( it => {
return it.name.toLowerCase().includes(terms); // only filter name
});
}
Now the list gets filtered only based on the name field. I wanna filter the list based on day, month and time as well.
Can anyone tell me how to make this happen?
Sample Data for Jobs. Jobs is an array of objects
[
{
"id":10,
"day":"Monday",
"month":"June",
"time":"10",
"name":"John",
"email":"john#gmail.com"
},
{
"id":11,
"day":"Tuesday",
"month":"May",
"time":"12",
"name":"Jane",
"email":"jane#gmail.com"
},
{
"id":12,
"day":"Friday",
"month":"June",
"time":"16",
"name":"",
"email":"john#gmail.com"
},
{
"id":13,
"day":"Tuesday",
"month":"August",
"time":"21",
"name":"",
"email":"kevin#gmail.com"
},
{
"id":14,
"day":"Saturday",
"month":"December",
"time":"12",
"name":"Sam",
"email":"sam#gmail.com"
},
]
And searchTerm is just a string.
As you can see, there are more fields in the sample data than the one displayed in the HTML but I'm trying only to search for the fields that are displayed in the HTML. Some fields can have null values (for eg. name in the sample data has two null values)
I tried the solutions already provided but none of them are working for my requirement.
P.S: Read somewhere that pipes are not the best option to do functionality like this. I'm ready to implement this logic in the class as well.
Try combining your includes with the logical or-operator (||):
transform(items: any[], terms: string): any[] {
if (!items) return [];
if (!terms) return items;
terms = terms.toLowerCase();
return items.filter(it => {
return it.name.toLowerCase().includes(terms) ||
it.day.toLowerCase().includes(terms) ||
it.month.toLowerCase().includes(terms) ||
it.time.toLowerCase().includes(terms)
});
}
This statement will return true if any of the includes returns true. So basically any item which name, day, month or time contains the searchterm will be returned by the pipe.
This solution assumes that name, day, month and time are not null or undefined. But I'm assuming that is okay as your sample data suggests null values will be empty strings(""). If my assumption is not correct you'll have to check if the values are assigned, before accessing them.
Try this code.. it's pretty simple.
transform(items: any[], terms: string): any[] {
if (!items) return [];
if (!terms) return items;
terms = terms.toLowerCase();
terms = terms.trim();
return items.filter(it => {
if (it.day) {
return it.day.toLowerCase().includes(terms);
}
if (it.month) {
return it.month.toLowerCase().includes(terms);
}
if (it.time) {
return it.time.toLowerCase().includes(terms);
}
if (it.name) {
return it.name.toLowerCase().includes(terms);
}
});
}
If your JSON has null values, you can replace it with an empty string using the following code:
items = JSON.parse(JSON.stringify(items).replace(/null/g, '""'));
This dont work because the includes dont test for multiple term cases. You didnt say whats inside the items Array but if it is a String you could do this:
transform(items: any[], terms: string): any[] {
if(!items) return [];
if(!terms) return items;
terms = terms.toLowerCase();
return items.filter( it => {
//if it is something like "Programmer 07 November 12:00PM"
var informations = it.split(' '); //["Programmer", "07" ,"November" ,"12:00PM"]
var termArray = terms.split(' ');
var rightResult = true;
for (var index in termArray) {
if !(informations.include(termArray[index])) {
rightResult = false;
}
return rightResult;
});
}
Inside your transform method of your search pipe, apply filters on all the fields you want to apply filter on. Following will search for all keys in the object:
transform(items: any[], terms: string): any[] {
if(!items) return [];
if(!terms) return items;
terms = terms.toLowerCase();
return items.filter( it => {
return keys(it).reduce((prev, key) => {
return prev || key.toLowerCase().includes(term);
}, false);
});
}
If keys or Object.keys are not working, use the following code instead of reduce function:
...
let bInclude = false;
for(let key in it){
bInclude = bInclude || key.toLowerCase().includes(term);
}
return bInclude;
...
filterItems(param: any): void {
let val: string = param;
if (val) {
if (val.trim() !== '') {
this.filterItemsList = this.items.filter((data) => {
console.log(data.category);
return data.category.toLowerCase().indexOf(val.toLowerCase()) > -1
|| data.products.some(product => product.code.toLowerCase().indexOf(val.toLowerCase()) > -1);
})
}
}
}
it's working perfect

reactive forms: use one validator for multiple fields

I'm using angular 2 reactive forms and made a validator for a date of birth field. The validator is working, but it turns out the date of birth field is split into three new field: year, month, day. They all have their own validators. My question is, how can I change my code so my original date of birth validator works on three fields.
my original validator that checks one field.
input(2000/12/12) is valid
export function dobValidator(control) {
const val = control.value;
const dobPattern = /^\d{4}\/\d{2}\/\d{2}$/ ;
const comp = val.split('/');
const y = parseInt(comp[0], 10);
const m = parseInt(comp[1], 10);
const d = parseInt(comp[2], 10);
const jsMonth = m - 1;
const date = new Date(y, jsMonth, d);
const isStringValid = dobPattern.test(control.value);
const isDateValid = (date.getFullYear() === y && date.getMonth() === jsMonth && date.getDate() === d);
return (isStringValid && isDateValid) ? null : { invalidDob: ('Date of birth not valid') };
};
new html with 3 fields
year has a validator that checks the year
day has a validator that checks if the input is between 1 and 31
month has a validator that checks if the input is between 1 and 12.
I want to combine the above input of the three field into a new string and use my original date of birth validator.
<label>Date of birth :</label>
<div>
<div class="col-xs-1">
<input required type="text" formControlName="day" class="form-control" placeholder="dd" id="day"/>
<p *ngIf="form.controls.day.dirty && form.controls.day.errors">{{ form.controls.day.errors.invalidDay }}</p>
</div>
<div class="col-xs-1">
<input required type="text" formControlName="month" class="form-control" placeholder="mm" id="month"/>
<p *ngIf="form.controls.month.dirty && form.controls.month.errors">{{ form.controls.month.errors.invalidMonth }}</p>
</div>
<div class="col-xs-2">
<input required type="text" formControlName="year" class="form-control" placeholder="yyyy" id="year"/>
<p *ngIf="form.controls.year.dirty && form.controls.year.errors">{{ form.controls.year.errors.invalidYear }}</p>
</div>
</div>
<div>
<button type="submit" [disabled]="form.invalid">Submit</button>
</di>
I have created a validator for comparing two dates (their format is NgbDateStruct - as used in ng-bootstrap package's datepickers)
import { Directive, forwardRef, Attribute } from '#angular/core';
import { Validator, AbstractControl, NG_VALIDATORS, ValidatorFn } from '#angular/forms';
import { NgbDateStruct } from "#ng-bootstrap/ng-bootstrap";
import { toDate } from "../helpers/toDate";
export function dateCompareValidator(compareToControl: string, compareToValue: NgbDateStruct, compareType: string, reverse: boolean, errorName: string = 'dateCompare'): ValidatorFn {
return (c: AbstractControl): { [key: string]: any } => {
let compare = function (self: Date, compareTo: Date): any {
console.log('comparing ', compareType.toLowerCase());
console.log(self);
console.log(compareTo);
if (compareType.toLowerCase() === 'ge') {
if (self >= compareTo) {
return true;
} else {
return false;
}
} else if (compareType.toLowerCase() === 'le') {
if (self <= compareTo) {
return true;
} else {
return false;
}
}
return false;
};
// self value
let v = c.value;
// compare vlaue
let compareValue: Date;
let e;
if (compareToValue) {
compareValue = toDate(compareToValue);
} else {
e = c.root.get(compareToControl);
if (e) {
compareValue = toDate(e.value);
}
else {
// OTHER CONTROL NOT FOUND YET
return null;
}
}
let controlToValidate: AbstractControl = reverse ? e : c;
// validate and set result
let error = null;
let result = compare(toDate(c.value), compareValue);
if (result === true) {
console.log('clearing errors', compareToControl);
if (controlToValidate.errors) {
delete controlToValidate.errors[errorName];
if (!Object.keys(controlToValidate.errors).length) {
controlToValidate.setErrors(null);
}
}
else {
console.log('errors property not found in control', controlToValidate);
}
} else {
error = {};
error[errorName] = false;
controlToValidate.setErrors(error);
console.log(controlToValidate.errors);
console.log(controlToValidate.value);
console.log('Error Control', controlToValidate);
console.log('returning errors');
}
return reverse ? null : error;
}
}
Couldn't manage to modify much lot to best describe here as an answer but I believe you would get your query answered in this validator function code.
Note:
Function toDate() used in the code is a small function I created to convert NgbDateStruct into a javascript date object so that comparing dates can get easier. Here goes its implementation:
import { NgbDateStruct } from "#ng-bootstrap/ng-bootstrap"
export function toDate(ngbDate: NgbDateStruct): Date {
return ngbDate != null ? new Date(Date.UTC(ngbDate.year, ngbDate.month, ngbDate.day)) : null;
}

how to disable background-color input fields

I am using a form validation with javascript.
When submitting, the background-color of those input fields which are not valid changes to red color. When filling up this field and typing into another input field, the red background-color of the former field should go away. This is at the moment not the case. It only disappears when submitting again. How can I make this possible that the bg color changes back to normal when typing into another field?
// Return true if the input value is not empty
function isNotEmpty(inputId, errorMsg) {
var inputElement = document.getElementById(inputId);
var errorElement = document.getElementById(inputId + "Error");
var inputValue = inputElement.value.trim();
var isValid = (inputValue.length !== 0); // boolean
showMessage(isValid, inputElement, errorMsg, errorElement);
return isValid;
}
/* If "isValid" is false, print the errorMsg; else, reset to normal display.
* The errorMsg shall be displayed on errorElement if it exists;
* otherwise via an alert().
*/
function showMessage(isValid, inputElement, errorMsg, errorElement) {
if (!isValid) {
// Put up error message on errorElement or via alert()
if (errorElement !== null) {
errorElement.innerHTML = errorMsg;
} else {
alert(errorMsg);
}
// Change "class" of inputElement, so that CSS displays differently
if (inputElement !== null) {
inputElement.className = "error";
inputElement.focus();
}
} else {
// Reset to normal display
if (errorElement !== null) {
errorElement.innerHTML = "";
}
if (inputElement !== null) {
inputElement.className = "";
}
}
}
The form:
<td>Name<span class="red">*</span></td>
<td><input type="text" id="name" name="firstname"/></td>
<p id="nameError" class="red"> </p>
The submit:
<input type="submit" value="SEND" id="submit"/>
Css:
input.error { /* for the error input text fields */
background-color: #fbc0c0;
}
Update:
I tried this but it seems not to work:
function checkFilled() {
var inputVal = document.querySelectorAll("#offerteFirstname, #offerteLastname, #offertePhone, #offertePoster, #offerteStreet").value;
if (inputVal == "") {
document.querySelectorAll("#offerteFirstname, #offerteLastname, #offertePhone, #offertePoster, #offerteStreet").style.backgroundColor = "red";
}
else{
document.querySelectorAll("#offerteFirstname, #offerteLastname, #offertePhone, #offertePoster, #offerteStreet").style.backgroundColor = "white";
}
}
checkFilled();
here example of it
<input type="text" id="subEmail" onchange="checkFilled();"/>
and now you can JavaScript on input
function checkFilled() {
var inputVal = document.getElementById("subEmail").value;
if (inputVal == "") {
document.getElementById("subEmail").style.backgroundColor = "white";
}
else{
document.getElementById("subEmail").style.backgroundColor = "red";
}
}
checkFilled();
here working demo
Try
$(formElement).on('keyup','input.error', function(){
if(<values changed>){
$(this).removeClass('error');
}
});

How on earth do you get the return value from an MVC2 checkbox

I have a checkbox on one of my forms. And unfortunately, I cant't seem to figure out how to get the value out of the thing on the server side (my controlller). How in sam hill do you do that? It seems like you have to do a check for when the form ellement if not false?
How do you do this?
Adding some addition information
if ((formCollection["popID"] != null) && (formCollection["StartDate"] != null) && (formCollection["EndDate"] != null) && (formCollection["sendAnyway"] != null))
{
string popId = formCollection["popID"];
if (formCollection["StartDate"] != "")
{
startDate = DateTime.Parse(formCollection["StartDate"]);
}
if (formCollection["EndDate"] != "")
{
endDate = DateTime.Parse(formCollection["EndDate"]);
}
Boolean sendAnyway = Boolean.Parse(formCollection["sendAnyway"]);
if (client.ProcessGetABBYPopulation(popId, startDate, endDate, sendAnyway) == false)
{
return PutToQError("Error placing message on Queue");
}
else
{
//return Success("You successfully placed a message on the Queue");
return RedirectToAction("Home", "Home");
}
}
Here is my view (where I have a checkbox)
<%:Html.Label("Reprocess patients already sent during this timeframe?") %>
<%:Html.CheckBox("sendAnyway") %>
Update 2
Checking my return value it returns, "true,false"
what kind of sense does that make?
If you're not using a strongly typed view model, you're probably doing something like this:
<% Html.CheckBox("someName") %>
In which case, you can access it when you POST it to your server like so:
public ActionResult SomeMethod(string someName) // Bound via name on the parameter
{
string value = Request.Form["someName"]; // Or pulled from the Form collection
// someValue / value = "1" or whatever your checkbox value was, IF SELECTED.
// If unselected, it's NULL.
}
If you're using a strongly typed view model, it's available the same way:
<% Html.CheckBoxFor(x => x.IsSet) %>
And then accessed like:
public ActionResult SomeMethod(MySampleViewModel vm)
{
vm.IsSet; // true if selected, false if not
string request = Request.Form["IsSet"];
// request = value of your checkbox, NULL otherwise.
}

Do not submit empty form fields in ExtJS

I have an extjs form with fields. The user isn't required to enter data into each field so I do not want to submit the fields with no data. I want it to post only fields that actually have data. Is this possible?
I recommend using form's beforeaction event. While handling this event you can check all fields. If all values are empty just return false;. The following example works in ExtJS4 and has to work in ExtJS3:
myform.on('beforeaction', function(form, action) {
if (action.type == 'submit') {
var doSubmit = false, vals = form.getValues();
for (var i in vals)
if (vals[i] !== '') {
doSubmit = true;
break;
}
return doSubmit;
}
});
Actualy, the right way to not submit empty fields is to use action's submitEmptyText config. But it's not working in current version (ExtJS4.0.2a).
Another options is to override component's getSubmitValue() method and return null if this field is empty, this way it won't be included into submit fields.
{
xtype: 'combo',
getSubmitValue: function(){
var value = this.getValue();
if(Ext.isEmpty(value)) {
return null;
}
return value;
}
}
Instead of using form's submit, directly call Ext.Ajax.request(...) with the url, method type (GET/POST) and params (and any other options as explained in the call documentation).
To generate params, iterate over the form fields and check for null value before adding to params.
This bug is present in ExtJS 4.0.7 too.
As Molecule Man pointed:
Actualy, the right way to not submit empty fields is to use action's submitEmptyText config. But it's not working in current version (ExtJS4.0.2a).
A possible solution to fix this bug is by overriding 2 functions, getValues in "Ext.form.Basic" (where the bug is) and createForm (to create our basic form) in "Ext.form.Panel" by extension in the following way:
Ext.define("My.form.Basic", {
alias: "form.mybasic",
extend: "Ext.form.Basic",
getValues: function(asString, dirtyOnly, includeEmptyText, useDataValues) {
var values = {};
this.getFields().each(function(field) {
if (!dirtyOnly || field.isDirty()) {
var data = field[useDataValues ? "getModelData" : "getSubmitData"](includeEmptyText);
if (Ext.isObject(data)) {
var isArray = Ext.isArray;
Ext.iterate(data, function(name, val) {
if (includeEmptyText && val === "") {
val = field.emptyText || "";
}
if (includeEmptyText || ((!isArray(val) && val !== "") || (isArray(val) && val.length !== 0))) {
if (name in values) {
var bucket = values[name];
if (!isArray(bucket)) {
bucket = values[name] = [bucket];
}
if (isArray(val)) {
values[name] = bucket.concat(val);
}
else {
bucket.push(val);
}
}
else {
values[name] = val;
}
}
});
}
}
});
if (asString) {
values = Ext.Object.toQueryString(values);
}
return values;
}
});
Ext.define("My.form.Panel", {
alias: "form.mypanel",
extend: "Ext.form.Panel",
createForm: function() {
return Ext.create("My.form.Basic", this, Ext.applyIf({listeners: {}}, this.initialConfig));
}
});
The code is copied from the ext source code. The only change is inside the iteration of each field: introduced the following wrapping "if":
if (includeEmptyText || ((!isArray(val) && val !== "") || (isArray(val) && val.length !== 0)))
I am a bit late but, better later than never...