I want to display an error in a bootstrap modal when a user submits an incorrect login form. Right now, the submitting the form just reloads the current page so I can't get the JSON response.
basic.html where the login modal appears
...
<button type="button" class="btn btn-secondary btn-sm" data-toggle="modal" data-target="#loginModal" id="login_modal_trigger">Log In</button>
{% include 'registration/login.html' with form=form %}
...
registration/login.html
<div class="modal fade" id="loginModal" tabindex="-1" role="dialog" aria-labelledby="loginModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Log In</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<div id="content-container" class="container p-none">
<div class="lgn-container col-lg-8">
<form id="login-form" method="post"
action="">
{% csrf_token %}
<table class="table">
<tr>
<td><label for="id_username">Username</label></td>
<td><input id="id_username" name="username"
type="text" class="form-control"></td>
</tr>
<tr>
<td><label for="id_password">Password</label></td>
<td><input id="id_password" name="password"
type="password" class="form-control"></td>
</tr>
</table>
{% if form.errors %}
<p class=" label label-danger">
Your username and password didn't match.
Please try again.
</p>
{% endif %}
<input type="submit" id="ajax_form_submit" value="Login"
class="btn btn-primary pull-right" />
</form>
</div>
</div>
</div>
</div>
</div>
</div>
script.js:
I figured event.preventDefault(); would prevent refreshing when there is an error.
$(document).ready(function() {
$("#login-form").submit(function(event) {
jQuery.ajax({
"data": $(this).serialize(),
"type": $(this).attr("method"),
"url": "{% url 'login_user' %}",
"success": function(response) {
// switch(response.code) {
// // Do what you want with the received response
// }
console.log(response);
if (response.code == 0) {
console.log("fail");
}
}
});
event.preventDefault();
});
});
project/urls.py
...
urlpatterns = [
...
url(r'^login/$', views.login_user, name='login_user'),
...
]
...
app/views.py
from django.contrib.auth import authenticate, login
def login_user(request):
username = request.POST['username']
password = request.POST['password']
user = authenticate(request, username=username, password=password)
if user is not None:
login(request, user)
# Redirect to a success page.
return HttpResponseRedirect(reverse('app:detail', args=(username,)))
else:
# Return an 'invalid login' error message.
response = {'code': 0}
return HttpResponse(response, content_type='application/json')
# return HttpResponse(status=404)
The login modal currently doesn't even work with my edits, but my main problem is the refreshing of the page after submitting instead of just giving me a response in JSON to then edit the HTML with. The js I use is mostly from other posts.
In your app/views.py you need to change else (that identify erro login) to:
return HttpResponseRedirect(reverse('app:login', args=(response,)))
Now you pass in the first parameter the name of your login view, and agr you send the 'response'.
In your template:
{% if code == 0 %}
<p class=" label label-danger">
Your username and password didn't match.
Please try again.
</p>
{% endif %}
Related
I have Table showing data from database inside each row there is a button
opening a modal with the current clicked row id like following:
<tbody>
#foreach($receivedShipments as $shipment)
<tr>
<th class="text-center" scope="row">
{{ $loop->iteration }}
</th>
<td class="font-w600 font-size-sm">
<button type="button" class="btn btn-sm btn-light js-tooltip-enabled push"
data-toggle="modal" data-target="#modal_handle_national_id" data-id="{{$shipment->id}}"
data-original-title="{{trans('validation.attributes.deliver_to_receiver_customer')}}">
{{trans('validation.attributes.deliver_to_receiver_customer')}}</button>
</td>
</tr>
#endforeach
</tbody>
the Modal modal_handle_national_id is :
<div class="modal fade" id="modal_handle_national_id" >
<div class="modal-content">
<form class="js-validation" id="handleForm" action="" method="POST">
#csrf
#if(count($errors)>0)
<div class="alert alert-danger ">
<ul>#foreach($errors->all() as $error)
<li>{{$error}}</li>
#endforeach
</ul>
</div>
#endif
<input type="text" class=" col-xl-8" id="receiver_customer_nationalId"
name="receiver_customer_nationalId"
value="{{ old('receiver_customer_nationalId') }}">
<button type="submit">Submit</button>
</form>
</div>
</div>
i have script to hadle the action link of the form according to clicked button row id:
<script>
#if (count($errors) > 0)
$('#modal_handle_national_id').modal('show');
#endif
$('#modal_handle_national_id').on('show.bs.modal', function (event) {
var button = $(event.relatedTarget);
$('#handleForm').attr("action", "");
var id = button.data('id');
var url = '{{ route("shipments.handle", ":id") }}';
url = url.replace(':id', id);
$('#handleForm').attr("action", url);
});
</script>
i need the modal to be re-showed with the same old clicked button id when there is a Laravel validation error
Any Help please?
You can use hidden.bs.modal event:
This event is fired when the modal has finished being hidden from the
user (will wait for CSS transitions to complete).
The snippet:
$('#modal_handle_national_id').on('hidden.bs.modal', function(e) {
$(this).find('form').trigger('reset');
})
When I use bootstrap modal for my form its only show first value.
here my template.html
{% for company in companys %}
<tr>
<td>{{ company.name }}</td>
<td>{{ company.desc }}</td>
<td align="center">
<button type="button" class="btn btn-warning margin-bottom" data-toggle="modal" data-target="#modal-default2">
delete
</button>
<div class="modal fade" id="modal-default2">
<div class="modal-dialog">
<form method="post" action="{% url 'system:company_delete' pk=company.pk %}">
{% csrf_token %}
<div class="modal-content">
<div class="modal-body">
<input type="text" name="name" maxlength="100" required="" id="id_name" value="{{ company.pk }}">
<input type="submit" class="btn btn-primary" value="Delete">
</div>
</div>
</form>
</div>
</div>
</td>
</tr>
{% endfor %}
its loop all the data, when click delete confirm form will popup. but its return same value.
but if without modal-bootstrap its work fine.
example: template.html
{% for company in companys %}
<tr>
<td>{{ company.name }}</td>
<td>{{ company.desc }}</td>
<td align="center">
<form method="post" action="{% url 'system:company_delete' pk=company.pk %}">
{% csrf_token %}
<input type="text" name="name" maxlength="100" required="" id="id_name" value="{{ company.pk }}">
<input type="submit" class="btn btn-primary" value="Delete">
</form>
</td>
</tr>
{% endfor %}
it's work fine.
what I should do to make it work?...
update
views.py
# Company Crud
class CompanyListView(ListView):
context_object_name = 'companys'
model = models.Company
class CompanyCreateView(CreateView):
fields = ('name', 'desc')
model = models.Company
class CompanyUpdateView(UpdateView):
fields = ('name', 'desc')
model = models.Company
class CompanyDeleteView(DeleteView):
model = models.Company
success_url = reverse_lazy("system:company_list")
Your ajax modal will always return the same value inside modal because:
- Modal has this data-target="#modal-default2" as the target, however, your loop contains the modal body, with the id id="modal-default2", which will render modal as much as your loop goes.
So what you can do is to define a unique ID for each modal with the ID of each company modal-default{{company.id}}:
{% for company in companys %}
''' rest of codes '''
<button type="button" class="btn btn-warning margin-bottom" data-toggle="modal" data-target="#modal-default{{company.id}}">
delete
</button>
''' rest of codes '''
<div class="modal fade" id="modal-default{{company.id}}">
<div class="modal-dialog">
</div>
</div>
''' rest of codes '''
{% endfor %}
But this method is not effective if you have a lot of data, it will render lots of html codes.
Another option
With AJAX and one modal.
Your html would be:
{% for company in companys %}
<td>{{ company.name }}</td>
<td>{{ company.desc }}</td>
<button data-id="{{company.id}}" type="button" class="btn btn-warning margin-bottom delete-company" >
delete
</button> <!-- be aware of class 'delete-company' -->
{% endfor %}
{% csrf_token %}
<div class="modal fade" id="modal-default">
<div class="modal-dialog">
{% if company %} <!-- this company instance will come from AJAX -->
<form method="post" action="{% url 'system:company_delete' pk=company.pk %}">
{% csrf_token %}
<div class="modal-content">
<div class="modal-body">
<input type="text" name="name" maxlength="100" required="" id="id_name" value="{{ company.pk }}">
<input type="submit" class="btn btn-primary" value="Delete">
</div>
</div>
</form>
{% endif %}
</div>
</div>
AJAX
$(document).on('click','.delete-company',function(){
var id = $(this).data('id');
$.ajax({
url:'',
type:'POST',
data:{
'id':id,
'csrfmiddlewaretoken': $('input[name=csrfmiddlewaretoken]').val(),
},
success:function(data){
$('#modal-default .modal-dialog').html($('#modal-default .modal-dialog',data));
$('#modal-default').modal('show');
},
error:function(){
console.log('error')
},
});
});
And your views would be:
change your url from CompanyListView.as_view() to companyListView
def companyListView(request):
context = {}
companys = models.Company.objects.all()
if request.method == 'POST' and request.is_ajax():
ID = request.POST.get('id')
company = companys.get(id=ID) # So we send the company instance
context['company'] = company
context['companys'] = companys
return render(request,'template.html',context)
My purpose is once modal form submitted, ajax pass the username and password to a view and get back the json info to update the modal form, I trace the djanog code ,and 100% sure the JsonResponse(rsdic) has been executed in server side, as well as client fully receive the son info with ajax success function.
The problem is how to update the #error_message1 field which embeded in model. I tried .html() or .append(), all failed.
I leave the core coding for your reference, many thanks again for your help again.
ajax component:
$.ajax(
{
type: "POST",
url: url,
data: {
'username': username,
'password': password
},
dataType: 'json',
success: function(data){
$('#login-form')[0].reset();
if (data.ret != '1107'){
var htmlcode ="<p> data.info </p>";
$('#modal').find('.error_message1').append(htmlcode);
}
},
error: function (data) {
console.log('An error occurred.');
console.log(data);
},
});
html component:
<div class="modal fade" id="modal">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div id="form-modal-body" class="modal-body">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4>EXP LOGIN</h4>
<form role="form" action="{% url 'auth_login' %}" method="post" id="login-form">
{% csrf_token %}
<ul>
<li>
<div class="g-icon"><i class="iconfont icon-yonghu"></i></div>
<input type="text" name="username" id="username" value="" placeholder="User name" />
</li>
<li>
<div class="g-icon"><i class="iconfont icon-mima"></i></div>
<input type="password" name="password" id="password" value="" placeholder="Password" onblur="check1()" />
<div class="g-cue" id="error_message1">Your email or password was entered incorrectly.</div>
</li>
</ul>
<div class="g-btn">
<input class="g-submit" id='login-button' type="submit" value="{% trans 'Log in' %}" />
<input type="hidden" name="next" value="{{ next }}" />
</div>
<p><span>{% trans "Not a member?" %} Join now.</span></p>
</form>
</div>
</div>
</div>
</div>
you have error_message1 as id not class
$('#modal').find('#error_message1').html(htmlcode);
Here's the code of an Angular 4 component used to collect contact information from visitors:
.html:
<form (submit)="onCreateContact()">
<div class="form-group">
<input type="text" [(ngModel)]="contactname" name="contactname" class="form-control form-control-lg" placeholder="Name">
</div>
<div class="form-group">
<input type="email" [(ngModel)]="contactemail" name="contactemail" class="form-control form-control-lg" placeholder="Email">
</div>
<div class="form-group">
<input type="text" [(ngModel)]="contactphone" name="contactphone" class="form-control form-control-lg" placeholder="Phone">
</div>
<input type="submit" class="btn btn-outline-light btn-block" data-toggle="modal" data-target='#addContactModal'>
</form>
<!-- Modal -->
<div class="modal fade" id="addContactModal" tabindex="-1" role="dialog" aria-labelledby="addContactModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="addContactModalLabel">Contact</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
Thanks for contacting us! We will get in touch with you shortly.
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" data-dismiss="modal">OK</button>
</div>
</div>
</div>
</div>
.ts:
onCreateContact() {
let contact = {
contactname: this.contactname,
contactemail: this.contactemail,
contactphone: this.contactphone
}
return this.http.post('api/contacts/add', contact).map(res => res.json()).subscribe(data => {
if(data.success) {
console.log(data);
} else {
console.log('Failed to add contact');
}
}
);
}
All contact fields are required; the data is not passed to the backend if not all fields are filled.
Currently, the Bootstrap modal popups every time I press the submit button, even when the data is not passed. How can I show it only when the data is actually passed to the server?
You are toggling the modal when the user clicks on the submit button.
What you need to do is, toggle the modal from component class(.ts) after getting the response from the backend.
So in your ".ts" file add below line under the imports section
declare var $: any;
Then toggle modal after receiving response from backend as below
onCreateContact() {
return this.http.post('api/contacts/add', contact).map(res => res.json()).subscribe(data => {
if(data.success) {
console.log(data);
$('#addContactModal').modal('show'); // Add this line
} else {
console.log('Failed to add contact');
$('#errorModalId').modal('show'); // If you are planning to show error modal when something goes wrong.
}
});
}
Don't forget to remove data-toggle and data-target attribute from submit button.
Hope this helps.
I'll try to be as clear as I can. I'm trying to code a CRUD. I have a table that shows all the info about products. To register a new item I have a form in a modal and it sends the data with AJAX to a .php file called 'registro.php' where the data is inserted into the MySQL table.
I'd like to make that after clicking the 'Submit' button of the new-item form, the table auto-realoaded showing the new row too without refreshing the page.
The INSERT INTO is working fine but after inserting a new item, the <table> that displays all the data just disappears
So, this is my form # index.php
<div class="modal fade" id="myModalNorm" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog" id="modal-dialog">
<div class="modal-content">
<!-- Modal Header -->
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"> <span aria-hidden="true">×</span>
<span class="sr-only">Cerrar</span>
</button>
<h4 class="modal-title" id="myModalLabel"> Registrar un artículo </h4>
</div>
<div class="modal-body">
<!-- Modal form -->
<form name="nuevo_registro" id="nuevo_registro" action="" onsubmit="registrarNew(); return false">
<div class="form-group">
<label for="descripcion">Descripción</label>
<input type="text" class="form-control" id="descripcion" name="descripcion" placeholder="Descripción del artículo"/>
</div>
<div class="form-group">
<label for="precio">Precio</label>
<div class="input-group">
<span class="input-group-addon">Bs.</span>
<input type="text" class="form-control" id="precio" name="precio" placeholder="Precio"/>
</div>
</div>
<div class="form-group">
<label for="existencia">Existencia</label>
<input type="text" class="form-control" id="existencia" name="existencia" placeholder="Unidades en existencia"/>
</div>
<button type="submit" name="submit" id="submitmodal" class="btn btn-default">Guardar</button>
</form>
</div>
</div>
</div>
</div>
This is the ajax code at the bottom of index.php
$(document).ready(function() {
$('#nuevo_registro').submit(function(e){
e.preventDefault();
$.ajax({
url: 'registro.php',
type: 'POST',
data: $(this).serialize()
})
.done(function(data){
$('#myModalNorm').modal('toggle');
$('#lista_articulos').fadeOut('slow', function(){
$('#lista_articulos').fadeIn('slow').html(data);
});
})
.fail(function(){
alert('Ajax Submit Failed ...');
});
});
});
And this is registro.php where the data is inserted into the MySQL table
<?php
if ( $_POST ) {
require_once 'dbconnection.php';
$descripcion=$_POST['descripcion'];
$precio=$_POST['precio'];
$existencia=$_POST['existencia'];
$query = "INSERT INTO producto (descripcion, precio, existencia, estado) VALUES ('$descripcion', '$precio', '$existencia', 'A')";
$conexion->query($query);
$conexion->close();
}
?>
Hope you can help me and thank you so much.
I needed to do that, one day, and here's my solution:
Send data to PHP file and INSERT to the mysql database
Get the last inserted ID, find all available data regarding that row
Make an array out of that data and json_encode it
On the main page with the table, find the table and prepend or append the data you just received.