"An undefined behavior was detected: undefined is not an instance of java.lang.String" - scala.js

I am using scalajs/angulate
I have a problem that only occurs when using type="email" on a form. When i change it to type="text" the problem disappears.
The problem manifests itself:
The email field does not change when typing
Exception "An undefined behavior was detected: undefined is not an instance of java.lang.String"
This is my controller
class FooInfoController(…) extends Controller {
var name: String = _
var email: String = _
…
}
And the html
<div class="wrapper" ng-controller="FooInfoController as ctrl">
<form ng-submit="ctrl.add()">
<div class="form-group">
<label for="email">Email</label>
<input class="form-control" id="email" required maxlength="80" name="email" size="20" type="email"
ng-model="ctrl.email"
placeholder="email address">
</div>
</form>
</div>

Related

How can I make this form dynamically with ES6 by extending a base class form?

I would like to make forms in JS that act like they're inheriting...For example, I can easily append form elements all day long using a for loop, but I'd rather leave myself the freedom to insert a different element in the middle. In other words, I want this to be 'modular', and have a base class that can generate something simple like a login screen, but then extend it to include dropdowns in between text fields. Any ideas as to how to make this happen? Preferably with ES6 classes and import/export and without the webpack nonsense.
Ideally i'd have a class called BasicForm and have RegistrationForm extends BasicForm. This way, I could simply store field names in an array and change that file once if i needed to make changes as opposed to changing everything. Here's the existing code....Note that "invoices" is only shown if the user role option selected is "admin"....which makes the idea of trying to make this all very difficult for me to comprehend. Is there any way to procedurally generate, with bootstrap and custom classes, this from Javascript using ES6 classes, such that the module may be reused to create forms either with or without dropdowns?
HTML:
<div class= "row"> <!--Inherits background from .body-->
<div class="col-hidden col-sm col-md col-lg col-xl"> <!--spacing divs inherit background from .body-->
</div>
<div class="form-box rounded col-12 col-xs col-sm-7 col-md-6 col-lg-4 col-xl-3"> <!--Actual box containing fields and prompts and buttons changes to new background-->
<h2 class="portal-heading">Registration</h2>
<form name="new_user_form">
Email Address<input type="text" class="form-control register-field highlight-hover" name="email" value="" placeholder="Email Address"><br>
Re-Enter Email Address<input type="text" class="form-control register-field highlight-hover" autocomplete="off" name="email" value="" placeholder="Re-enter Email Address"><br>
First Name<input type="text" class="form-control register-field highlight-hover" autocomplete="given-name" name="firstname" value="" placeholder="First Name"><br>
Last Name<input type="text" class="form-control register-field highlight-hover" autocomplete="family-name" name="lastname" value="" placeholder="Last Name"><br>
Company Name<img src="images/help-icon.png">
<select class="form-control register-field highlight-hover" name="company">
<option value="noSelect">Select</option>
<option value="company2">Company 2</option>
</select>
Mobile Phone <img src="images/help-icon.png">
<input type="text" class="form-control register-field highlight-hover" autocomplete="tel" name="mobile" value="" placeholder="0005559999"><br>
Portal User Role <img src="images/help-icon.png">
<select class="form-control register-field highlight-hover" name="role" id="user-role">
<option value="user">User</option>
<option value="admin">Admin</option>
</select>
<div id="invoices">
Enter two recent invoice totals in USD($)<br>
Invoice 1<input type="text" class="form-control register-field highlight-hover" name="invoice1" value="" placeholder="0.00">
Invoice 2<input type="text" class="form-control register-field highlight-hover" name="invoice2" value="" placeholder="0.00">
</div>
<button class="btn btn-block highlight-hover" id="submit">Submit</button>
</form>
</div>
<div class="col-hidden col-sm col-md col-lg col-xl"> <!--spacing divs-->
</div>
</div>
I would suggest using Web Components. They're native, have support in Chrome with other browsers soon to come, and you can use a polyfill for other browsers. With below code:
class WordCount extends HTMLParagraphElement {
constructor() {
// Always call super first in constructor
super();
//put code here
}
}
Insert code found at https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements after super() with your element functionality
Define a new element: `customElements.define('popup-info', PopUpInfo);
And then you can use it like this:
<popup-info img="img/alt.png" text="Your card validation code (CVC)
is an extra security feature — it is the last 3 or 4 numbers on the
back of your card.">
Example taken from link above, in Mozilla's Dev Site.
Not sure if this can help (?): classList, it is meant to test if a class exist, at a precise position.
It isn't well documented, but found it very useful to bind stuffs.
Using a timeout for the demo (Added id="company" class="hidden"):
function toggle(id){
if (id.classList[0] === "hidden"){
id.classList = "unhidden"
}
else {
id.classList = "hidden"
}
}
setTimeout(function(){
toggle(company)
},3000)
.hidden {display: none}
.unhidden {display: block}
<div class= "row">
<div>
</div>
<div>
<h2>Registration</h2>
<form name="new_user_form">
Email Address<input type="text" name="email" value="" placeholder="Email Address"><br>
Re-Enter Email Address<input type="text" autocomplete="off" name="email" value="" placeholder="Re-enter Email Address"><br>
First Name<input type="text" autocomplete="given-name" name="firstname" value="" placeholder="First Name"><br>
Last Name<input type="text" autocomplete="family-name" name="lastname" value="" placeholder="Last Name"><br>
Company Name<a href="#"
data-toggle="tooltip" title="Choose your company name. If you do not see it here, please contact ACSI to become an official distributor."><img src="images/help-icon.png"></a>
<select id="company" class="hidden" name="company">
<option value="noSelect">Select</option>
<option value="company2">Company 2</option>
</select>
Mobile Phone <img src="images/help-icon.png">
<input type="text" autocomplete="tel" name="mobile" value="" placeholder="0005559999"><br>
Portal User Role <img src="images/help-icon.png">
<select name="role" id="user-role">
<option value="user">User</option>
<option value="admin">Admin</option>
</select>
<div id="invoices">
Enter two recent invoice totals in USD($)<br>
Invoice 1<input type="text" name="invoice1" value="" placeholder="0.00">
Invoice 2<input type="text" name="invoice2" value="" placeholder="0.00">
</div>
<button id="submit">Submit</button>
</form>
</div>
<div>
</div>
</div>
Steps:
Create a div, append it to document.
Create a form, append it to div.
Create fieldsets, append to form.
4.Create form fields, append to fieldset.
class BasicForm {
constructor(formId,formTitle) {
this.form = document.createElement('form');
this.form.id = formId;
this.form.method = 'post';
this.form.enctype = 'multipart/form-data';
this.topFieldset = document.createElement('fieldset');
this.topLegend = document.createElement('legend');
this.topLegend.appendChild(document.createTextNode(formTitle));
this.topFieldset.appendChild(this.topLegend);
this.form.appendChild(this.topFieldset);
this.div = document.createElement('div');
this.div.appendChild(this.form);
// add div to the document
// add fields to the topFieldset
}
}
class RegistrationForm extends BasicForm {
constructor() {
super();
// add fields of derived form
}
}
Note: the code is not tested.

Angular Form Validation error : form is undefined

I am trying to validate my data for a student object with Angular Form Validation, but when I want to use or print for example, the serialNumber of a student it gives me this error: Cannot read property 'serialNumber' of undefined.
Here is the code:
<div *ngIf="student">
<div class=container>
<h2>Student {{student.name}} details</h2>
<form name="studentForm" (ngSubmit)="save()">
<!--<div ng-class="{ 'has-error' : studentForm.serialNumber.$invalid && !studentForm.serialNumber.t">-->
<label>Serial number: {{student.serialNumber}} </label>
<input type="text" name="serialNumber" class="form-control" ng-model="student.serialNumber" required>
<div ng-messages="studentForm.serialNumber.$error">
{{studentForm.serialNumber}}
<p ng-message="required">Your name is required!</p>
</div>
<!--</div>-->
<div>
<label>Name: {{student.name}}</label>
<input ng-model="student.name" placeholder="name">
</div>
<div>
<label>Group number: {{student.groupNumber}}</label>
<input ng-model="student.groupNumber" placeholder="groupNumber">
</div>
<button (click)="goBack()">Back</button>
<button (click)="save()">Save</button>
</form>
</div>
</div>
The ng-messages and ng-model attribute directives do not exist in Angular 2+. I would recommend reading into Angular Forms, ReactiveForms, and Template Syntax.
If you would like to dual data-bind the input values, you can do so with the following syntax: [(ngModel)]="student.serialNumber". However, in Angular 2+, there are usually better ways of getting values other than explicitly data-binding.
Angular Form Validation template Driven Model
onSubmit(form : NgForm) {
console.log(form);
}
<form #form="ngForm" (ngSubmit)="onSubmit(form)"
[ngClass]="{'was-validated': form.invalid && (form.dirty || form.touched)}">
<div class="" ngModelGroup="User">
<h2 class="text-center">Registration page</h2>
<br />
<div class="form-group">
<input type="text" class="form-control" placeholder="First Name" name="firstname" required
ngModel #firstname="ngModel">
<span class="help-bpx" *ngIf="firstname.touched && !firstname.valid ">Please enter the
firstname</span>
</div>
<div class="form-group">
<input type="text" class="form-control" placeholder="Last Name" name="lastname" required ngModel
#lastname="ngModel">
<span class="help-bpx" *ngIf="lastname.touched && !lastname.valid ">Please enter the
lastname</span>
</div>
<div class="form-group">
<input type="email" class="form-control" id="email" placeholder="Email" name="email" email
required ngModel #email="ngModel">
<span class="help-bpx" *ngIf="email.touched && !email.valid ">Please enter the Email
Value</span>
</div>
<div class="form-group">
<div class="custom-file">
<input type="file" class="custom-file-input" id="customFile" required ngModel name="file" #file="ngModel">
<label class="custom-file-label" for="customFile">Choose file</label>
</div>
</div>
<br />
<div class="align-center">
<button type="submit" class="btn btn-primary" [disabled]="!form.valid">Register</button>
</div>
</div>
</form>

Cannot read property of undefined in record edit form in angular 2

I have a problem in my edit form with undefined properties. I have an API that allows me to create and update customers. The problem is that some of the nested attributes are optional, this is fine when creating or editing fields that already exist but i can't figure out what to do when editing one of the nested fields on a customer that wasn't created with those fields and keep getting Cannot read property undefined errors.
This is my customer object:
export class Customer {
CompanyName: string;
DisplayName: string;
FamilyName: string;
GivenName: string;
Id: number;
Title: string;
BillAddr: BillAddress;
ShipAddr: ShipAddress;
PrimaryPhone: PrimaryPhoneNumber;
Mobile: MobileNumber;
PrimaryEmailAddr: PrimaryEmailAddress;
}
export class ShipAddress {
City: string;
Country: string;
CountrySubDivisionCode: string;
Line1: string;
Line2: string;
Line3: string;
Line4: string;
Line5: string;
PostalCode:string;
}
export class BillAddress {
City: string;
Country: string;
CountrySubDivisionCode: string;
Line1: string;
Line2: string;
Line3: string;
Line4: string;
Line5: string;
PostalCode:string;
}
export class PrimaryPhoneNumber {
FreeFormNumber: number;
}
export class MobileNumber {
FreeFormNumber: number;
}
export class PrimaryEmailAddress {
Address: string;
}
This is the html from the edit component:
<h1 class="page-header">Edit Customer</h1>
<div [ngBusy]="busy"></div>
<form (ngSubmit)="onSubmit()">
<div class="row">
<div class="col-md-6">
<h3>Customer information</h3>
<div class="form-group">
<label for="customertitle">Title</label>
<input type="text" class="form-control" id="cutomertitle" placeholder="Title" name="title" [(ngModel)]="customer && customer.Title" >
</div>
<div class="form-group">
<label for="customerGivenName">First Name</label>
<input type="text" class="form-control" id="customerGivenName" placeholder="First Name" name="givenname" [(ngModel)]="customer && customer.GivenName" >
</div>
<div class="form-group">
<label for="customerFamilyName">Last Name</label>
<input type="text" class="form-control" id="customerFamilyName" placeholder="Surname" name="familyname" [(ngModel)]="customer && customer.FamilyName" >
</div>
<div class="form-group">
<label for="customerEmailAddress">Email Address</label>
<input type="text" class="form-control" id="customerEmailAddress" placeholder="Email" name="email" [(ngModel)]="customer && customer.PrimaryEmailAddr.Address" >
</div>
<div class="form-group">
<label for="customerPhone">Phone</label>
<input type="text" class="form-control" id="customerPhone" placeholder="Phone Number" name="primaryphone" [(ngModel)]="customer && customer.PrimaryPhone.FreeFormNumber" >
</div>
<div class="form-group">
<label for="customerMobile">Mobile</label>
<input type="text" class="form-control" id="customerMobile" placeholder="Mobile Number" name="mobile" [(ngModel)]="customer && customer.Mobile.FreeFormNumber" >
</div>
</div>
<div class="col-md-6">
<h3>Address:</h3>
<div class="form-group">
<label for="customerLine1">Line 1</label>
<input type="text" class="form-control" id="cutomerLine1" placeholder="Line 1" name="line1" [(ngModel)]="customer && customer.BillAddr.Line1" >
</div>
<div class="form-group">
<label for="customerLine1">Line 2</label>
<input type="text" class="form-control" id="cutomerLine2" placeholder="Password" name="line2" [(ngModel)]="customer && customer.BillAddr.Line2" >
</div>
<div class="form-group">
<label for="customerLine1">Line 3</label>
<input type="text" class="form-control" id="cutomerLine3" placeholder="Password" name="line3" [(ngModel)]="customer && customer.BillAddr.Line3" >
</div>
<div class="form-group">
<label for="customerCity">City</label>
<input type="text" class="form-control" id="customerCity" placeholder="Password" name="city" [(ngModel)]="customer && customer.BillAddr.City" >
</div><div class="form-group">
<label for="customerLine1">State/Province</label>
<input type="text" class="form-control" id="cutomerLine1" placeholder="Password" name="Province" [(ngModel)]="customer && customer.BillAddr.CountrySubDivisionCode" >
</div>
<div class="form-group">
<label for="customerLine1">Postal Code</label>
<input type="text" class="form-control" id="cutomerLine1" placeholder="Password" name="postcode" [(ngModel)]="customer && customer.BillAddr.PostalCode" >
</div>
</div>
</div>
<button type="submit" class="btn btn-default">Save Changes</button>
</form>
The current details are fetched oninit with this function:
getCustomer(id): void {
this.busy = this.customersService.getCustomer(id)
.then(customer => this.customer = customer);
}
First problem is that data is coming async, so customer will be undefined when the view is rendered on all fields. Second problem is indeed that, since some fields do not have a value, will also throw an error.
Usually this could be solved by just initializing the customer:
customer = {};
But here again the problem is, that you have some deeper property paths that will though throw error despite this, like: customer.BillAddr.Line3. Of course you could initialize aaaall properties you have in your object, but that seems just ugly to me.
All this can be solved with the safe navigation operator. Unfortunately two-way-binding, i.e [(ngModel)] does not allow the safe navigation operator.
But!
[(ngModel)]="something" equals the following:
[ngModel]="something" (ngModelChange)="changeHappened($event)"
and one-way-binding does support the safe navigation operator. So what you could then do, is to use the ternary operator, that catches the input user makes and assigns it to your variable (in this example) with customer.Title = $event. And by using the ternary operator you get rid of the error undefined if there is no value initially with applying an empty string to the field:
[ngModel]="customer?.Title"
(ngModelChange)="customer?.Title ? customer.Title = $event : ''"
(All credit goes to this answer: https://stackoverflow.com/a/36016472/6294072)
Also I could suggest to use a model-driven form here where you could set all fields as empty initially and then just set values to the fields that have value and get rid of the ngModel. Just to throw in a second option.
But all in all, the above solution should get rid of your errors! :)

Form is submitting and redirecting without information

I'm really terrible with forms, so any help you can provide would be great.
This form initially had a modal that came up on submission, but I had to change it to a redirect. Now it's redirect without any data being entered.
<form id="contact-form" method="post" onsubmit="return redirect()">
<div class="contact-form-loader"></div>
<fieldset>
<div class="contact-form_top-section">
<label class="name">
<input type="text" name="name" placeholder="Parent's Name:" value="" data-constraints="#Required #JustLetters">
<span class="empty-message">*This field is required.</span>
<span class="error-message">*This is not a valid name.</span>
</label>
<label class="email">
<input type="text" name="email" placeholder="Parent's E-mail:" value="" data-constraints="#Required #Email">
<span class="empty-message">*This field is required.</span>
<span class="error-message">*This is not a valid email.</span>
</label>
<label class="phone">
<input type="text" name="phone" placeholder="Parent's Cellphone:" value="" data-constraints="#JustNumbers">
<span class="empty-message">*This field is required.</span>
<span class="error-message">*This is not a valid phone.</span>
</label>
<label class="message">
<input type="text" name="message" placeholder="Tell us about your children:" value="" data-constraints="#Required">
<span class="empty-message">*This field is required.</span>
<span class="error-message">*The message is too short.</span>
</label>
</div>
<div class="contact-form_bottom-section">
Clear
<input type="submit" class="btn btn__hover bg-color-6" value="Send">
</div>
</fieldset>
The .js page has a ton of data, and I'm not exactly sure which part you need. Here's the first part.
;(function($){
$.fn.TMForm=function(opt){
return this.each(TMForm)
function TMForm(){
var form=$(this)
opt=$.extend({
okClass:'ok'
,emptyClass:'empty'
,invalidClass:'invalid'
,successClass:'success'
,responseErrorClass:'response-error'
,responseMessageClass:'response-message'
,processingClass:'processing'
,onceVerifiedClass:'once-verified'
,mailHandlerURL:'bat/MailHandler.php'
,successShowDelay:'4000'
,stripHTML:true
,recaptchaPublicKey:''
,capchaTheme:'clean'
},opt)
init()
function init(){
form
.on('submit',formSubmit)
.on('reset',formReset)
.on('focus','[data-constraints]',function(){
$(this).parents('label').removeClass(opt.emptyClass)
})
.on('blur','[data-constraints]:not(.once-verified)',function(){
$(this)
.addClass(opt.onceVerifiedClass)
.trigger('validate.form')
})
.on('keyup','[data-constraints].once-verified',function(){
$(this).trigger('validate.form')
})
.on('keydown','input',function(e){
var $this=$(this)
,next=$this.parents('label').next('label').find('input,textarea')
if(e.keyCode===13)
if(next.length)
next.focus()
else
form.submit()
})
.on('keydown','textarea',function(e){
if(e.keyCode===13&&e.ctrlKey)
$(this).parents('label').next('label').find('input,textarea').focus()
})
.on('change','input[type="file"]',function(){
$(this).parents('label').next('label').find('input,textarea').focus()
})
.attr({
method:'POST'
,action:opt.mailHandlerURL
})
Your best bet is to put the redirect function at the end of the formSubmit function which should be somewhere in your JS file. By doing what you did your form never gets to hit the 'formSubmit' function which I assume handles the data.

Can you require two form fields to match with HTML5?

Is there a way to require the entries in two form fields to match using HTML? Or does this still have to be done with JavaScript? For example, if you have two password fields and want to make sure that a user has entered the same data in each field, are there some attributes, or other coding that can be done, to achieve this?
Not exactly with HTML validation but a little JavaScript can resolve the issue, follow the example below:
function check() {
var input = document.getElementById('password_confirm');
if (input.value != document.getElementById('password').value) {
input.setCustomValidity('Password Must be Matching.');
} else {
// input is valid -- reset the error message
input.setCustomValidity('');
}
}
<p>
<label for="password">Password:</label>
<input name="password" required="required" type="password" id="password" oninput="check()"/>
</p>
<p>
<label for="password_confirm">Confirm Password:</label>
<input name="password_confirm" required="required" type="password" id="password_confirm" oninput="check()"/>
</p>
<input type="submit" />
You can with regular expressions Input Patterns (check browser compatibility)
<input id="password" name="password" type="password" pattern="^\S{6,}$" onchange="this.setCustomValidity(this.validity.patternMismatch ? 'Must have at least 6 characters' : ''); if(this.checkValidity()) form.password_two.pattern = this.value;" placeholder="Password" required>
<input id="password_two" name="password_two" type="password" pattern="^\S{6,}$" onchange="this.setCustomValidity(this.validity.patternMismatch ? 'Please enter the same Password as above' : '');" placeholder="Verify Password" required>
A simple solution with minimal javascript is to use the html attribute pattern (supported by most modern browsers). This works by setting the pattern of the second field to the value of the first field.
Unfortunately, you also need to escape the regex, for which no standard function exists.
<form>
<input type="text" oninput="form.confirm.pattern = escapeRegExp(this.value)">
<input name="confirm" pattern="" title="Fields must match" required>
</form>
<script>
function escapeRegExp(str) {
return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
}
</script>
JavaScript will be required, but the amount of code can be kept to a minimum by using an intermediary <output> element and an oninput form handler to perform the comparison (patterns and validation could augment this solution, but aren't shown here for sake of simplicity):
<form oninput="result.value=!!p2.value&&(p1.value==p2.value)?'Match!':'Nope!'">
<input type="password" name="p1" value="" required />
<input type="password" name="p2" value="" required />
<output name="result"></output>
</form>
Not only HTML but a bit of JavaScript
HTML
<form class="pure-form">
<fieldset>
<legend>Confirm password with HTML5</legend>
<input type="password" placeholder="Password" id="password" required>
<input type="password" placeholder="Confirm Password" id="confirm_password" required>
<button type="submit" class="pure-button pure-button-primary">Confirm</button>
</fieldset>
</form>
JavaScript
var password = document.getElementById("password")
, confirm_password = document.getElementById("confirm_password");
function validatePassword(){
confirm_password.setCustomValidity( password.value !=
confirm_password.value ? "Passwords Don't Match" : '');
}
password.onchange = validatePassword;
confirm_password.onkeyup = validatePassword;
CodePen Demo
As has been mentioned in other answers, there is no pure HTML way to do this.
If you are already using JQuery, then this should do what you need:
$(document).ready(function() {
$('#ourForm').submit(function(e){
var form = this;
e.preventDefault();
// Check Passwords are the same
if( $('#pass1').val()==$('#pass2').val() ) {
// Submit Form
alert('Passwords Match, submitting form');
form.submit();
} else {
// Complain bitterly
alert('Password Mismatch');
return false;
}
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form id="ourForm">
<input type="password" name="password" id="pass1" placeholder="Password" required>
<input type="password" name="password" id="pass2" placeholder="Repeat Password" required>
<input type="submit" value="Go">
</form>
<div className="form-group">
<label htmlFor="password">Password</label>
<input
value={password}
onChange={(e) => { setPassword(e.target.value) }}
type="password" id='password' name="password" required minLength={3} maxLength={255} />
</div>
<div className="form-group">
<label htmlFor="confirmPassword">Confirm Password</label>
<input
title='Passwords should be match'
pattern={`${password}`}
value={confirmPassword}
onChange={(e) => { setConfirmPassword(e.target.value) }}
type="password" id='confirmPassword' name="confirmPassword" required minLength={3} maxLength={255} />
</div>