Bootstrap select2 in livewire keeps disappearing when I submit the form - laravel-livewire

I have a problem with my code the select2 is displaying only once when I refresh the page but it disappears when I submit the form or if there was a validation error it will disappear too. I tried wire:ignore The select2 doesn't disappear but it stops working properly and the form considered it like if it doesn't exist.
I use laravel 8, livewire 2 and turbolinks. Any help would be appreciated I've been stuck for almost 2 weeks.
Here is my code :
Blade:
<form wire:submit.prevent="submit">
{{ csrf_field() }}
<div class="form-group row">
<label for="to" class="col-form-label col-md-1">à :</label>
<div class="col-md-11" >
<select class="form-control mul-select" wire:model.lazy="id_to" name="id_to[]" multiple="multiple">
<option value="test#gmail.com">test#gmail.com</option>
<option value="test5#gmail.com">test5#gmail.com</option>
</select>
<div class="text-danger">
#error('id_to')
<span>
<strong>{{ $message }}</strong>
</span>
#enderror
</div>
</div>
</div>
<div class="form-group row">
<label for="cc" class="col-form-label col-md-1">Cc :</label>
<div class="col-md-11">
<input type="text" class="form-control" wire:model.lazy="cc" name="cc" placeholder="Cc">
<div class="text-danger">
#error('cc')
<span>
<strong>{{ $message }}</strong>
</span>
#enderror
</div>
</div>
</div>
<div class="form-group row">
<label for="sujet" class="col-form-label col-md-1">Sujet :</label>
<div class="col-md-11">
<input type="text" class="form-control" wire:model.lazy="sujet" name="sujet" placeholder="Sujet">
<div class="text-danger">
#error('sujet')
<span>
<strong>{{ $message }}</strong>
</span>
#enderror
</div>
</div>
</div>
<div class="form-group row">
<label for="message" class="col-form-label col-md-1">Message :</label>
<div class="col-md-11">
<textarea class="form-control" name="message" wire:model.lazy="message" rows="8"></textarea>
<div class="text-danger">
#error('message')
<span>
<strong>{{ $message }}</strong>
</span>
#enderror
</div>
</div>
</div>
{{-- <div class="email-editor">
<textarea class="form-control" id="summary-ckeditor" name="summary-ckeditor" wire:model.lazy="message"></textarea>
<div class="text-danger">
#error('message')
<span>
<strong>{{ $message }}</strong>
</span>
#enderror
</div>
</div> --}}
<div class="email-action mt-3">
<button class="btn btn-primary" type="submit">Envoyer</button>
<button class="btn btn-warning" wire:click="resetForm">Reset</button>
</div>
</form>
<script type="text/javascript">
document.addEventListener("livewire:load", function (event) {
$(document).ready(function() {
$('.mul-select').select2();
});
});
</script>
Component:
public $id_to, $id_from, $sujet, $cc, $message;
public $rules=[
'id_to' => 'required',
'id_from' => '',
'cc' => '',
'sujet' => 'required|max:30',
'message' => 'required|max:155',
];
public function render()
{
return view('livewire.admin.messages.messages');
}
public function submit()
{
$validateData=$this->validate();
$to_email=User::where('email', $validateData['id_to'])->first();
Mail::send(array(), array(), function ($message) {
$validateData=$this->validate();
$emails=$validateData['id_to'];
foreach($emails as $email)
{
$message->to($email)
->subject($validateData['sujet'])
->from(Auth::user()->email, 'ADMIN')
->setBody($validateData['message']);
}
});
$validateData['id_from']=Auth::user()->id;
$validateData['id_to']= implode(",", $to_email->id);
SendMessage::create($validateData);
session()->flash('success', 'data has been sent successfully');
$this->resetForm();
}
public function resetForm()
{
$this->id_to = '';
$this->cc = '';
$this->sujet = '';
$this->message = '';
}

Here is a simple way to achieve that
<div class="col-md-11">
<div wire:ignore> // this will make sure to ignore DOM changes
<select
class="form-control"
id="mul-select"
name="id_to[]"
multiple="multiple"
>
<option value="test#gmail.com">test#gmail.com</option>
<option value="test5#gmail.com">test5#gmail.com</option>
</select>
</div>
<div class="text-danger">
#error('id_to')
<span>
<strong>{{ $message }}</strong>
</span>
#enderror
</div>
</div>
And then outside of your component root tag make sure you push this script to your layout
#push('scripts')
<script>
$(document).ready(function () {
$('#mul-select').select2();
$(document).on('change', '#mul-select', function (e) {
//when ever the value of changes this will update your PHP variable
#this.set('id_to', e.target.value);
});
});
</script>
#endpush
Finally, on your layout file append the pushed script like this just before closing your body tag
#stack('scripts')
</body

Normally for select2 in Livewire I use hydration for element's rerender.
<div class="form-group row" wire:ignore.self> // I'm not sure about this it's necessary
<label for="to" class="col-form-label col-md-1">à :</label>
<div class="col-md-11" >
<select class="form-control mul-select" wire:model.lazy="id_to" name="id_to[]" multiple="multiple">
<option value="test#gmail.com">test#gmail.com</option>
<option value="test5#gmail.com">test5#gmail.com</option>
</select>
<div class="text-danger">
#error('id_to') <span><strong>{{ $message }}</strong></span> #enderror
</div>
</div>
</div>
//......
<script>
$(document).ready(function() {
window.initSelectDrop=()=>{
$('.mul-select').select2({
placeholder: '{{ __('locale.Select') }}',
allowClear: true});
}
initSelectDrop();
$('.mul-select').on('change', function (e) {
livewire.emit('selectedCompanyItem', e.target.value)
});
window.livewire.on('select2',()=>{
initSelectDrop();
});
});
</script>
in component
public function hydrate()
{
$this->emit('select2');
}
protected $listeners = [
'selectedCompanyItem'
];
public function selectedCompanyItem($value)
{
dd($value);
}

Related

Ajax With Django Not Reload Page But Loop will reload

<div class="container" id="cd">
<div class="row">
<div class="col-2">
<label for="serialno" class="h4 text-center mx-4"> S.No </label>
</div>
<div class="col-3">
<label for="billno" class="h4 text-center"> Bill No</label>
</div>
<div class="col-5">
<label for="Items" class="h4 text-center"> Items</label>
</div>
<div class="col-2">
<label for="total" class="h4 text-center"> Total</label>
</div>
<hr>
</div>
{% for b,d in history.items %}
<div class="row" id="refresh">
<div class="col-2 py-2">
<label class="h6">{{forloop.counter}}. | {{b.created_at}}</label>
</div>
<div class="col-3 py-2">
<label class="h5">{{b}}</label>
</div>
<div class="col-5 py-2">
{% for i in d %}
<label class="h6">{{i.itemname}} x {{i.qty}} {{i.subtotal}}</label><br>
{% endfor %}
</div>
<div class="col-2 py-2">
<span class="h6">₹</span>
<label class="h6">{{b.grandtotal}}</label>
</div>
</div>
{% endfor %}
</div>
<script>
$(document).on('change','#myform',function(e){
e.preventDefault();
$.ajax({
type:'POST',
url:"{% url 'history' %}",
data:{
tb1:$('#cal').val(),
csrfmiddlewaretoken:$('input[name=csrfmiddlewaretoken]').val(),
},
success:function(response){
},
});
});
</script>
How Can I reload this {% for b,d in history.items() %} without refresh a page using ajax
Any way to change history value using ajax Important Note value processed by onchange event
I am trying to reload the loop without a page reload
I want to change the history.items() django variable value after the ajax call and corressponding values can be iterated
{% for b,d in history.items %}
<div class="row" id="refresh-main">
<div class="row" id="refresh-child">
<div class="col-2 py-2">
<label class="h6">{{forloop.counter}}. | {{b.created_at}}</label>
</div>
<div class="col-3 py-2">
<label class="h5">{{b}}</label>
</div>
<div class="col-5 py-2">
{% for i in d %}
<label class="h6">{{i.itemname}} x {{i.qty}} {{i.subtotal}}</label><br>
{% endfor %}
</div>
<div class="col-2 py-2">
<span class="h6">₹</span>
<label class="h6">{{b.grandtotal}}</label>
</div>
</div>
</div>
{% endfor %}
<script>
$(document).on('change','#myform',function(e){
e.preventDefault();
$.ajax({
type:'POST',
url:"{% url 'history' %}",
data:{
tb1:$('#cal').val(),
csrfmiddlewaretoken:$('input[name=csrfmiddlewaretoken]').val(),
},
success:function(response){
var pageURL = $(location).attr("href");
$('#refresh-main').load(pageURL + ' #refresh-child');
},
});
});
</script>

Livewire to update live status message during function execution

I have Livewire Country component which has input text for user to input 2-letter country code. After input the code, user will click on Import button and it calls import function to process. It will find the Country by given code and import the cities. Is there anyway to display a live message to show process status, ex: "Importing for country name".
Here is my code:
Livewire component
class CityImportComponent extends Component
{
public string $iso2 = '';
public string $process_message = '';
public function resetFilters()
{
$this->reset(['iso2', 'process_message']);
}
public function getCountryProperty()
{
return Country::findByCode($this->iso2)->first();
}
public function render()
{
return view('livewire.import.state-and-city-not-in-france');
}
public function import()
{
$this->process_message = 'Importing cities for ' . $this->country->name;
}
}
Livewire view
<div class="position-relative">
#if (session()->has('error'))
<div class="alert alert-danger mb-3">
<i class="bi bi-info-circle-fill"></i> {{ session('error') }}
</div>
#endif
#if (session()->has('success'))
<div class="alert alert-success mb-3">
<i class="bi bi-check-circle-fill"></i> {{ session('success') }}
</div>
#endif
<div class="position-absolute w-100 h-100" wire:loading wire:target="import">
<div
class="d-flex align-items-center justify-content-start text-white w-100 h-100 bg-secondary ps-3 rounded gap-2">
<i class="bi bi-arrow-repeat spin"></i> <span wire:model="process_message">{{ $process_message }}</span>
</div>
</div>
<form wire:submit.prevent="import">
<input type="text" class="form-control text-uppercase" name="iso2" wire:model="iso2" placeholder="2-letter country code">
<button type="submit" class="btn btn-outline-secondary">
Import
</button>
</form>
</div>
You could add a div and call wire:loading:
<div class="alert alert-primary" role="alert" wire:loading wire:target.longest="import">
{{ $process_message }}
</div>
More info can be found here: Livewire Loading States
try this.
<div wire:loading.delay class="float-right">
<span class="bg-info col-md-12 rounded"><b>Loading...</b>{{ $process_message }}</span>
</div>

'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();
}

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,}))$/);