Rails: don't refresh page after modal action/submit - javascript

I have a modal which opens on top of another screen. The base screen has a filter method that uses AJAX to filter the results on that page.
After, I filter the results on the screen, I can open the modal and perform an action on the form in the modal. However, I don't want to perform a redirect/refresh.
How do I do this while still performing the submission?
My modal link is like:
<%= link_to this_path(user_id: user.id), class:"modal-link", data: {"modal-url" => this_path(user_id: user.id)} do %><span><i class="fa fa-plus"></i><% end %>
The modal is standard enough:
<div class="modal form-modal">
<div class="modal-container">
<div class="modal-dialog modal-dialog-wide">
<button class="close">×</button>
<div class="modal-content">
<div class="modal-header">
<h2 class="hdg-b">Edit This</h2>
</div>
<div class="modal-body">
<div id="error_explanation"></div>
<%= render 'form', form_path: action_path, form_method: :put, create: false %>
</div>
</div>
</div>
</div>
</div>
The AJAX is too:
MyProject.onPageLoad(function() {
var form = $('.edit_site_scope'),
onSubmit = function(event) { //callback handler for form submit
event.preventDefault();
var form = $(this),
url = form.attr("action"), //get form action:
type = form.attr("method"),
data = form.serialize();
var location = window.location.href;
var posting = $.ajax({
type: type,
url: url,
data: data,
dayaType: "json",
success:function(data, textStatus, jqXHR)
{
$('.modal').remove();
window.location = location;
$('#contact-tab-submit').show();
},
error: function(jqXHR, textStatus, errorThrown)
{
$('#error_explanation').html('');
errors = jqXHR.responseJSON;
$.each( errors, function( key, value ) {
$('#error_explanation').append('<div class="alert alert-dismissable" id="alert-message"><i class="fa fa-exclamation-triangle"></i>' + value + '<div class="alert-close">Close</div></div>');
});
$('#contact-tab-submit').show();
}
});
window.setTimeout(function() {
$(".alert").fadeTo(500, 0).slideUp(500, function(){
$(this).remove();
});
}, 5000);
return false; // prevent default when submit button clicked
};
if (form.size() !== 0) {
form.submit(onSubmit);
}
});
And here is my controller action on the form submit:
def action_to_be_performed
#this_thing = ThisThing.where(id: params[:id]).first
#this_thing.update(this_things_params)
flash[:success] = "Successfully performed the action."
render json: #this_thing
rescue => error
Rails.logger.error "Exception caught updating this.\nCause: #{error}\n" + error.backtrace.join("\n")
render json: #this_thing.errors.full_messages, status: :bad_request
end
I really struggle with modals still and I guess with AJAX. How do I perform my action, close the modal and keep the current page open?

I figured out a simple solution on the drive home. The following line in my Javascript:
window.location = location;
can be changed to:
window.location.reload();

Related

Check data in Succes ajax function to reidrect to specific view

I am calling a javascript function on click which calls an action method that returns either a partial view or full view. I want to load partial view in a modal popup and if it is a full view, then just want to redirect it.
View
foreach(var productTemplate in Products)
{
Add New Product
}
<div class="modal fade" id="mymodel" role="dialog" tabindex="-1">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">Shared Products</h4>
<button type="button" class="close" data-dismiss="modal">×</button>
</div>
<div class="modal-body" id="mymodelbody">
</div>
</div>
</div>
<script>
var loadModal = function (productId, customerId) {
$.ajax({
type: 'GET',
url: '/NewProductTemplate/CreateNewProduct',
cache: false,
data: {
productId: productId,
customerId: customerId
},
dataType: 'html',
success: function (data) {;
$("#mymodelbody").html(data);
$("#mymodel").modal("show");
}
});
}
</script>
NewProductTemplateController code:
public ActionResult CreateNewProduct(Guid productId, Guid customerId)
{
var sharedProduct = _productTemplateService.GetSharedProducts(productId);
var _finalSharedProducts = (sharedProduct.Any(t => t.productId != productId));
if (_finalSharedProducts)
{
var sharedProdctTemplate = _productTemplateService.GetSharedProduct(productId);
return PartialView("_shared", new SharedModel
{
SharedProduct = sharedProdctTemplate
});
}
else
{
_productTemplateService.CreateNewProduct(productId);
return RedirectToAction("Details", "ProductTemplate");
}
}
Problem is that when controller returns a full view, it loads in a modal popup which I don't want. I just want to check the data in success function and decide whether to load modal for partial view OR redirect to a full view. I am not sure how to do it.
Can please someone help me here? Thank you!
UPDATE:
I was able to make it work like
if (data.indexOf('<!DOCTYPE html>') != 0) {
$("#mymodelbody").html(data);
$("#mymodel").modal("show");
} else {
window.location.href = '/ProductTemplate/Details?productTemplateId=' + productId;
}
One more question:
Is there any way that I can create a ProductModal object in javascript and pass it to the Details action method of ProductTemplate?
If your action returns your whole page, it will include the <!DOCTYPE html> and <html> tags. You can check if the result starts with '<!DOCTYPE html>' for example to make to check if it is the whole page or not.
success: function (data) {
if (!data.startsWith('<!DOCTYPE html>')) {
$("#mymodelbody").html(data);
$("#mymodel").modal("show");
} else {
window.location.href = '<redirect url here>';
}
}

Modal dialog's onshow not called after postback

I have a Bootstrap modal dialog that I am using to populate with data when user clicks on "Edit" in a jQuery data table. There is a Cancel and Submit button on this modal.
When I open the modal and click Cancel and then select another table row and click "Edit", everything is fine; data gets populated correctly each time "Edit" is clicked. However, if I do a postback by clicking "Submit" on the modal and then click "Edit" again, modal opens and no data is there.
I am using modal's on('show.bs.modal', ...) to populate it and it never gets hit after a postback is done.
// This is called when "Edit" in data table row is clicked
function showEdit(var1, var2) {debugger
$('#hfVar1').val(var1);
$('#hfVar2').val(var2);
showEditModal();
}
function showEditModal() {debugger
$("#spnEditHeader").text("Edit Something");
$('#editModal').modal('show');
}
$(document).ready(function () {
// This populates the jQuery data table
showTable(somthing, anotherThing);
// This is executed as long there is no postback;
// once a postback is perfoemd this is not hit, modal not populated
$('#editModal').modal({
keyboard: true,
backdrop: "static",
show: false
}).on('show.bs.modal', function (e) {debugger
var var1= $('#hfVar1').val();
var var2= $('#hfVar2').val();
//make ajax call to populate items
populateMPOOEdit(var1, var2);
});
....
});
//This is the button in modal that causes postback
<div class="modal-footer">
<div id="divEditButtons" style="text-align: center;">
<button id="btnCancel" class="btn btn-info2" data-dismiss="modal" aria-hidden="true" aria-label="Cancel">Cancel</button>
<button id="btnSubmit" class="btn btn-primary" aria-hidden="true" aria-label="Update">Update</button>
</div>
</div>
// "Submit" button's click handler
$(document).on("click", "#btnSubmit", function (event) {
// Validate data (client side validation)
var isValid = validateUpdate();
// Also need a server side validation checking for duplicate name, using ajax to do this
$.ajax({
type: "POST",
dataType: "json",
contentType: "application/json; charset=utf-8",
url: '<%= ResolveUrl("services/mpoo.asmx/NameExists") %>',
cache: false,
data: JSON.stringify({ "Name": name }),
}).done(function (data) {
var result = data.d;
if (result != '') {
nameExists = JSON.parse(data.d);
if (nameExists == "true") {
$("#lblErrName").text("Duplicate Name");
$("#lblEditErrName").show();
isValid = false;
}
if (isValid) {
__doPostBack('btnSubmit', JSON.stringify({
action: "SaveUpdate", Var1: var1, ..., Varn: varn
}));
$('#editModal').modal('hide');
}
}
});
return false; // to prevent modal from closing if there are errors on page
});
Create a function like this:
//basically everything you had in your document.ready function
function myJsFunc() {
// This populates the jQuery data table
showTable(somthing, anotherThing);
// This is executed as long there is no postback;
// once a postback is perfoemd this is not hit, modal not populated
$('#editModal').modal({
keyboard: true,
backdrop: "static",
show: false
}).on('show.bs.modal', function (e) {debugger
var var1= $('#hfVar1').val();
var var2= $('#hfVar2').val();
//make ajax call to populate items
populateMPOOEdit(var1, var2);
});
....
}
Then in your Page_Load event handler in your codebehind, try putting this:
Page.ClientScript.RegisterStartupScript(this.GetType(), "some random name for your script", "myJsFunc();", true);

Uploading files to django through ajax

I'm having trouble trying to upload files to django using ajax. The upload process is done in a modal.
Form
<div class="modal fade bs-example-modal-lg" id="fileUploadModal" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<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" id="myModalLabel2">Upload File</h4>
</div>
<div class="modal-body">
<div class="modal-body">
{% crispy fileform %}
</div>
</div>
</div>
</div>
</div>
The modal toggle
<a data-toggle="modal" href="#fileUploadModal" data-id="0" role="button" class="btn btn-success btn-sm pull-right">
<i class="fa fa-fw fa-cloud-upload"></i>
Upload File
</a>
This is how my file upload looks like
$(document).ready(function(){
var file = 0;
$('#fileUploadModal').on('show.bs.modal', function(e) {
file = $(e.relatedTarget).data('id');
var form = $(e.currentTarget).find('form');
$.ajax({
url: "{% url 'employee:ajax-file-upload' %}",
type: "POST",
data: $(form).serialize() + '&action=load&eid=' + employee + '&fid=' + file,
success: function(data) {
if (data['form_html']) {
$(form).html(data['form_html']);
$('.datepicker').datetimepicker({
format: 'YYYY-MM-DD'
});
}
}
});
});
$(".container" ).on('click', '#submit-file-upload', function(e) {
e.preventDefault();
e.stopImmediatePropagation();
var form = $(this).closest('form');
$.ajax({
url: "{% url 'employee:ajax-file-upload' %}",
type: "POST",
data: $(form).serialize() + '&eid=' + employee + '&fid=' + file,
success: function(data) {
if (!(data['success'])) {
$(form).replaceWith(data['form_html']);
$('.datepicker').datetimepicker({
format: 'YYYY-MM-DD'
});
}
else {
location.reload();
}
}
});
});
});
And my view looks like this
#json_view
#login_required
def ajax_file_upload(request):
if request.method == 'POST':
action = request.POST.get('action')
fid = int(request.POST.get('fid'))
eid = int(request.POST.get('eid'))
employee = Employee.objects.get(id=eid)
if action == 'load':
try:
file = File.objects.get(id=fid)
form = FileForm(instance=file)
except:
form = FileForm()
context = {}
context.update(csrf(request))
form_html = render_crispy_form(form, context=context)
return {'success': True, 'form_html': form_html}
else:
if fid == 0:
form = FileForm(request.POST or None, request.FILES or None)
else:
file = File.objects.get(id=fid)
form = FileForm(request.POST or None, request.FILES or None, instance=file)
if form.is_valid():
file = form.save(commit=False)
file.employee = employee
file.save()
messages.add_message(request, messages.SUCCESS, 'File was successfully saved.')
return {'success': True}
context = {}
context.update(csrf(request))
form_html = render_crispy_form(form, context=context)
return {'success': False, 'form_html': form_html}
I really can't seem to get it to work. I can successfully get other data but not the file. When I click on submit, it refreshes and I get a 'This field is required' in the file upload section.
I hope you can help me with this. Thanks.
Your ajax call is only posting the form data, not the file:
data: $(form).serialize() + '&action=load&eid=' + employee + '&fid=' + file
I would suggest using a library (such as jquery.fileupload.js but there's plenty of other options) to upload correctly a file, as it's quite a complex operation: you have to set the multipart/related body format, attach the file to your request as application/octet-stream, if it's large cut it into chunks etc etc...
With jquery.fileupload for example, uploading the file is as simple as:
$(function() {$('#fileupload').fileupload({
dataType: 'json',
formData: $(form).serialize()...
done: function(e, data) {
... your success handling code ...
}
});});
where $('#fileupload') targets your file input field (<input type='file'>).
The django code looks fine at first glance.

How to show Ajax response as modal popup

I have a link on clicking it is sending ajax request and getting response successfully which is html file and I am appending to a div, but I need to show that div as modal popup and I tried something below.
in html file
<a th:if="${ratingSummary}" href="#" class="small dark account review_ratings_login">Login to write a review</a>
<div id="login_for_review" data-toggle="modal" data-target="#reviewLoginModal"></div>
in js file
$(document).on('click', '.review_ratings_login', function () {
var $data = $('#review_product_id span').text();
var url = '/mycompany/login/'+$data;
$.ajax({
type: 'GET',
url: url,
success: function (output) {
$('#login_for_review').html(output).modal('show');// I tried to show this response as modal popup
},
error: function(output){
alert("fail");
}
});
});
output file
<div class="centerForm modal fade" role="dialog" style="margin-left: 35%;" id="reviewLoginModal">
<div class="modal-dialog modal-sm" >
<div class="modal-content">
// here I have login form
</div>
</div>
but I am not getting this html output as modal pup instead I am getting black screen can anyone help me how to do this?
In Bootsrap modal popup, You can use plain way to show modal which don't need pre-defined modal div container . see at modal
For E.g
$.ajax({
url: "url",
type: 'POST',
dataType: "html",
data:{id:params},
success: function(data, status, xhr) {
if(data==""){
window.location.href="/";
}
else{
BootstrapDialog.show({
title: "Modal Tital",
message: function(dialogRef){
$mydata = $($.parseHTML(data));
return $mydata;
},
onshow: function(dialog){
// and css change if need, eg.
dialog.$modalHeader.css("float","none");
},
onshown:function(dialog)
{
// event after shown
},
onhide:function(dailog)
{
// event on hide
}
});
}
},
statusCode: {
401: function () {
alert("Your session has been expired");
}
}
});
I solved this problem by creating modal and by removing data-toggle and data-target and just appending response to that modal div
Code For modal div
<div id="login_for_review" class="modal hide" role="dialog">
</div>
Code For hyperlink
<a th:if="${ratingSummary}" href="#" class="small dark account review_ratings_login">Login to write a review</a>
Code For ajax call
$(document).on('click', '.review_ratings_login', function () {
var $data = $('#review_product_id span').text();
var url = '/mycompany/login/'+$data;
$.ajax({
type: 'GET',
url: url,
success: function (output) {
$('#login_for_review').html(output).modal('show');//now its working
},
error: function(output){
alert("fail");
}
});
});

TwitterBootstrapMvc (3rd): modal dialog state

I use Modal dialogs to submit new records (Asp.Net, MVC).
<div id="modal-dlg" class="modal fade" tabindex="-1"></div>
<div id="banner-add">
<a class="btn-default btn" data-toggle="modal" href="#Url.Action("BannerSlideNewModal", "Account", new { Model.Id })" data-target="#modal-dlg" target="profile-banner">Add</a>
</div>
On form submit, after data processing, I hide current dialog:
form.submit(function() {
button.attr('disabled', true).text('Please wait ...');
// call service to update/add record
if ($(this).valid()) {
$(this).ajaxSubmit(
{
success: function(data) {
.....
$('#' + context.id).modal('hide');
}
});
});
The problem is, when I open modal dialog again, I want to see blank fields for new entry, but all fields are assigned from previous entry. How I can initialize each time new modal dialog instead of reusing same one?
Thanks.
Just reset your form with reset():
form.submit(function() {
button.attr('disabled', true).text('Please wait ...');
// call service to update/add record
if ($(this).valid()) {
$(this).ajaxSubmit(
{
success: function(data) {
.....
$('#' + context.id).modal('hide');
form.reset();
}
});
});

Categories

Resources