Create a Dynamic Checkbox Validation in Angular With Data from API - javascript

So I have a function that displays a list from an API:
displayEventTicketDetails() {
this.Service
.getEventTicketDetails().subscribe((data: any) => {
this.eventTicketDetails = data.map(ticket => ticket.ticket_name);
console.log(this.eventTicketDetails);
});
}
This is the result from the function above:
["Regular", "VIP", "Table", "Testing", "Cabana"]
Here is how the form array is declared:
ngOnInit() {
this.composeMessage = this.fb.group({
ticket: new FormArray([])
});
Then I use this function below to track if the check boxes are checked
onChange(event: any, isChecked: boolean){
const control = <FormArray>this.composeMessage.controls.ticket;
if(isChecked){
control.push(new FormControl(event))
} else{
const index = control.controls.findIndex(x => x.value === event);
control.removeAt(index)
}
}
Then finally in my ts file, here is my onsubmit function that submits the data on the form:
submitComposeMessage() {
this.submitted = true;
if (this.composeMessage.invalid) {
return;
}
const ticket = this.f.ticket.value;
this.Service
.createMessage(
ticket)
.subscribe(
(res: any) => {
if (res.err) {
this.toaster.errorToastr(res.message, null, { toastTimeout: 5000 });
return false;
}
this.toaster.successToastr(res.message, null, { toastTimeout: 5000 });
console.log("Message successfully created");
},
err => {
console.log(err);
}
);
}
So in my Html file here is my input field:
<ng-container *ngFor="let event of eventTicketDetails; let i = index" >
<label class="w-checkbox checkbox-field" >
<input
type="checkbox"
id="{{i}}"
name="checkbox-9"
class="w-checkbox-input checkbox"
(change)="onChange(event, $event.target.checked)"
[checked]="composeMessage.controls.ticket.value.indexOf(event)>=0">
<span class="no-margin w-form-label">{{event}}</span>
</label>
</ng-container>
With that loop, I'm able to get this result
So, I need help with two things:
1). I want all the checkbox to be checked by default when the page loads at first instance.
2). I want to validate the checkbox to ensure at least one checkbox is checked on submission.
I'll appreciate any help I can get.

If you want to only show validation message after submit, I would suggest the following, where we instead iterate the formarray in template, initially set all checked (as that is what you wish). We would listen to valueChanges of the formarray, but filter out as long as form is not submitted. We would introduce a new variable, for example isEmpty, which based on we would show/hide validation message. So all in all....
TS:
isEmpty = false;
submitted = false;
constructor(private fb: FormBuilder) {
const ctrls = this.eventTicketDetails.map(control => this.fb.control(true));
this.composeMessage = this.fb.group({
ticket: this.fb.array(ctrls)
});
this.tickets.valueChanges.pipe(
filter(() => !!this.submitted)
).subscribe((value) => {
value.some(x => x === true) ? this.isEmpty = false : this.isEmpty = true;
})
}
get tickets() {
return this.composeMessage.get("ticket") as FormArray;
}
onSubmit() {
this.submitted = true;
const selectedTickets = this.tickets.value
.map((checked, i) => (checked ? this.eventTicketDetails[i] : null))
.filter(value => !!value);
selectedTickets.length ? this.isEmpty = false : this.isEmpty = true
}
HTML:
<label formArrayName="ticket" *ngFor="let t of tickets.controls; index as i">
<input type="checkbox" [formControlName]="i">
{{eventTicketDetails[i]}}
</label>
<small *ngIf="isEmpty">Choose at least one checkbox</small>
STACKBLITZ

change Id to something like this
id="ticket{{i}}"
In this method write like this and call displayEventTicketDetails on ngOnit. This will check all the values:
displayEventTicketDetails() {
this.Service
.getEventTicketDetails().subscribe((data: any) => {
this.eventTicketDetails = data.map(ticket =>ticket.ticket_name);
setTimeout(() => {
for(var i= 0;i < this.evenTicketDetails.length ; i++){
var id = "ticket" + i;
(<HTMLInputElement>document.getElementById(id)).checked = true;
console.log(this.eventTicketDetails);
}, 500);
});
}
2. In submit method write something like this
submitComposeMessage() {
for(var i= 0;i < this.evenTicketDetails.length ; i++){
var id = "ticket" + i;
var resval = (<HTMLInputElement>document.getElementById(id)).value;
if(resval){
// this will check atleast one value is checked and if it true we are coming
out of the loop and performing other operations..
i = this.evenTicketDetails.length;
}
else{
// show error message or block from going forward..
}
});
}
This will solve your issues.

Related

onchange event being triggered when form submits

I would like the user to be able to record an action that they have carried out. I grouped the actions by category and then using two select menus and JS the user is only showed the actions from the category that they have selected. There is also a quantity input that is generated depending on which action is selected.
My issue is that when I submit the form, I get the error:
Uncaught TypeError: Cannot set property 'onchange' of null
The select box and the functionality implemented by the JS work until the form is submitted.
index.js
document.addEventListener("DOMContentLoaded", () => {
// First select
let cat_select = document.getElementById("id_post_cat");
cat_select.onchange = () => handleCatChange(cat_select.value);
// Second select
let desc_select = document.getElementById("id_post_action");
desc_select.onchange = () => handleDescChange(desc_select.value);
});
const handleCatChange = (cat) => {
let quantity_div = document.getElementById("quantity_div");
quantity_div.innerHTML = "";
// Fetching the actions in the category selected and populating second select
fetch(`/action/${cat}`)
.then((response) => response.json())
.then((data) => {
let desc_select = document.getElementById("id_post_action");
let optionHTML = "<option>---------</option>";
data.actions.forEach((action) => {
optionHTML +=
'<option value"' + action.id + '">' + action.desc + "</option>";
});
desc_select.innerHTML = optionHTML;
})
.catch((err) => console.log(err));
};
const handleDescChange = (desc) => {
let quantity_div = document.getElementById("quantity_div");
quantity_div.innerHTML = "";
let time_actions = [
"Public transport instead of driving",
"Walk/cycle instead of drive",
];
let quant_actions = [
"Unplug unused electrical items",
"Repurpose a waste object",
"Use a reusable bag",
"Buy an unpackaged item",
"Buy a locally produced item",
"Buy a second hand item",
"Buy an object in bulk",
"Use a refillable bottle/to-go mug",
"Drink a tap beer instead of bottled beer",
];
if (time_actions.includes(desc)) {
formAdder("Distance* (km)");
} else if (quant_actions.includes(desc)) {
formAdder("Quantity*");
}
};
const formAdder = (label_content) => {
let quantity_div = document.getElementById("quantity_div");
// Label
let label = document.createElement("label");
label.innerHTML = `${label_content}`;
label.setAttribute("for", "id_post_quantity");
label.classList += "requiredField";
// Input
let input = document.createElement("input");
input.setAttribute("id", "id_post_quantity");
input.setAttribute("name", "post_quantity");
input.setAttribute("required", "");
input.classList += "form-control";
quantity_div.append(label, input);
};
views.py
#login_required
def record(request):
if request.method == 'POST':
form = NewPostForm(request.POST)
if form.is_valid():
post = form.save(commit=False)
post.poster = request.user
if request.POST.get('id_post_quantity'):
post.post_quantity = request.POST.get('id_post_quantity')
post.save()
return HttpResponseRedirect(reverse('index'))
return render(request, 'my_app/record.html', {
'form': NewPostForm
})
record.html
<form action="{% url 'record' %}" method="post">
{% csrf_token %}
{{form.post_cat|as_crispy_field}}
{{form.post_action|as_crispy_field}}
<div class="form-group" id="quantity_div">
</div>
<button class="btn btn-success" type="submit">Post</button>
</form>
A pointer in the right direction would be greatly appreciated thank you.
It seems the onchange was being called on every page that was loaded. That meant that, when redirecting to the index page (where the select boxes don't exist), the getElementById was returning a null value etc.
I changed this by adding conditionals to check if the elements are present on the page:
document.addEventListener("DOMContentLoaded", () => {
// First select
let cat_select = document.getElementById("id_post_cat");
if (!!cat_select) {
cat_select.onchange = () => handleCatChange(cat_select.value);
}
// Second select
let desc_select = document.getElementById("id_post_action");
if (!!desc_select) {
desc_select.onchange = () => handleDescChange(desc_select.value);
}
});
Is there a more elegant/correct way of solving the same problem?
for me it got fixed when i changed on submit event to btn click event.

Reactive form: how to blur and submit in one click

I have a Reactive Form (#myform) with a button "foo", to which is attached (click) = myform.submit() so that the form will only submit when that button is clicked, and not on Enter events. The component listens for Enter events, and dispatches blur in that case, and the FormControls all have {updateOn: 'blur'} so blur events trigger updates (i.e., valueChanges, etc).
My problem is this: If I key data into an Input (or select an item in a Select) without hitting Enter or Tabbing out of the element and then click on the "foo", i.e. "Submit" button it seems that clicking the "foo" button only causes a blur event without triggering submission of the form (through myform.submit). I.e., the submit gets "swallowed" by the blur event.
How can I set this up so that if I don't Enter or Tab out of an element, and immediately click "foo", the element will be updated through the blur event AND THEN the form will ALSO be submitted?
I've tried things such as: 1. first processing the blur and then trying to programatically call myform.submit() in the component (by accessing the Form through #ViewChild), and 2. adding a (blur)= (submitNow && setTimeout(()=>myform.submit(),50) listener in the template view. At this point, I haven't even got this setTimeout call to compile, and none of the approaches I've tried seem to work so far.
The original code (simplified) is like this:
template details.component.html
<form #myform [formGroup]="form" method="POST" action="http://localhost:3000/users/{{userID}}/details">
<ng-container *ngFor="let sec of datArr">
<ng-container *ngFor="let row of sec; let i = index">
<input type="text"
[appTag]="row[datColEnum.tabCol]"
(keydown.enter)="onEnter($event)"
tabindex = "{{row[datColEnum.tabCol]}}"
name="{{row[datColEnum.controlNameCol]}}" value="{{row[datColEnum.valueCol]}}"
formControlName="{{row[datColEnum.controlNameCol]}}"/>
</ng-container>
</ng-container>
<button name="foo" type="button" (click)="myform.submit()">Submit</button>
</form>
component details.component.ts
export class DetailsComponent implements OnInit, AfterViewInit {
#ViewChildren(TagDirective) ipt!: QueryList<ElementRef>;
#ViewChild('myform', {static: true}) myform: any;
data: Object;
meta: Object;
datArr: any[] = [];
formCtls: any = {};
form: FormGroup = new FormGroup({});
tabIdx: number = 0;
focusItm: number = 0;
submitNow: boolean = false;
constructor(private member: MemberService, private route: ActivatedRoute, private el: ElementRef) { }
ngAfterViewInit() {
this.ipt.changes.subscribe(list=>{
setTimeout(()=>
list.filter(itm=>+itm.id===this.focusItm%this.tabIdx).forEach(itm=>{
if (!this.first_pass) this.navigateTo(itm.id);
}
),100)
})
}
doSubmit() {
this.submitNow = true;
}
navigateTo(ti: number) {
console.log(`NAVIGATING TO ITEM WITH TAB INDEX: ${ti}`)
this.ipt["_results"][ti-1].el.nativeElement.focus();
this.ipt["_results"][ti-1].el.nativeElement.style.borderWidth = "3px";
}
onEnter(e: Event) {
let cname = (<HTMLInputElement | HTMLSelectElement>e.target).name;
let idx = 0;
for (let itm of this.ipt["_results"]) {
if (itm.el.nativeElement.name === cname) {
this.focusItm = (itm.id+1)%this.ipt["_results"].length;
itm.el.nativeElement.style.borderWidth = "1px";
break;
}
}
e.target.dispatchEvent(new Event('blur'));
}
ngOnInit() {
. . .
. . .
//SET EVERYTHING UP
this.renderDataArray();
. . .
. . .
})
};
// SET UP ALL THE FormControls, etc. AND THE DATA MODEL datArr USED TO RENDER THE TEMPLATE
renderDataArray() {
this.datArr = [];
this.tabIdx = 0;
Object.keys(this.meta).forEach((sec,idx) => {
let rowCnt = this.getActiveArrayLen(sec);
for (let i = 0; i < rowCnt; i++) {
Object.keys(this.data[sec]).
.map((fld,idx)=>{
let itm = this.data[sec][fld];
this.tabIdx += 1;
let val = getVal();
let ctlName = sec+this.FLD_SPLIT_CHAR+fld;
this.removeControl(ctlName);
this.formCtls[ctlName] = new FormControl(val, {updateOn: 'blur'});
this.form.addControl(ctlName, this.formCtls[ctlName]);
of(this.tabIdx).
pipe(switchMap(ti=>this.formCtls[ctlName].valueChanges.
pipe(map(newVal => [newVal,ti]))
)
).subscribe(([newVal,ti])=>{
if (Array.isArray(itm["value"])) {
itm["value"][+(itm["value"].length || 1)-1]=newVal || '';
} else {
itm["value"]=newVal || '';
}
this.focusItm = (ti+1)%this.ipt["_results"].length;
this.renderDataArray();
});
. . .
. . .

How to perform calculation with values of dynamic input fields?

I have a little problem with my html form code...
In my code, there are few input fields which are generated dynamically. In every input field generated dynamically, there is some numerical value. i need to do some Mathematical calculation with them.
="PE+ROCE+(2-SG)-(4-DY/2)"
This is a pattern of my calculation. In this, PE, ROCE etc are the IDs of Dynamic Input fields generated.
Using values of dynamic input fields generated, I need to perform above calculation.
This calculation has to be executed when the user would click on "Calculate" Input Button.
Then, the final calculated value from the above will be shown in the Output Tag present in bottom of my form code.
I tried to solve this problem on my own. But unfortunately, failed in this task.
somebody can now please help me to solve this problem.
I will be very grateful...
here is my full code of form..
// define the headings here, so we can access it globally
// in the app
let headings = []
// appending the created HTML string to the DOM
function initInputs(headingList) {
jQuery(".fields").append(createInputsHTML(headingList))
}
// the HTMLT template that is going to be appended
// to the DOM
function createInputsHTML(headingList) {
let html = ''
headingList.forEach(heading => {
if (heading !== 'Company') {
html += `<label for="${heading}">${heading}: </label>`
html += `<input id="${heading}">`
html += '<br>'
}
})
return html
}
// receiving data
// this data arrives later in the app's lifecycle,
// so it's the best to return a Promise object
// that gets resolved (check JS Promise for more information)
function getJSON() {
return new Promise(resolve => {
jQuery.get("https://cors-anywhere.herokuapp.com/www.coasilat.com/wp-content/uploads/2019/06/data-1.txt", function(data) {
resolve(JSON.parse(data))
});
})
}
// processing raw JSON data
function processRawData(data) {
return new Promise(resolve => {
const companyData = []
// creating data array
// handling multiple sheets
Object.values(data).forEach((sheet, index) => {
sheet.forEach((company, i) => {
companyData.push({ ...company
})
// create headings only once
if (index === 0 && i === 0) {
Object.keys(company).forEach(item => {
headings.push(item.trim())
})
}
})
})
resolve(companyData)
})
}
$(async function() {
let lists = [];
function initAutocomplete(list) {
const thisKey = 'Company'
$("#company").autocomplete('option', 'source', function(request, response) {
response(
list.filter(item => {
if (item[thisKey].toLowerCase().includes(request.term.toLowerCase())) {
item.label = item[thisKey]
return item
}
})
)
})
}
$("#company").autocomplete({
minLength: 3,
source: lists,
focus: function(event, ui) {
// the "species" is constant - it shouldn't be modified
$("#company").val(ui.item.Company);
return false;
},
select: function(event, ui) {
// handling n number of fields / columns
headings.forEach(heading => {
$('#' + heading).val(ui.item[heading])
})
return false;
}
});
// starting data download, processing and usage
getJSON()
.then(json => {
return processRawData(json)
})
.then(data => {
// just so we see what data we are using
console.log(data)
// make the processed data accessible globally
lists = data
initAutocomplete(lists)
initInputs(headings)
})
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<link href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css" rel="stylesheet" />
<div class="ui-widget">
<form id="frm1">
<label for="company">Company: </label>
<input id="company"><br />
<div class="fields"></div>
<input type="submit" id="calculate" value="Calculate">
<p>Final Amount <output name="amount" for="calculation">0</output></p>
</form>
</div>
Try each loop of inputs
$("#Calculate").click(function(){
var peVal,roceVal,sgVal,dyVal;
jQuery(".fields input").each(function (){
var idHeading=$(this).attr("id");
if(idHeading=="Your ID for PE input"){
peVal=parseInt($(this).val());
}
if(idHeading=="Your ID for ROCE input "){
roceVal=parseInt($(this).val());
}
if(idHeading=="Your ID for SG input"){
sgVal=parseInt($(this).val());
}
if(idHeading=="Your ID for DY input"){
dyVal=parseInt($(this).val());
}
});
var output=peVal+roceVal+(2-sgVal)-(4-dyVal/2);
});

How do I change this Contact Form's Javascript so that IF a key is something else, perform different action?

I have a Contact Form that utilizes Google Scripts. It successfully sends the email and formats it decently to my inbox, but there are 2 problems:
-I need it so that IF var key is equal to 'Action', then do not display it in the email it sends. Because right now, "Action send_message" is getting included in the email and I don't like that.
For this, I have unsuccessfully tried things like:
for (var idx in order) {
var key = order[idx];
//Skip this entry into the email output if it is the Action
if( key === 'Action') {
continue
}
It seems to not react to this code at all.
-I also need it so that if a city is selected, e.g. Alachua, that the email says 'Alachua' instead of 'Florida_Alachua'. But I can't add a NAME to an option since apparently options don't have that property. I also can't do the quick fix of changing the VALUE of the <option> to resolve this step, because of other code I have that conflicts with this route.
Google Scripts Code:
/******************************************************************************
* This tutorial is based on the work of Martin Hawksey twitter.com/mhawksey *
* But has been simplified and cleaned up to make it more beginner friendly *
* All credit still goes to Martin and any issues/complaints/questions to me. *
******************************************************************************/
// if you want to store your email server-side (hidden), uncomment the next line
var TO_ADDRESS = "myemail#email.com";
// spit out all the keys/values from the form in HTML for email
// uses an array of keys if provided or the object to determine field order
function formatMailBody(obj, order) {
var result = "";
if (!order) {
order = Object.keys(obj);
}
// loop over all keys in the ordered form data
for (var idx in order) {
var key = order[idx];
result += "<h4 style='text-transform: capitalize; margin-bottom: 0'>" + key + "</h4><div>" + sanitizeInput(obj[key]) + "</div>";
// for every key, concatenate an `<h4 />`/`<div />` pairing of the key name and its value,
// and append it to the `result` string created at the start.
}
return result; // once the looping is done, `result` will be one long string to put in the email body
}
// sanitize content from the user - trust no one
// ref: https://developers.google.com/apps-script/reference/html/html-output#appendUntrusted(String)
function sanitizeInput(rawInput) {
var placeholder = HtmlService.createHtmlOutput(" ");
placeholder.appendUntrusted(rawInput);
return placeholder.getContent();
}
function doPost(e) {
try {
Logger.log(e); // the Google Script version of console.log see: Class Logger
record_data(e);
// shorter name for form data
var mailData = e.parameters;
// names and order of form elements (if set)
var orderParameter = e.parameters.formDataNameOrder;
var dataOrder;
if (orderParameter) {
dataOrder = JSON.parse(orderParameter);
}
// determine recepient of the email
// if you have your email uncommented above, it uses that `TO_ADDRESS`
// otherwise, it defaults to the email provided by the form's data attribute
var sendEmailTo = (typeof TO_ADDRESS !== "undefined") ? TO_ADDRESS : mailData.formGoogleSendEmail;
// send email if to address is set
if (sendEmailTo) {
MailApp.sendEmail({
to: String(sendEmailTo),
subject: "Contact form submitted",
// replyTo: String(mailData.email), // This is optional and reliant on your form actually collecting a field named `email`
htmlBody: formatMailBody(mailData, dataOrder)
});
}
return ContentService // return json success results
.createTextOutput(
JSON.stringify({"result":"success",
"data": JSON.stringify(e.parameters) }))
.setMimeType(ContentService.MimeType.JSON);
} catch(error) { // if error return this
Logger.log(error);
return ContentService
.createTextOutput(JSON.stringify({"result":"error", "error": error}))
.setMimeType(ContentService.MimeType.JSON);
}
}
/**
* record_data inserts the data received from the html form submission
* e is the data received from the POST
*/
function record_data(e) {
var lock = LockService.getDocumentLock();
lock.waitLock(30000); // hold off up to 30 sec to avoid concurrent writing
try {
Logger.log(JSON.stringify(e)); // log the POST data in case we need to debug it
// select the 'responses' sheet by default
var doc = SpreadsheetApp.getActiveSpreadsheet();
var sheetName = e.parameters.formGoogleSheetName || "responses";
var sheet = doc.getSheetByName(sheetName);
var oldHeader = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues()[0];
var newHeader = oldHeader.slice();
var fieldsFromForm = getDataColumns(e.parameters);
var row = [new Date()]; // first element in the row should always be a timestamp
// loop through the header columns
for (var i = 1; i < oldHeader.length; i++) { // start at 1 to avoid Timestamp column
var field = oldHeader[i];
var output = getFieldFromData(field, e.parameters);
row.push(output);
// mark as stored by removing from form fields
var formIndex = fieldsFromForm.indexOf(field);
if (formIndex > -1) {
fieldsFromForm.splice(formIndex, 1);
}
}
// set any new fields in our form
for (var i = 0; i < fieldsFromForm.length; i++) {
var field = fieldsFromForm[i];
var output = getFieldFromData(field, e.parameters);
row.push(output);
newHeader.push(field);
}
// more efficient to set values as [][] array than individually
var nextRow = sheet.getLastRow() + 1; // get next row
sheet.getRange(nextRow, 1, 1, row.length).setValues([row]);
// update header row with any new data
if (newHeader.length > oldHeader.length) {
sheet.getRange(1, 1, 1, newHeader.length).setValues([newHeader]);
}
}
catch(error) {
Logger.log(error);
}
finally {
lock.releaseLock();
return;
}
}
function getDataColumns(data) {
return Object.keys(data).filter(function(column) {
return !(column === 'formDataNameOrder' || column === 'formGoogleSheetName' || column === 'formGoogleSendEmail' || column === 'honeypot');
});
}
function getFieldFromData(field, data) {
var values = data[field] || '';
var output = values.join ? values.join(', ') : values;
return output;
}
Contact Form HTML
<section id="contact-form">
<form id="gform"
class="contact-form" method="post"
action="(Google Scripts URL)"
enctype="text/plain">
<p>
<label for="name">Your Name <font face="Arial" color="red">*</font></label>
<input type="text" style="height:35px;" class="heighttext required" name="name" id="name" class="required" title="* Please provide your name">
</p>
<p>
<label>Your Location <font face="Arial" color="red">*</font></label>
<select name="Location" id="column_select" style="height:35px;" class="required" title=" * Please provide your location">
<option selected value="col00">-- State --</option>
<option value="Alabama">Alabama</option>
<option value="California">California</option>
<option value="Florida">Florida</option>
</select>
<select name="City" id="layout_select" style="height:35px;">
<option disabled selected value="Florida">-- City --</option>
<option name="Alachua" value="Florida_Alachua">Alachua</option>
<option name="Alford" value="Florida_Alford">Alford</option>
</select>
</p>
<p>
<input type="submit" value="Send Message" id="submit" class="pp-btn special">
<img src="images/ajax-loader.gif" id="contact-loader" alt="Loading...">
<input type="hidden" name="action" value="send_message">
</p>
</form>
</section><!-- #contact-form -->
Form Handler Javascript
(function() {
function validEmail(email) { // see:
var re = /^([\w-]+(?:\.[\w-]+)*)#((?:[\w-]+\.)*\w[\w-]{0,66})\.([a-z]{2,6}(?:\.[a-z]{2})?)$/i;
return re.test(email);
}
function validateHuman(honeypot) {
if (honeypot) { //if hidden form filled up
console.log("Robot Detected!");
return true;
} else {
console.log("Welcome Human!");
}
}
// get all data in form and return object
function getFormData() {
var form = document.getElementById("gform");
var elements = form.elements;
var fields = Object.keys(elements).filter(function(k) {
return (elements[k].name !== "honeypot");
}).map(function(k) {
if(elements[k].name !== undefined) {
return elements[k].name;
// special case for Edge's html collection
}else if(elements[k].length > 0){
return elements[k].item(0).name;
}
}).filter(function(item, pos, self) {
return self.indexOf(item) == pos && item;
});
var formData = {};
fields.forEach(function(name){
var element = elements[name];
// singular form elements just have one value
formData[name] = element.value;
// when our element has multiple items, get their values
if (element.length) {
var data = [];
for (var i = 0; i < element.length; i++) {
var item = element.item(i);
if (item.checked || item.selected) {
data.push(item.value);
}
}
formData[name] = data.join(', ');
}
});
// add form-specific values into the data
formData.formDataNameOrder = JSON.stringify(fields);
formData.formGoogleSheetName = form.dataset.sheet || "responses"; // default sheet name
formData.formGoogleSendEmail = form.dataset.email || ""; // no email by default
console.log(formData);
return formData;
}
function handleFormSubmit(event) { // handles form submit without any jquery
event.preventDefault(); // we are submitting via xhr below
var data = getFormData(); // get the values submitted in the form
/* OPTION: Remove this comment to enable SPAM prevention, see README.md
if (validateHuman(data.honeypot)) { //if form is filled, form will not be submitted
return false;
}
*/
if( data.email && !validEmail(data.email) ) { // if email is not valid show error
var invalidEmail = document.getElementById("email-invalid");
if (invalidEmail) {
invalidEmail.style.display = "block";
return false;
}
} else {
disableAllButtons(event.target);
var url = event.target.action; //
var xhr = new XMLHttpRequest();
xhr.open('POST', url);
// xhr.withCredentials = true;
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhr.onreadystatechange = function() {
console.log( xhr.status, xhr.statusText )
console.log(xhr.responseText);
//document.getElementById("gform").style.display = "none"; // hide form
/*
var thankYouMessage = document.getElementById("thankyou_message");
if (thankYouMessage) {
thankYouMessage.style.display = "block";
}
*/
return;
};
// url encode form data for sending as post data
var encoded = Object.keys(data).map(function(k) {
return encodeURIComponent(k) + "=" + encodeURIComponent(data[k])
}).join('&')
xhr.send(encoded);
}
}
function loaded() {
console.log("Contact form submission handler loaded successfully.");
// bind to the submit event of our form
var form = document.getElementById("gform");
form.addEventListener("submit", handleFormSubmit, false);
};
document.addEventListener("DOMContentLoaded", loaded, false);
function disableAllButtons(form) {
var buttons = form.querySelectorAll("button");
for (var i = 0; i < buttons.length; i++) {
buttons[i].disabled = true;
}
}
})();
finally, this is the extra code that would break if I simply tried changing the value of option to, e.g., 'Alachua' instead of 'Flordia_Alachua'. https://jsfiddle.net/hmatt843/504dgmqy/19/
Thanks for any and all help.
Try console.log(key) before if( key === 'Action'). I think you'll find that key never equals 'Action', exactly. Looks like you'll need if( key === 'action'), instead.
If you wish to remove part of string value, try the replace method: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace
It also looks like you're trying to work with elements[k].name when you mean to be working with elements[k].value.
I believe your code should look something like...
function(k) {
if(elements[k].value !== undefined) {
return elements[k].value.replace('Florida_', '');
// special case for Edge's html collection
} else if(elements[k].length > 0){
return elements[k].item(0).value.replace('Florida_', '');
}
}
... or something to that effect.
In the future, you may want to make it easier for folks trying to help you by posting only the portions of code your having trouble with, and breaking your questions into different posts. A lot to sift through up there.
Hope this helped.
The split() method splits a String object into an array of strings by separating the string into substrings, using a specified separator string to determine where to make each split.
Var splitValue = elements[k].item(0).value.split("");
splitValue[1] will give you a string of characters after the delimeter () in this case.

JavaScript Model Form Validation

I am using BackboneJS MVC pattern and have a form with 2 fields which the user can select.
I call changeAction whenever there is any change in selection by the user (to call validation);
changeAction: function (event) {
var self = this;
var target = event.target;
target.value = $.trim(target.value);
change[target.name] = target.value;
this.model.set(change);
var check = self.model.validateItem(target.id);
if (check.isValid === false) {
self.addValidationError(target.id, check.message);
} else {
self.removeValidationError(target.id);
}
}
My validation is defined in the Model as below;
this.validators.myDropDownField = function(value) {
return !_.isUndefined(value) && !_.isNull(value) && $.trim(value).length > 0 ? {
isValid: true
} : {
isValid: false,
message: "Select dropdown field"
};
};
validateItem: function(key) {
var result = (this.validators[key]) ? this.validators[key](this.get(key)) : {
isValid: true
};
return result;
}
Now my question is I do not want to do anything to the Model in changeAction.
But if I remove the line this.model.set(change) in changeAction()
the validation does not work correctly. I do not get the value in the function
this.validators.myDropDownField
How do I handle this ?

Categories