Can I conditionally render in EJS based on the existence of a variable? - ejs

I'm writing the template for a form. On the GET request to the form, it's supposed to render an empty input field (since it's a "blank" form), but if called from a POST request it's supposed to render into the text input field the (invalid) value which had been entered by the user.
I typed:
<% if (genre) { %>
<input type="text" id="name" class="form-control" placeholder="Fantasy, Poetry, etc." name="name" value="<%= genre.name %>" />
<% } else { %>
<input type="text" id="name" class="form-control" placeholder="Fantasy, Poetry, etc." name="name" value="" />
<% } %>
The issue is that when I pull up the page using a GET request, I'm getting the following error:
ReferenceError: /home/mrd2689a/Documents/the_odin_project/express-locallibrary-tutorial/views/genre_form.ejs:13
11| <div class="form-group">
12| <label for="name">Genre:</label>
>> 13| <% if (genre) { %>
14| <input type="text" id="name" class="form-control" placeholder="Fantasy,
15| Poetry, etc." name="name" value="<%= genre.name %>" />
16| <% } else { %>
genre is not defined
Does anybody know in EJS how I can conditionally render based on the existence of a variable?

Just found out that if I check for (locals.genre) instead of genre, it works as expected.

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.

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>

On CodeIgniter, how to repopulate a form only with correct values?

Imagine a form like this:
<form action="test.php" method="post">
<input type="text" name="firstname" value="<?=set_value('firstname')?>" />
<input type="text" name="lastname" value="<?=set_value('lastname')?>" />
<input type="text" name="email" value="<?=set_value('email')?>" />
<input type="submit" name="submit_form" value="OK" />
</form>
If I submit an incorrect email, the CodeIgniter function will write "the field is not valid" and populate the invalid field with the wrong value.
I would like to keep the error message but not the wrong value (I prefer having an empty value). But I also want to keep the re-populating function for correct values.
Here is what I get:
Here is what I want:
[EDIT] SOLUTION FOUND (thanks to Herr Kaleun and Matt Moore)
Example with the email field:
<input type="text" name="email" id="email" value="<?=!form_error('email')?set_value('email'):''?>" />
You can check the fields individually and have a logic like this.
If the error for a specific field is present, you can build a logic on top of that.
if ( form_error('email') != '' )
{
$data['email_value'] = '';
}
else
{
$data['email_value'] = set_value('email');
}
<form action="test.php" method="post">
<input type="text" name="firstname" value="<?=set_value('firstname')?>" />
<input type="text" name="lastname" value="<?=set_value('lastname')?>" />
<input type="text" name="email" value="<?= $email_value; ?>" />
<input type="submit" name="submit_form" value="OK" />
</form>
The Form_error is set when a form value errors out based on the validation. Judging by your use of the set_value function I assume you're using the built in form validation. You can check to see if the message for that field is set if(form_error('fieldname') !=NULL) and set the value based on that.
You may have to setup error messages for each field, which you should be doing anyway. Here is the guide that covers it: http://codeigniter.com/user_guide/libraries/form_validation.html#repopulatingform
<form action="test.php" method="post">
<input type="text" name="firstname" value="<?if(form_error('firstname') != NULL){echo set_value('firstname');}?>" />
<input type="text" name="lastname" value="<?if(form_error('lastname') != NULL){ echo set_value('lastname');}?>" />
<input type="text" name="email" value="<?if(form_error('email') !=NULL){ echo set_value('email');}?>" />
<input type="submit" name="submit_form" value="OK" />
</form>
*NOTE THIS CODE HAS NOT BEEN TESTED *

html / iphone - getting a form alert when attempting to refresh the page

I'm building a site which has a form but for some reason, even if a user doesn't enter info into the form (even if the form hasn't been presented yet - it starts out hidden) - if I refresh the page, iOS gives me a browser alert stating:
are you sure you want to submit this form again?
Any idea why this happens or how to suppress that?
This is my form code:
<div id="vehicle_form">
<form method="post" name="emailForm">
<input class="dField" id="dfEmail" type="email" name="email" value="Email"/><br/>
<input class="dField" id="dfName" type="text" name="firstname" value="First Name"/><br/>
<input class="dField" id="dfLast" type="text" name="lastname" value="Last Name"/><br/>
<input class="dField" id="dfZip" type="text" maxlength="5" name="zip" value="Zip Code"/><br/>
<button id="dFormBack">Back</button><button type="submit" id="dSubmit">Submit</button>
</form>
<div id="dErrors"></div>
</div>
I also have this javascript acting on the form fields:
$j('.dField').focus(function(){
clearInput($j(this)[0]); //The [0] seems to be necessary to retrieve the element at the DOM object level
}).blur(function(){
restoreInput($j(this)[0]);
});
as well as some other form related javascript.
Not sure if this is exactly what you're looking for, but try this:
<form method="post" name="emailForm">
<input type="text" name="email" value="Email" size="30" onfocus="value=''"><br>
<input type="text" name="firstname" value="First Name" size="30" onfocus="value=''"><br>
<input type="text" name="lastname" value="Last Name" size="30" onfocus="value=''"><br>
<input type="text" name="zipcode" value="Zip Code" size="30" onfocus="value=''"><br>
<button id="dFormBack">Back</button><button type="submit" id="dSubmit">Submit</button>
</form>