I have created a modal to display information about a specific record when I click on the button.
{% for seat in seats %}
<span class="fa-stack fa-lg seat" id="{{ seat.id }}" data-toggle="modal" data-target="#seatModal">
<i style="color: lightgrey;" class="fa fa-stop fa-stack-2x"></i>
<strong style="color: white;" class="fa-stack-1x">
{{ seat.seatNo }}
</strong>
</span>
{% endfor %}
<div class="modal fade seat-details" id="seatModal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content"></div>
</div>
</div>
I have an Ajax request that get the information for the specific seat when clicking on that seat icon.
$(document).ready(function () {
$('.seat').click(function() {
var url = Routing.generate('show_seat', {'seat': $(this).attr('id')});
$.get(url, function (data) {
$(".modal-content").html(data);
});
});
});
This ajax call perform a request to the 'show_seat' route which lead to this controller action:
public function showSeatAction(Seat $seat)
{
return $this->render('AppBundle:Seat:seat_details.html.twig', [
'seat' => $seat,
]);
}
This action renders the details in the seat_details.html.twig;
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
<h4 class="modal-title">Seat Details</h4>
</div>
<div class="modal-body table-responsive no-padding">
<table class="table table-modal">
<tbody>
<tr>
<th>Description</th>
<td>{{ seat.desc }}</td>
</tr>
<tr>
<th>Seat Number</th>
<td>{{ seat.seatNo }}</td>
</tr>
<tr>
<th>Status</th>
<td>
{% if seat.status == 'special' %}
<span class="label label-info">{{ seat.status|upper }}</span>
{% elseif seat.status == 'bad' %}
<span class="label label-warning">{{ seat.status|upper }}</span>
{% else %}
<span class="label label-default">{{ seat.status|upper }}</span>
{% endif %}
</td>
</tr>
</tbody>
</table>
</div>
And finally when the Ajax request is done it loads it into the modal as you can see in that Ajax function: $(".modal-content").html(data);.
This works good, but now I'm trying to add a spinner, because what happens now is when I click one the modal opens and the right data displays, but when I close it and open a new one the model opens with the previous data and then when the Ajax is done the text data get replaced in the modal.
But I want to let a spinner show until the Ajax is done and then the complete modal should display.
I've tried to add this:
$(document).on({
ajaxStart: function() { $('.loading').show() },
ajaxStop: function() { $('.loading').hide() }
});
This makes the spinner appear when clicking and hides it when Ajax is done, but the modal still appear too early. So I've tried to modify it to this:
$(document).on({
ajaxStart: function() {
$('.loading').show();
$('.seat-details').hide();
},
ajaxStop: function() {
$('.loading').hide();
$('.seat-details').show();
}
});
But this doesn't change anything.
Can somebody help me out to fix this?
var seatModal = $("#seatModal");//your modal
$(document).on({
ajaxStart: function() {
seatModal.find(".modal-content").html("");//empty modal every ajaxstart
$('.loading').show();
seatModal.modal("hide");//hide
},
ajaxStop: function() {
$('.loading').hide();
seatModal.modal("show");//modal show
}
});
You can process with an other way. Initialize your modal with nothing in it.
Then, when the user close the modal, remove the content and replace it with your spinner.
$(".modal").on("hidden.bs.modal", function(){
$(".modal-content").html([your spinner here]);
});
Related
I'm working in Angular 8. I'm using NG-BOOTSTRAP for styling.
In several of my components I offer the ability to click a delete button on an item, this brings up a modal window with a YES or NO and when YES is clicked, the modal closes and the route appears to refresh, no actual browser refresh - this is what I want. The list is updated correctly and all seems fine. Then, when I try and click on any other route in my navbar they all fail and the page stays where it's at until I refresh the browser page - also, the link in the URL bar isn't updating, which I suspect is causing the pages not to be able to be routed to. Not sure why this behavior is happening. Frustrating too. Looking for some assistance if possible. Thanks.
THIS IS THE HTML TABLE
<tbody>
<tr *ngFor="let client of clients">
<td>{{ client.name | titlecase }}</td>
<td>{{ client.website }}</td>
<td>{{ client.phone }}</td>
<td>{{ client.address.street | titlecase }}, {{ client.address.city | titlecase }}
{{ client.address.state | uppercase }}
{{ client.address.zip }}</td>
<td>
<button class="btn btn-primary" (click)="editClient(client._id)">
<fa-icon [icon]="faEdit"></fa-icon>
</button>
<button class="btn btn-danger ml-3" (click)="open(content, client)">
<fa-icon [icon]="faTrashAlt"></fa-icon>
</button>
</td>
</tr>
</tbody>
----- THIS IS THE MODAL TEMPLATE (SAME HTML PAGE)------
<!-- MODAL TEMPLATE -->
<ng-template #content let-modal>
<div class="modal-header">
<h4 class="modal-title" id="modal-basic-title">Delete Client?</h4>
<button type="button" class="close" aria-label="Close" (click)="modal.dismiss('Cross click')">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<div class="row">
<div class="col-sm">
<button class="btn btn-success mr-3" (click)="deleteClient(modalContent._id)">YES</button>
<button class="btn btn-danger" (click)="modal.close('Close click')">NO</button>
</div>
</div>
</div>
</ng-template>
----- THIS IS THE TS FILE -----
deleteClient(id) {
this._clientService.deleteClient(id).subscribe(
response => {
console.log(response['message']);
// Close the modal window and reload the component
this._modalService.dismissAll();
this.reloadComponent();
},
error => console.log(error['message'])
);
}
///// MODAL FUNCTIONS
open(content, client) {
this.modalContent = client;
this._modalService
.open(content, { ariaLabelledBy: 'modal-basic-title' })
.result.then(
result => {
this.closeResult = `Closed with: ${result}`;
},
reason => {
this.closeResult = `Dismissed ${this.getDismissReason(reason)}`;
}
);
}
private getDismissReason(reason: any): string {
if (reason === ModalDismissReasons.ESC) {
return 'by pressing ESC';
} else if (reason === ModalDismissReasons.BACKDROP_CLICK) {
return 'by clicking on a backdrop';
} else {
return `with: ${reason}`;
}
}
///// FUNCTION TO RELOAD PAGE AFTER DELETE /////
reloadComponent() {
this._router.routeReuseStrategy.shouldReuseRoute = () => false;
this._router.onSameUrlNavigation = 'reload';
this._router.navigate(['admin/clients']);
}
Instead of reloading the page you could re-execute the call that binds the results from the backend to your clients var. This is at least a nice separation of sources & routing and can avoid further complications.
Something like:
deleteClient(id) {
this._clientService.deleteClient(id).subscribe(
response => {
console.log(response['message']);
// Close the modal window and reload the component
this._modalService.dismissAll();
this.getClients();
}, error => console.log(error['message'])
});
getClients() {
this._clientService.getClients().subscribe(
response => {
this.clients = response.data;
}, error => console.log(error['message'])
});
Table
<table id="fisicHostsTable">
<tr class="row">
<th class="tableHeader">Nombre</th>
<th class="tableHeader">IP</th>
<th class="tableHeaders">Sistema Operativo</th>
<th class="tableHeaders">Notas</th>
</tr>
<th:block th:each="fh : ${datacenterFisicHosts}">
<div>
<tr class="row">
<td id="fisicHostName" th:text="${fh.name}"></td>
<td id="fisicHostIp" th:text="${fh.ip}"></td>
<td id="fisicHostOS" th:text="${fh.operatingSystem}"></td>
<td id="fisicHostNotes" th:text="${fh.notes}"></td>
<td><button class="credentialsButton" th:attr="data-fisic-host-id=${fh.id}">CREDENCIALES</button></td>
</tr>
</div>
</th:block>
</table>
Modal:
<!-- Modal -->
<div class="modal fade" id="credentialsModal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="modal-title">Credenciales</h5>
</div>
<div class="modal-body">
<table id="credentialsTable">
<tr class="row">
<th>Usuario</th>
<th>Clave</th>
<th>Notas</th>
</tr>
</table>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Cerrar</button>
</div>
</div>
</div>
</div>
JS
$(".credentialsButton").click(function(){
var fisicHostId = $(this).data('fisic-host-id');
$.get( "/fisicHost/" + fisicHostId + "/credentials", data => {
console.log(data);
for (i = 0; i < data.length; ++i) {
var fisicHost = data[i];
var new_row = document.createElement('tr');
new_row.className = "row fisichost";
var userCol = document.createElement('td');
userCol.textContent = fisicHost["user"];
new_row.append(userCol);
var passwordCol = document.createElement('td');
passwordCol.textContent = fisicHost["password"];
new_row.append(passwordCol);
var notesCol = document.createElement('td');
notesCol.textContent = fisicHost["notes"];
new_row.append(notesCol);
$("#credentialsTable").append(new_row);
}
$('#credentialsModal').modal('show');
$('#credentialsTable').remove(new_row);
}).fail(function(xhr, status, error) {
console.error(error);
alert('No se pudieron cargar las credenciales.');
});
});
The data array looks always like this:
the problem I have is that the credentials are repeating each time I click on the button. I want to show them once, not in a cicle but can't find the way to stop them from cycling !
I've added the remove(new_row) after the modal is showing but it's removing everything !
EDIT:
This is the modal:
I just want to show the first two rows cause there are two credentials I need to show, but as you can see, each time I open the modal the data is repeating itself ... i want to stop that repetition!
I would say, right before the loop for(i= etc, put:
$('#credentialsTable').empty();
Thus you remove all rows before adding.
So put this code just before the loop.
I think you are retrieving credentials and adding them to the table that you have in the modal. The problem is that once you close and open model, previous data is still there and new data is being added. To avoid such situation you need to listen to modal close event and once modal is closed remove added rows.
Something like this:
$('#credentialsModal').bind('hide', function () {
$('#credentialsModal tr.fisichost').remove();
});
You can use the jquery method .one instead of .on to only run a function the first time an event occurs.
$("button").one("click", function() {
console.log("ran only the once");
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button>click me</button>
I need to create a button that will automatically search in my database all user with a "secouriste" Attribute set and print their firstname, lastname and phone number in a popup.
Here is what I found from my research:
In my HTML, I have to set a button which will enable a popup modal with id of the user I want to get and under this button, there is the code of my popup modal with a listener.
In my JS, I get the data (which is an object).
In Ajax, I need to pass the ID to my controller.
In PHP, I get the ID with a symfony request and FindOneBy.
But there are different problems with this technique: I dont need to get only one person but a list of person with the good attribute so maybe I should use "FindBy" instead of "FindOneBy", but someone said to me that I should use a custom FindAll(). I'm completely lost right now. Here is what I could gather from posts, I know that's far from right, but this is what I have.
//=============================================
// Recherche PopUp Secouriste
//=============================================
$(document).on('show.bs.modal', '#secouristeModal', function (e) {
var id = $('#secouristeModal').data('id');
$.ajax({
url: 'UserBundle/utilisateur',
method: 'POST',
data: {
id: id
}
}).done(function (data) {
// Si status est égal à true
if(data.status) {
console.log(data);
$('#userTitle').replaceWith(data.user.firstName);
}
}).fail(function (data) {
// Code if error
});
})
PHP
$user = $this->findBy($request->request->get('secouristeAttribute' -> $secouristeAttribute));
if($user) {
return new JSONResponse(array(
'user' => $user
));
} else {
// Faire code de retour avec une erreur (status = false)
}
}
<!-- Button trigger modal -->
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#secouristeModal">
Liste des secouristes
</button>
<!-- Modal des secouristes-->
<div class="modal fade" id="secouristeModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Liste des Secouristes</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<!-- prints a list but doesnt load it from db on request only -->
{% for user in workFlow.listeSecouriste|default('')%}
{% if user.tel is not null %}
<br />{{ user.username }} - {{ user.nom }} {{ user.prenom }} - {{ user.tel }}
{% else %}
<br />{{ user.username }} - {{ user.nom }} {{ user.prenom }}
{% endif %}
{% endfor %}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
Thank you very much for your help.
Exx
I don't think you can filter your query with a findAll so findBy is good.
But you need to pass an array, something like that:
$users = $this->findBy(['attribute' => $request->request->get('secouristeAttribute')]);
Also, I'm not really sure about that, but before you return your list of Users you could have to implement JsonSerializable Interface with the method jsonSerialize() (or at least the toArray() magic method).
I finally solved my problem, here is how I did it if it can help someone later:
//For my popup
function myAlert(message,titre='Information',btn='',class_msg='',fonction,args) {
//=======================================================
if (btn==''){
btn='<a name="btnOk" class="btn btn-success">Ok</a>';
}
if (class_msg!='') {
message='<div class="'+class_msg+'">'+message+'</div>';
}
myConfirm(message,titre,btn,fonction,args); // Message d'alerte
}
//listeSecouriste.html.twig
<ul>{% for secouriste in listeSecouriste |sort secouriste.nom %}
<li>{{ secouriste.fullName }} {{ secouriste.tel }}</li>
{% endfor %}
</ul>
//php: my controller
public function getSecours($agence=null){
$listeSecouriste = $this->getDoctrine()->getManager()->getRepository('SIGUserBundle:Utilisateur')->ListeSecouriste($agence);
$retour=array('ok'=>false);
if ($listeSecouriste!== null){
$retour['ok']=true;
$retour['html']=$this->renderView('SIGUserBundle:Utilisateur:listeSecouriste.html.twig',
array(
'listeSecouriste'=>$listeSecouriste
)
);
}
return new JsonResponse($retour);
}
I am attempting to create a form that upon clicking submit calls a function that will post to a php page (which runs a query), then displays those results on the page.
If I call said function in my controller on load, I get my expected result(data presented in html table in a modal). However if I call that function upon clicking submit. I can log the data result, but it does not display on my page.
$scope.report = {};
var url = "";
// calling our submit function.
$scope.submitForm = function() {
$http.post('url.php').success(function(data) {
// Stored the returned data into scope
$scope.names = data;
console.log(data);
$('#myModal').modal();
});
};
<button type = "button" class="btn btn-success" ng-click="submitForm()" >Submit Request</button>
<div class="modal fade" id="myModal" role="dialog" >
<div class="modal-dialog">
<!-- Modal content-->
<div class="modal-content" >
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title">Modal Header</h4>
</div>
<div class="modal-body">
<table class="table table-striped table-bordered">
<tr>
<th>Name</th>
</tr>
<tr ng-repeat="name in names | filter:search_query">
<td><span>{{name.first}}</span></td>
</tr>
</table>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
Try adding a small $timeout before opening your modal (don't forget to inject $timeout to your controller):
$scope.submitForm = function() {
$http.post('url.php').success(function(data) {
// Stored the returned data into scope
$scope.names = data;
console.log(data);
$timeout(function () {
$('#myModal').modal();
},250);
});
};
I'm a newbie to Laravel 4, and I'm trying to get a form validation in bootstrap modal.
My modal have a form with a text input and a submit button, and I want that when the validation fails, the modal show me the error.
But the modal, after the validation and the page refresh, is closed.
Here is the code from the controller and the view:
Controller code:
public function postAvatar()
{
$avatar_rules = array(
'avatar_src' => 'url',
);
$validator = Validator::make(Input::all(), $avatar_rules);
$validator->setAttributeNames(User::$names_attr);
if ($validator->passes())
{
$avatar_src = (Input::get('avatar_src'))? Input::get('avatar_src') : URL::asset('assets/images/user/default-user-avatar.png');
$user = User::find(Auth::id());
$user->avatar_src = $avatar_src;
if ($user){
return Redirect::to('dashboard')->withSuccess("Success: avatar updated.");
}
return Redirect::to('dashboard')->withError("Error: an error has occurred.");
}
return Redirect::back()->withErrors($validator);
}
View code:
<!-- Modal -->
<div class="modal fade" id="avatarModal" tabindex="-1" role="dialog" aria-labelledby="avatarModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span><span class="sr-only">Close</span></button>
<h4 class="modal-title" id="avatarModalLabel">Update avatar</h4>
</div>
<div class="modal-body">
<h4><span class="label label-info">Current avatar</span></h4>
<img class="img-circle img-responsive dashboard-avatar" src="{{ $user->avatar_src }}" alt="{{ $user->username }} avatar">
<div class="divider"></div>
<h4><span class="label label-info">New avatar</span></h4>
{{ Form::open(array('url' => 'dashboard/avatar', 'method'=>'post', 'role'=>'form')) }}
<ul>
#foreach($errors->all() as $error)
<div class="alert alert-danger" role="alert">{{ $error }}</div>
#endforeach
</ul>
<div class="form-group">
<label for="avatar_src" class="control-label">Link avatar</label>
<input type="text" name="avatar_src" class="form-control" id="avatar_src" placeholder="Link of avatar image url">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button type="submit" class="btn btn-primary">Update</button>
</div>
{{ Form::close() }}
</div>
</div>
</div>
How can I resolve ?
Thanks.
SOLVED:
Controller code:
public function postAvatar()
{
$avatar_rules = array(
'avatar_src' => 'url',
);
$validator = Validator::make(Input::all(), $avatar_rules);
$validator->setAttributeNames(User::$names_attr);
if ($validator->passes())
{
$avatar_src = (Input::has('avatar_src'))? Input::get('avatar_src') : URL::asset('assets/images/user/default-user-avatar.png');
$user = User::find(Auth::id());
$user->avatar_src = $avatar_src;
if ($user->save()){
if(Request::ajax()){
return Response::json(array('success' => true));
}
}
return Redirect::to('dashboard')->withError("Error: an error has occurred.");
}
return Response::json(array('errors' => $validator->errors()->toArray()));
}
View code:
<!-- Modal -->
<div class="modal fade" id="avatarModal" tabindex="-1" role="dialog" aria-labelledby="avatarModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span><span class="sr-only">Close</span></button>
<h4 class="modal-title" id="avatarModalLabel">Update avatar</h4>
</div>
<div class="modal-body">
<h4><span class="label label-info">Current avatar</span></h4>
<img class="img-circle img-responsive dashboard-avatar" src="{{ $user->avatar_src }}" alt="{{ $user->username }} avatar">
<div class="divider"></div>
<h4><span class="label label-info">New avatar</span></h4>
{{ Form::open(array('url' => 'dashboard/avatar', 'id'=>'avatar_form', 'method'=>'post', 'role'=>'form')) }}
<div class="alert alert-danger avatar_alert" role="alert" style="display: none">
<ul></ul>
</div>
<ul>
</ul>
<div class="form-group">
<label for="avatar_src" class="control-label">Link avatar</label>
<input type="text" name="avatar_src" class="form-control s_tooltip" id="avatar_src" placeholder="Avatar image links">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button type="submit" class="btn btn-primary">Update</button>
</div>
{{ Form::close() }}
</div>
</div>
</div>
Ajax:
<script>
$(document).on('submit', '#avatar_form', function(event){
var info = $('.avatar_alert');
event.preventDefault();
var data = { avatar_src: $("#avatar_src").val() }
$.ajax({
url: "/dashboard/avatar",
type: "POST",
data: data,
}).done(function(response) {
info.hide().find('ul').empty();
if(response.errors)
{
$.each(response.errors, function(index, error){
info.find('ul').append(error);
});
info.slideDown();
}
else if(response.success){
window.location.href = "/dashboard";
}
});
});
</script>
Your best bet would be to validate the form via AJAX to avoid the page reloading entirely. You would then check the response of your AJAX request for the presence of errors and show them inside the modal if they exist.
You could also add in client side validation to prevent the request being made until the rules are satisfied. I wouldn't recommend using this INSTEAD of server side validation but using it ASWELL as is normally quite desirable.
To accomplish this, you'd need to do something along these lines:
Javascript:
Catch submit event of your form and make an AJAX request.
$(document).on('submit', 'form', function(event){
event.preventDefault();
var data = { avatar_src: $("#avatar_src").val(); };
$.ajax({
url: "/dashboard/avatar",
data: data
type: "POST",
}).done(function(response) {
if(response.errors)
{
// Add error to Modal Body
}
else
{
// Show success message, close modal?
}
});
});
Backend:
Modify your controller method to detect if the current request is an AJAX request and if so, return the response in JSON instead of Redirecting. For example:
if(Request::ajax())
{
return Response::json(array('errors' => $validator->messages()));
}
else
{
return Redirect::back()->withErrors($validator);
}
I've not tested any of that code so might contain some typos/errors but hopefully this helps you!
I was facing same issue. After research on internet,I found that Laravel don't support withSuccess('success_msg') method.
return Redirect::to('dashboard')->withSuccess("Success: avatar updated.");
Here is complete discussion on this topic:
https://github.com/laravel/framework/issues/906.
But you can handle this issue with this approach:-
- For Error message:-
[code has to be added in controller]
return Redirect::to('view')->withErrors('your error message.');
[code has to be added in view]
#if(isset($errors) && count($errors->all())>0)
<ul>
#foreach($errors->all() as $error)
<li>{{ $error }}</li>
#endforeach
</ul>
#endif
- for succcess message:-
[code has to be added in controller]
$success_msg='your success message.';
Session::flash('successMsg', $success_msg);
return Redirect::to('view');
[code has to be added in view]
#if (Session::has('successMsg'))
{{ Session::get('successMsg') }}
#endif
This approach is working fine for me.
For better display of your errors you can use bootstrap css.