Display error if no checkbox is checked in checkbox group - zurb-foundation

How do I display an error message with Foundation 5's Abide HTML5 form validation library when no checkboxes are checked within the same checkbox group?

You have to write your own abide validator, but it is quite simple.
Working example: CodePen link
JavaScript
$(document).foundation({
abide: {
validators: {
checkbox_limit: function(el, required, parent) {
var group = parent.closest('.checkbox-group');
var min = group.attr('data-abide-validator-min');
var checked = group.find(':checked').length;
if (checked >= min) {
group.find('small.error').hide();
return true;
} else {
group.find('small.error').css({
display: 'block'
});
return false;
}
}
}
}
});
HTML
<form data-abide>
<div class="row">
<div class="small-12 column">
<h4>Select your favourite vehicles</h4>
</div>
</div>
<div class="row">
<div class="small-12 columns checkbox-group" data-abide-validator-min="1">
<label>
<input type="checkbox" data-abide-validator="checkbox_limit" value="car" />
car
</label>
<label>
<input type="checkbox" data-abide-validator="checkbox_limit" value="train" />
train
</label>
<label>
<input type="checkbox" data-abide-validator="checkbox_limit" value="bicycle" />
bicycle
</label>
<label>
<input type="checkbox" data-abide-validator="checkbox_limit" value="ferry" />
ferry
</label>
<label>
<input type="checkbox" data-abide-validator="checkbox_limit" value="plane" />
plane
</label>
<small class="error">You have to check at least one vehicle.</small>
</div>
</div>
<div class="row">
<div class="small-12 columns">
<button type="submit">Submit</button>
</div>
</div>
</form>

Related

'stripeToken' error when attempting to submit payment form

I'm following an outdate django e-commerce course using django and stripe. The course is about 4 years old so a lot has changed with django and stripe, which has allowed me to do a ton of research on both. I'm at the end of the tutorial and have run into an issue while creating the checkout page and more importantly using stripe to 'Create Charge'. I am receiving the following error message:
django.utils.datastructures.MultiValueDictKeyError
django.utils.datastructures.MultiValueDictKeyError: 'stripeToken'
I read in the documentation for Creating Charge which states
token = request.POST['stripeToken'] # Using Flask
is for Flask (I think), however when i remove ['stripeToken'], I receive this error message:
stripe.error.InvalidRequestError stripe.error.InvalidRequestError:
Request req_kikB88HKbEkq9W: Could not find payment information
I need a way to pass Stripe the payment information when the form is submitted. Also, I came across this post but the publisher was receiving error message do to multiple forms
view.py
from django.conf import settings
from django.contrib.auth.decorators import login_required
from django.shortcuts import render
import stripe
stripe.api_key = settings.STRIPE_SECRET_KEY
# Create your views here.
#login_required
def checkout(request):
publish_key = settings.STRIPE_PUBLISHABLE_KEY
if request.method == 'POST':
token = request.POST['stripeToken']
stripe.Charge.create(
amount=999,
currency='usd',
description='Example charge',
source=token,
statement_descriptor='Custom descriptor',
)
context = {'publish_key': publish_key}
template = 'checkout.html'
return render(request, template, context)
checkout.html
{% extends 'base.html' %}
{% block content %}
<div class="col-sm-6 offset-md-3">
<h4 class="mb-3">Billing address</h4>
<form id="payment-form" action="" method="post">{% csrf_token %}
<div class="row">
<div class="col-md-6 mb-3">
<label for="firstName">First name</label>
<input type="text" class="form-control" id="firstName" required style="background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABHklEQVQ4EaVTO26DQBD1ohQWaS2lg9JybZ+AK7hNwx2oIoVf4UPQ0Lj1FdKktevIpel8AKNUkDcWMxpgSaIEaTVv3sx7uztiTdu2s/98DywOw3Dued4Who/M2aIx5lZV1aEsy0+qiwHELyi+Ytl0PQ69SxAxkWIA4RMRTdNsKE59juMcuZd6xIAFeZ6fGCdJ8kY4y7KAuTRNGd7jyEBXsdOPE3a0QGPsniOnnYMO67LgSQN9T41F2QGrQRRFCwyzoIF2qyBuKKbcOgPXdVeY9rMWgNsjf9ccYesJhk3f5dYT1HX9gR0LLQR30TnjkUEcx2uIuS4RnI+aj6sJR0AM8AaumPaM/rRehyWhXqbFAA9kh3/8/NvHxAYGAsZ/il8IalkCLBfNVAAAAABJRU5ErkJggg=="); background-repeat: no-repeat; background-attachment: scroll; background-size: 16px 18px; background-position: 98% 50%;" required/>
<div class="invalid-feedback">
Valid first name is required.
</div>
</div>
<div class="col-md-6 mb-3">
<label for="lastName">Last name</label>
<input type="text" class="form-control" id="lastName" required />
<div class="invalid-feedback">
Valid last name is required.
</div>
</div>
</div>
<div class="mb-3">
<label for="email">Email <span class="text-muted"></span></label>
<input type="email" class="form-control" id="email" placeholder="you#example.com" required />
<div class="invalid-feedback">
Please enter a valid email address for shipping updates.
</div>
</div>
<div class="mb-3">
<label for="address">Address</label>
<input type="text" class="form-control" id="address" placeholder="1234 Main St" required />
<div class="invalid-feedback">
Please enter your shipping address.
</div>
</div>
<div class="mb-3">
<label for="address2">Address 2 <span class="text-muted"></span></label>
<input type="text" class="form-control" id="address2" placeholder="Apartment or suite" />
</div>
<div class="row">
<div class="col-md-5 mb-3">
<label for="city">City</label>
<input type="text" class="form-control" id="city" required />
<div class="invalid-feedback">
Zip code required.
</div>
</div>
<div class="col-md-4 mb-3">
<label for="state">State</label>
<select class="custom-select d-block w-100" id="state" required>
<option value="">Choose...</option>
<option>California</option>
</select>
<div class="invalid-feedback">
Please provide a valid state.
</div>
</div>
<div class="col-md-3 mb-3">
<label for="zip">Zip</label>
<input type="text" class="form-control" id="zip" required />
<div class="invalid-feedback">
Zip code required.
</div>
</div>
</div>
<hr class="mb-4">
<div class="custom-control custom-checkbox">
<input type="checkbox" class="custom-control-input" id="same-address">
<label class="custom-control-label" for="same-address">Shipping address is the same as my billing address</label>
</div>
<div class="custom-control custom-checkbox">
<input type="checkbox" class="custom-control-input" id="save-info">
<label class="custom-control-label" for="save-info">Save this information for next time</label>
</div>
<hr class="mb-4">
<h4 class="mb-3">Payment</h4>
<div class="d-block my-3">
<label for="card-element">Credit or debit card</label>
<div id="card-element" class="form-control" style='height: 2.4em; padding-top: .7em;'>
<!-- A Stripe Element will be inserted here. -->
</div>
<!-- Used to display form errors. -->
<div id="card-errors" role="alert"></div>
</div>
<hr class="mb-4">
<button class="btn btn-outline-success btn-lg btn-block" type="submit">Continue to checkout</button>
</form>
</div>
{% endblock %}
app.js
// Create a Stripe client.
const stripe = Stripe('{{ publish_key }}');
// Create an instance of Elements.
const elements = stripe.elements();
// Create an instance of the card Element.
const card = elements.create('card', {});
// Add an instance of the card Element into the `card-element` <div>.
card.mount('#card-element');
// Handle real-time validation errors from the card Element.
card.addEventListener('change', ({error}) => {
const displayError = document.getElementById('card-errors');
if (error) {
displayError.textContent = error.message;
} else {
displayError.textContent = '';
}
});
// Create a token or display an error when the form is submitted.
const form = document.getElementById('payment-form');
form.addEventListener('submit', async (event) => {
event.preventDefault();
const {token, error} = await stripe.createToken(card);
if (error) {
// Inform the customer that there was an error.
const errorElement = document.getElementById('card-errors');
errorElement.textContent = error.message;
} else {
// Send the token to your server.
stripeTokenHandler(token);
}
});
// Submit the form with the token ID.
const stripeTokenHandler = (token) => {
// Insert the token ID into the form so it gets submitted to the server
const form = document.getElementById('payment-form'),
hiddenInput = document.createElement('input');
hiddenInput.setAttribute('type', 'hidden');
hiddenInput.setAttribute('name', 'stripeToken');
hiddenInput.setAttribute('value', token.id);
form.appendChild(hiddenInput);
// Submit the form
form.submit();
}

Django image upload with js plugin issue

I am using js plugin to upload image, first time when i select image from the plugin the form gets submitted. The issue is that i select the image first time but then i don't want that image and i click on it again to upload another image, the form does not get validated and fails to submit.
views.py
class SelectObituaryView(LoginRequiredMixin, TemplateView):
template_name = "website/obituary_select.html"
def get_context_data(self, **kwargs):
context = super(SelectObituaryView, self).get_context_data(**kwargs)
church_id = self.request.session.get('church_id', None)
if church_id:
samples = ObituarySample.objects.filter(organization__id=church_id)
context['obituary_samples'] = samples
context['church_cover'] = self.request.session.get('church_cover', None)
return context
#transaction.atomic
def post(self, request):
print("Entered function")
try:
data = request.POST.copy()
data['organization'] = request.session.get('church_id', None)
data['slug'] = data['name'].replace(' ', '-')
data['funeral_time'] = data['funeral_time'].replace(" ", "")
data['viewing_time'] = data['viewing_time'].replace(" ", "")
if len(request.FILES.getlist('gallery')) > 10:
messages.error(request, "Max gallery images limit exceeded.")
return HttpResponseRedirect(
reverse('obituary:create', kwargs={'sample_obituary_id': request.POST.get('obituary_sample')}))
obituary_form = ObituaryForm(data=data, files=request.FILES)
# print("obituary form data",data)
print("before is valid")
if obituary_form.is_valid():
print("Inside is_valid")
obituary_instance = obituary_form.save(commit=False)
obituary_instance.image = obituary_instance.obituary_sample.background
obituary_instance.user = request.user
obituary_instance.save()
obituary_instance.update_slug_with_id()
#override profile_image
#imageName = os.path.basename(obituary_instance.profile_image.path)
imgArr = os.path.split(obituary_instance.profile_image.path)
image_data = request.POST['profile_image1']
b = json.loads(image_data)
head, data = b["output"]["image"].split(',')
binary_data = a2b_base64(data)
print(binary_data)
with open(obituary_instance.profile_image.path, 'wb+') as fh:
myfile = File(fh)
myfile.write(binary_data)
imprinted_image_path = apps.obituary.utils.imprint(obituary_instance, obituary_instance.obituary_sample)
# Save imprinted image in db
with open(imprinted_image_path, 'rb') as f:
data = f.read()
file_postfix = datetime.now().strftime("%Y%m%d-%H%M%S")
obituary_instance.image.save("%s%s.jpg" % ('obituary', file_postfix), ContentFile(data))
for gallery_image in request.FILES.getlist('gallery'):
GalleryImage.objects.create(obituary=obituary_instance, image=gallery_image)
return HttpResponseRedirect(reverse('obituary:preview', kwargs={'obituary_id': obituary_instance.id}))
else:
print("else")
messages.error(request, constants.OPERATION_UNSUCCESSFUL)
return HttpResponseRedirect(
reverse('obituary:create', kwargs={'sample_obituary_id': request.POST.get('obituary_sample')}))
except Exception as e:
print(e)
print("except")
messages.error(request, "Unable to create, Please try again.")
return HttpResponseRedirect(
reverse('obituary:create', kwargs={'sample_obituary_id': request.POST.get('obituary_sample')}))
html
{% extends "website/base.html" %}
{% load static %}
{% block javascript %}
<script>
// Submit post on submit
{# $('#create_obit').on('submit', function(event){#}
{# event.preventDefault();#}
{# alert("Aamixsh");#}
{# });#}
$("#create_obit").submit(function(evt){
//evt.preventDefault();
if($(this).find('input[name="profile_image"]').val() != "") {
$(this).find('input[name="profile_image"]').attr('name','profile_image1');
$(this).find(".slim").find('input[type="file"]').attr('name','profile_image');
return true;
}
});
$(document).ready(function(){
$('input[type="text"]').attr( 'autocomplete', 'off' );
$('.dateReadonly').attr( 'readonly', 'true' );
});
</script>
{% endblock %}
{% block body_block %}
<!-- Banner Area Start -->
<div class="banner-area">
<div class="overlay"></div>
<div class="img-holder">
<div class="holder"><img src="{{ church_cover }}" alt=""></div>
</div>
<div class="caption">
<div class="holder">
<div class="container">
<div class="row">
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
<div class="banner">
<h2>Fill in Loved Ones Details</h2>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="section-space">
<div class="container">
<div class="row">
<div class="col-xs-12">
<div class="row">
<h3 class="heading-title">Create an Obituary</h3>
<form class="setting-form" id="create_obit" action="{% url 'obituary:select' %}" method="post" enctype="multipart/form-data">
{% csrf_token %}
<fieldset>
<div class="col-xs-12">
<div class="row">
<div class="col-sm-6">
<div class="form-group">
Name: <input type="text" maxlength="50" name="name" placeholder="Name*" class="form-control input-field" required>
</div>
</div>
<div class="col-sm-6">
<div class="form-group">
Funeral Address: <input type="text" maxlength="50" name="address" placeholder="Funeral Address*" class="form-control input-field" required>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-6">
<div class="form-group">
Date of Birth: <input type="text" id="datepicker1" name="date_of_birth" placeholder="Date of Birth*" class="dateReadonly form-control input-field" required>
</div>
</div>
<div class="col-sm-6">
<div class="form-group">
Date of Death: <input type="text" id="datepicker2" name="date_of_death" placeholder="Date of Death*" class="dateReadonly form-control input-field" required>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-6">
<div class="form-group">
Funeral Date: <input type="text" name="funeral_date" id="datepicker3" placeholder="Funeral Date*" class="dateReadonly form-control input-field" required>
</div>
</div>
<div class="col-sm-6">
<div class="form-group">
Funeral Time: <input type="text" name="funeral_time" id="timepicker" placeholder="Funeral Time*" class="form-control input-field" required>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-6">
<div class="form-group">
Surviving Family: <input type="text" maxlength="100" name="family_info" placeholder="spouse Mary Louise, and sons Joe, Ed, and Tim, etc. (Max Limit: 100 Characters)" class="form-control input-field" required>
</div>
</div>
<div class="col-sm-6">
<div class="form-group">
Ways To Contribute: <input type="text" maxlength="40" name="memorial_donation_info" placeholder="e.g. Donation url or other Information* (Max Limit: 40 Characters)" class="form-control input-field" >
</div>
</div>
</div>
<div class="row">
<div class="col-sm-6">
<div class="form-group">
Viewing Date: <input type="text" name="viewing_date" id="datepicker4" placeholder="Viewing Date*" class="dateReadonly form-control input-field" required>
</div>
</div>
<div class="col-sm-6">
<div class="form-group">
Viewing Time: <input type="text" name="viewing_time" id="timepicker2" placeholder="Viewing Time*" class="form-control input-field" required>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-6">
<div class="form-group">
Viewing Address: <input type="text" maxlength="50" name="viewing_address" placeholder="Viewing Address*" class="form-control input-field" required>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12">
<div class="form-group">
Message: <textarea maxlength="500" name="message" id="" cols="30" rows="10" class="form-control input-field" placeholder="Message* (Max Limit: 500 Characters)" required></textarea>
</div>
</div>
</div>
<input type="hidden" name="obituary_sample" value="{{ obituary_form.obituary_sample.value }}" />
</div>
<div class="col-sm-12">
<h3>Upload Obituary Photo</h3>
<div class = "form-group">
Maximum image size is 8 MB. You can rotate and crop the uploaded image by using the control buttons at the bottom of the image.
<!-- original <input type="file" name="profile_image" placeholder="Obituary Image*" class="form-control input-field" required> -->
<input type="file" name="profile_image" placeholder="Obituary Image*" class="slim" required>
</div>
</div>
<div class="col-xs-12">
<h3>Upload Gallery Photos</h3>
<div class="dropzone" id="my-awesome-dropzone">
<div class="fallback">
(Maximum image size should be 8 MB)
<input type="file" name="gallery" multiple class="form-control input-field"/>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12">
<div class="form-group">
<input type="checkbox" onchange="document.getElementById('create').disabled = !this.checked;" /> I understand, that the obituary cannot be edited once paid for!
</div>
</div>
</div>
<div class="col-xs-12">
<div class="form-group">
<button type="submit" id="create" class="btn send-btn" disabled>Create</button>
</div>
</div>
</fieldset>
</form>
</div>
</div>
</div>
</div>
</div>
{% endblock %}

Ember js hasmany relationship saving data

I have two models in Ember where one is a collection and the other is book. Collection model has a "hasMany" relationship with "book" and "book" "belongsTo" "collection". So what i want to do is have a form with both models in and store them at the same time.
Collection Model
// collection Model
export default DS.Model.extend({
name: DS.attr('string'),
city: DS.attr('string'),
books: DS.hasMany('book', { async: true })
});
The book model
//book Model
export default DS.Model.extend({
title: DS.attr('string'),
description: DS.attr('string'),
collection: DS.belongsTo('collection', {async: true})
});
The form
//Collection View
<div class="row">
<div class="col-sm-12">
<div class='panel panel-default'>
<div class='panel-body'>
<form>
<fieldset>
<legend>
Collection
</legend>
<div class="row">
<div class="col-sm-6">
<label for="name" class="col-sm-2">Name</label>
<div class="col-sm-10">
{{input id="name" type="text" class="form-control" value=collection.name}}
</div>
</div>
<div class="col-sm-6">
<label for="city" class="col-sm-2">city</label>
<div class="col-sm-10">
{{input id="city" type="text" class="form-control" value=collection.city}}
</div>
</div>
</div>
</fieldset>
<fieldset>
<legend>
books
</legend>
<div class="row">
<div class="col-sm-6">
<label for="title1" class="col-sm-2">title</label>
<div class="col-sm-10">
{{input id="title1" type="text" class="form-control" value=book.title1}}
</div>
</div>
<div class="col-sm-6">
<label for="description1" class="col-sm-2">description</label>
<div class="col-sm-10">
{{input id="description1" type="text" class="form-control" value=book.description1}}
</div>
</div>
</div>
<div class="row">
<div class="col-sm-6">
<label for="title2" class="col-sm-2">title</label>
<div class="col-sm-10">
{{input id="title2" type="text" class="form-control" value=book.title2}}
</div>
</div>
<div class="col-sm-6">
<label for="description2" class="col-sm-2">description</label>
<div class="col-sm-10">
{{input id="description2" type="text" class="form-control" value=book.description2}}
</div>
</div>
</div>
</fieldset>
<div class="row">
<div class="col-sm-12">
<button {{action 'addCollection'}} class="btn btn-primary">New Collection</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
The controller:
actions:{
addCollection: function(){
var name = this.get('collection.name');
var city = this.get('collection.city');
var title1 = this.get('book.title1');
var description1 = this.get('book.description1');
var title2 = this.get('book.title2');
var description2 = this.get('book.description2');
var newCollection = this.store.createRecord('collection', {
name: name,
city: city,
});
},
As you can see I'm trying to obtain 2 sets of books for this collection, but I'm having trouble on finding the correct procedure to store items to these models. I guess I may have to store the collection model first and then push the individual books to the collection. Is this correct? How would I go about it?
If the book is a record already you can simply push it onto the new collection. You don't don't need to assign anything to variables since your template is already bound to the record.
As an improvement I'd suggest creating the collection before the add as well. Either within your model, or on controller initiation.
So the action could be as simple as this.
actions:{
addCollection: function(){
// newCollection and Book need to be records
this.get("newCollection").pushObject(this.get('book'));
},
}
Note: the createRecord will not persist until you call .save() but you do not need to call .save() to create a relationship.
Forgive me for not noticing the multiple new books, here is a more pertinent example.
// template.hbs
<div class="row">
<div class="col-sm-12">
<div class='panel panel-default'>
<div class='panel-body'>
<form>
<fieldset>
<legend>
Collection
</legend>
<div class="row">
<div class="col-sm-6">
<label for="name" class="col-sm-2">Name</label>
<div class="col-sm-10">
{{input id="name" type="text" class="form-control" value=model.newCollection.name}}
</div>
</div>
<div class="col-sm-6">
<label for="city" class="col-sm-2">city</label>
<div class="col-sm-10">
{{input id="city" type="text" class="form-control" value=model.newCollection.city}}
</div>
</div>
</div>
</fieldset>
<fieldset>
<legend>
books
</legend>
<div class="row">
<div class="col-sm-6">
<label for="title1" class="col-sm-2">title</label>
<div class="col-sm-10">
{{input id="title1" type="text" class="form-control" value=model.book1.title}}
</div>
</div>
<div class="col-sm-6">
<label for="description1" class="col-sm-2">description</label>
<div class="col-sm-10">
{{input id="description1" type="text" class="form-control" value=model.book1.description}}
</div>
</div>
</div>
<div class="row">
<div class="col-sm-6">
<label for="title2" class="col-sm-2">title</label>
<div class="col-sm-10">
{{input id="title2" type="text" class="form-control" value=model.book2.title}}
</div>
</div>
<div class="col-sm-6">
<label for="description2" class="col-sm-2">description</label>
<div class="col-sm-10">
{{input id="description2" type="text" class="form-control" value=model.book2.description}}
</div>
</div>
</div>
</fieldset>
<div class="row">
<div class="col-sm-12">
<button {{action 'addCollection' model}} class="btn btn-primary">New Collection</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
// route.js
model () {
return Ember.RSVP.hash({
newCollection: this.get('store').createRecord('collection'),
book1: this.get('store').createRecord('book'),
book2: this.get('store').createRecord('book')
})
}
// controller.js
actions:{
addCollection(model) {
model.newCollection.pushObject(model.book1);
model.newCollection.pushObject(model.book2);
},
}
Notice I've used the model to create the records before hand and it's being passed into the action. You still may need to save for these changes to persist.

Angular2 form validation with pattern

I'm trying to user the pattern attribute for email in Angular 4.3.0 but the field.errors.pattern returns true even when the email is correct.
I'm working on an existing code and this pattern was used in this.I'm also not able to understand the RegEx.
Below is the HTML form
<form #loginform="ngForm" class="form-horizontal b bg-white padding_default r-2x box-shadow" novalidate role="form">
<div class="text-danger wrapper text-center" *ngIf="authError">
</div>
<div class="animated fadeIn">
<div class=" m-b-md no-border ">
<input id="username" type="email" class="form-control input-lg b text-md" name="username" placeholder="Email" [(ngModel)]="loginData.email"
autofocus required #username="ngModel" pattern="emailPattern">
<div *ngIf="username.invalid && (username.dirty || username.touched)" class="alert alert-danger">
<div *ngIf="username.errors.required">
Name is required.
</div>
<div *ngIf="username.errors.pattern">
Name is invalid
</div>
</div>
<!--<div class="sxo_validate_msg text-danger text-sm" *ngIf="username.touched && isValidEmail">
<span>Invalid email address.</span>
</div>-->
</div>
<div class=" m-b-md no-border">
<input id="password" type="password" class="form-control input-lg b b-light text-md" name="password" [(ngModel)]="loginData.password"
placeholder="Password" required #password="ngModel">
<div class="text-danger sxo_validate_msg text-sm" *ngIf="password.dirty && password.invalid">
<span *ngIf="password.required">Password is required.</span>
</div>
</div>
<div class="m-b-md m-t-md">
<label class="i-checks text-sm">
<input name="rememberme" id="login-remember" type="checkbox" [(ngModel)]="loginData.rememberMe"><i></i> Remember me
</label>
</div>
<div class="controls m-t-md">
<div class="m-b-lg" *ngIf="showCaptche">
<re-captcha [site_key]="model.key" (captchaResponse)="setResponse($event)"></re-captcha>
<!--<div vc-recaptcha
theme="'light'"
key="model.key"
on-create="setWidgetId(widgetId)"
on-success="setResponse(response)"
on-expire="cbExpiration()"></div>-->
</div>
<input class="btn btn-lg btn-dark btn-block" value="Login" (click)="login()" [disabled]="!loginform.form.valid" />
<div [hidden]="!message" class="alert alert-danger sxo_validate_msg p-t-xs p-b-xs">
{{message}}
</div>
</div>
</div>
</form>
Below is the pattern
emailPattern:any = new RegExp(/^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))#((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/i);
I have encounter the same problem too and I don't know why regex seems not working in my Angular 4 project. I start using Validators in Angular's FormGroup and the email validation works like a charm in my project.
Here's my snippet of code for my Edit Profile Page (edit-profile.component.html):
<form [formGroup]="editProfileForm" class="form-horizontal" (ngSubmit)="EditProfile()" >
<div class="form-group">
<label for="email" class="col-md-4 control-label">E-Mail Address </label>
<div class="col-md-6">
<input id="email" type="email" class="form-control" formControlName="email" [(ngModel)]="user.email" required autofocus >
</div>
</div>
<span class="help-block">
<strong>{{ errors.email }}</strong>
</span>
<div class="form-group">
<div class="col-md-6 col-md-offset-4">
<button type="submit" class="btn btn-primary" [disabled]="editProfileForm.pristine">
Update
</button>
</div>
</div>
</form>
and in the edit-profile.component.ts file:
import { NgForm, FormGroup, FormBuilder, FormArray, FormControl, Validators } from '#angular/forms';
private errors = {
email: '',
};
public editProfileForm: FormGroup;
constructor(
private fb: FormBuilder,
) {
this.createForm();
}
createForm() {
// constructor + form Validator
this.editProfileForm = this.fb.group({
email: ['', Validators.compose([Validators.required, Validators.email])],
});
}
EditProfile() {
if (this.editProfileForm.invalid) {
if (this.editProfileForm.controls['email'].hasError('required')) {
this.errors.email = 'E-mail name cannot be empty';
} else if (this.editProfileForm.controls['email'].hasError('email')) {
this.errors.email = 'E-mail is not valid';
}
} else {
// submit the form
}
}
Hope this helps!
Angular 4 has a built-in email validation tag that can be added within the input. E.g.:
<input type="email" id="contactemail" email>
This will be valid for a series of numbers and letters then an # then
another series of letters. It will not account for the dot after the #
-- for that you can use the "pattern" tag within the input and your standard regex.
Or if you want to go with pattern try this
<input type="text" name="email" pattern="^\w+([\.-]?\w+)*#\w+([\.-]?\w+)*(\.\w{2,3})+$" required email/>
To understand/learn RegExp : https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/RegExp
The following should work:
emailPattern:any = new RegExp(/^(([^<>()\[\]\\.,;:\s#']+(\.[^<>()\[\]\\.,;:\s#']+)*)|('.+'))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/);

formvalidation.io validation issue with Bootsrap design

Let’s say if you have two fields in same row and one requires validation but other not when you trigger validation it shows validation error for other field too. For example, Below is my validation only on “Logged by name” but when I submit the form it throws for “Manager” field too. As soon as I enter something in “Logged by name” field it gets OK.
Here is my HTML,
<div id="Section_ObserverDetails">
<div class="col-sm-12">
<div class="row">
<div class="panel-body form-horizontal">
<div class="form-group">
<div class="col-sm-2">
<label for="pro_LoggedByName" class="col-sm-12 control-label">Logged by name</label>
</div>
<div class="col-sm-4">
<input type="text" class="form-control" id="pro_LoggedByName" name="pro_LoggedByName" value="" > </div>
<div class="col-sm-2">
<label for="top_Manager" class="col-sm-12 control-label">Manager</label>
</div>
<div class="col-sm-4" id="div-top-manager">
<div class="radio">
<label class="form-radio form-normal form-text form-success "><input type="radio" name="top_Manager" value="Yes">Yes</label><label class="form-radio form-normal form-text form-success active"><input type="radio" name="top_Manager" checked="checked" value="No">No</label>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
If I put class="form-group" tag for both the fields then problem gets resolve but "Manager" field slides down to the next row which I don't want.
Any idea ?
In your validation script code, set custom error selector e.g row: '.col-sm-4', so it will override the default error class .has-error .form-control and only target the selector which contains the required input field.
fields: {
pro_LoggedByName: {
row: '.col-sm-4', //<----This is custom error selector
validators: {
notEmpty: {
message: 'The city is required'
}
}
}
}
More Information & Reference
Fiddle