I want to duplicate the behavior for uploading images in Slack in my chat app.
Currently, you can click a button in the area where you enter a message, and that brings up a modal where you can drag and drop files using Dropzone.js. That’s great.
However, I also want the entire page (document body) to be a dropzone as well. So when you drag a file onto the screen, I want the previously mentioned modal to pop up, with the dragged file loaded.
I tried adding this to the bottom of the page, but no dice:
<script>
// Make whole page a dropzone for image uploads
new Dropzone("#body", { // Make the whole body a dropzone
url: "/upload/url", // Set the url
previewsContainer: "#modal-image-uploads .modal-body #previews" // Define the container to display the previews
});
Dropzone.options.filedrop = {
init: function () {
this.on("complete", function (file) {
if (this.getUploadingFiles().length === 0 && this.getQueuedFiles().length === 0) {
$('body').append("<%= escape_javascript(render :partial => 'rooms/modals/image_uploads') %>");
}
});
}
};
</script>
The error in the console is: Uncaught Error: Invalid previewsContainer option provided. Please provide a CSS selector or a plain HTML element.
Here's what the modal looks like:
<div class="modal fade" id="modal-image-uploads" tabindex="-1" role="dialog">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title">Upload Image</h4>
</div>
<div class="modal-body">
<div id="previews" class="dropzone-previews"></div>
<form action="/file-upload"
class="dropzone"
id="my-awesome-dropzone"></form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
</div>
</div>
</div>
</div>
Related
Issue
Toggling a modal with Javascript from another modal creates a conflict with the .modal-backdrop. Solutions I have thought of require me to make some functions to count .modal-backdrop but it breaks Bootstrap's native modal-dismiss behavior. I think maybe there could be better way that incorporates Bootstrap's native CSS (fade, etc.) without additional functions?
Here is my current working example
Ultimate Goal
Create a modal that can toggle another modal while retaining Bootstrap's default CSS. Also eliminate .modal-backdrop from creating more than one instance.
Background
I am creating a "parent" form that can be built dynamically (with JQuery) based on user input. Two sections of the form, "Add System" and "Add Circuit", will require an additional "child" form that will be placed inside a modal, outside the scope of the parent form (This helps avoid nesting one form inside the parent form). The reason I want to separate the user inputs from the parent and child forms is because the child form inputs may have different JQuery validation rules than the parent form (i.e., the data is not required to create a CSD, but if you want to add a system/circuit then I want to make sure you give me all the necessary data to create those objects). If a user wants to Add a system or a circuit:
they click the "Add System/Circuit" button where the 1st modal appears.
The user is prompted with a form to search for an existing one or create a new one.
If the user decides to "Add New System/Circuit", then a different modal appears.
The user is prompted with a form to enter the relevant data.
Here is my javascript function creating the modals. I am generating the modal dynamically based on the option the user chooses. One thing to note, since I am creating these modals in the same function, I want to make sure my function deletes the existing modal content too. (That's why I added the line
if (modalWrap !== null) {
modalWrap.remove()
}
at the beginning of my function)
var modalWrap = null
function create_dynamic_csd_modal(modal_type, section_type) {
if (modalWrap !== null) {
modalWrap.remove()
}
modalWrap = document.createElement("div")
if (modal_type == "new") {
if (section_type == "system") {
var modalContent = `
<div class="modal-header">
<h1 class="modal-title">Add New System</h1>
</div>
<div class="modal-body" style="height: 50vh;">
[...]
</div>
`
} else if (section_type == "circuit") {
var modalContent = `
<div class="modal-header">
<h1 class="modal-title">Add New Circuit</h1>
</div>
<div class="modal-body" style="height: 50vh;">
[...]
</div>
`
}
modalWrap.innerHTML = `
<div class="modal fade csd-add-new-${section_type}" tabindex="-1">
<div class="modal-dialog modal-dialog-centered modal-dialog-scrollable modal-xl">
<div class="modal-content">
<form
action='/ajax/csd_add_new_${section_type}/'
method='POST'
class="csd-add-new-${section_type}"
novalidate
>
${modalContent}
<div class="modal-footer">
<button
class="btn btn-warning cancel"
type="reset"
data-bs-dismiss="modal"
>
Cancel
</button>
<button
class="btn btn-secondary previous"
type="button"
>
Previous
</button>
<button
class="btn btn-danger"
type="button"
>
Add
</button>
</div>
</form>
</div>
</div>
</div>
`
} else {
if (section_type == "system") {
var modalContent = `
<div class="modal-body mt-4">
[...]
</div>
`
} else if (section_type == "circuit") {
var modalContent = `
<div class="modal-body mt-4">
[...]
</div>
`
}
modalWrap.innerHTML = `
<div class="modal fade csd-add-existing-${section_type}" tabindex="-1">
<div class="modal-dialog modal-dialog-centered modal-lg">
<div class="modal-content">
<form
action='/ajax/csd_add_existing_${section_type}/'
method='POST'
class="csd-add-existing-${section_type}"
novalidate
>
${modalContent}
<div class="modal-footer">
<button
class="btn btn-warning cancel"
type="reset"
data-bs-dismiss="modal"
>
Cancel
</button>
<button
class="btn btn-danger"
type="submit"
>
Add
</button>
</div>
</form>
</div>
</div>
</div>
`
}
document.body.append(modalWrap)
var modal = new bootstrap.Modal(modalWrap.querySelector(".modal"))
modal.show()
if ($(".modal-backdrop").length >= 1) {
$(".modal-backdrop").not(":first").remove()
}
}
$(document).on(
"click",
"form.create-csd-series button.add-system, form.create-csd-series button.add-circuit, form.csd-add-existing-system button.add-system, form.csd-add-existing-circuit button.add-circuit",
function(e) {
var button = this
var modal_type = null
if (button.classList.contains("add-system")) {
var section_type = "system"
} else if (button.classList.contains("add-circuit")) {
var section_type = "circuit"
}
if (button.closest(".modal") !== null) {
modal_type = "new"
}
create_dynamic_csd_modal(modal_type, section_type)
},
)
The idea is once the data inside the "child" form is entered and the user clicks "Add" in the modal - the data from this form will populate the parent form in a consolidated view. All the inputs' attributes (like name='some_input_name', id='some_input_id', etc.) from the child form will be transposed into the parent form that match validation rules for it. The user could then edit/delete that data before submitting the parent form to the server. (something like this).
I am using a bootastrap modal inside a .Net MVC Razor page which uses Vue JS
The modal popup is initiated with a button click event like below
<div>
<button type="button" class="btn" v-on:click="rejectModal(item)">Reject Popup</button>
</div>
rejectModal: function (item) {
this.selectedItemReject = item; //set a property
console.log(this.selectedItemReject);
$('#declineModal').modal('show'); //show modal
},
This shows the popup and text area to enter a comment and when i am trying to click on SAVE Button , The click event seems to be not firing. I am planning to add the notes property to selectedItemReject object and proceed with an ajax call and hide popup on SAVE button click. But no idea why the button click event is firing
<div class="modal fade" id="declineModal" tabindex="-1" role="dialog" aria-labelledby="declineModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title" id="declineModalLabel">Decline Note</h4>
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
</div>
<div class="modal-body">
<textarea name="decline-notes" v-model="rejectNote" placeholder="Add a note..." rows="4" class="form-control"></textarea>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button class="btn btn-primary" v-on:click="reject">SAVE</button>
</div>
</div>
</div>
</div>
reject: function () {
console.log("reject"); // NOT FIRING
}
Based on some suggestions already tried removing data-dismiss="modal" from close button , but no differece
I followed a great little solution over at CodeProject for injecting partial views into bootstrap modals with no explicit ajax calls required...
https://www.codeproject.com/Tips/826002/Bootstrap-Modal-Dialog-Loading-Content-from-MVC-Pa
In a nutshell, the author does this (UPDATE: I have added modal-dialog, which the author doesn't do but is required):
_Layout
<div id="modal-container" class="modal fade" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content"></div>
</div>
</div>
<script>
$('body').on('click', '.modal-link', function (e) {
e.preventDefault();
$(this).attr('data-target', '#modal-container');
$(this).attr('data-toggle', 'modal');
});
</script>
UPDATE - Here's the _Partial
<div class="modal-header">
</div>
<div class="modal-body">
</div>
<div class="modal-footer">
</div>
... and by doing so makes any link with class="modal-link" inject its result to the modal automatically.
Seems wonderfully simple and elegant, but just one problem: The data-target he specifies is the <div id="modal-container">. Really? Why? The content should be injected into the <div class="modal-content">, shouldn't it? But nearly everyone has no problem, and no one mentions this conundrum. For me, the solution does exactly what he's told it to, it injects into <div id="modal-container">, thereby overwriting <div class="modal-content"> with my modal-body, etc. that are the contents of my partial view, so the display is messed up -- full width of the window and transparent, because it's not going into the modal-content.
Am I missing something here?
UPDATE
One of Stom's answers below is correct (I've marked it). However, as I've shown in updates above, I actually already had the <div class="modal-dialog" role="document"> in the _Layout and <div class="modal-header">, body, and footer in the _Partial. Ultimately, after this issue persisted for days, I woke up today and it just started working with no changes! Seriously? Frustrating. The problem previously was that the data-toggle was causing it to actually inject into the #modal-container, not the .modal-content. But now it started to function as Stom says the documentation says, which is that even though you set the data-toggle as the #modal-container, Bootstrap should inject it into the .modal-content. Why that was not happening before but is now, I haven't the foggiest. I haven't upgraded versions overnight or anything. Ghost problem ---
The content should be injected into the ,
shouldn't it?
Before version 3.1 it should be injected root element of modal i.e your modal-container But on version 3.1 it has changed. And now the bootstrap docs says it will be injected in modal-content.
modal-content with my modal-body, etc. that are the
contents of my partial view, so the display is messed up , Why?
Because your partial view should contain modal-body and not modal-content.
Also Adding modal-dialog inside model root element solves the syling issue.
So below setup should work for you:
Action Methods
public ActionResult Index()
{
return View();
}
public ActionResult GetPartialData()
{
return PartialView("_ExamplePartial");
}
Index View
<!-- Button trigger modal -->
<a data-toggle="modal" href="#Url.Action("GetPartialData","Home")" data-target="#myModal">Click me</a>
<!-- Modal -->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
</div>
</div>
</div>
_ExamplePartial View
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Modal title</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<h1>Remote Partial Content</h1>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary">Save changes</button>
</div>
Note:
This option is deprecated since v3.3.0 and has been removed in v4.
Reference:
1.
2.
Below Setup should work to inject partial view content into modal body and it doesn't mess up with your default bootstrap modal style.
Action Methods
public ActionResult Index()
{
return View();
}
public PartialViewResult GetSomeData()
{
System.Threading.Thread.Sleep(2000); // Just to show delay to Get data
ViewBag.Message = "Example Data from Server"; //Using ViewBag Just for example, use ViewModel Instead
return PartialView("~/Views/Shared/_ExamplePartial.cshtml");
}
Index View
<!-- Button trigger modal -->
<button type="button" class="btn btn-primary" id="btnGetData">
Get Modal With Partial
</button>
<!-- Modal -->
<div class="modal fade" id="myModal" 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">Modal title</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="partialViewContent">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary">Save changes</button>
</div>
</div>
</div>
</div>
_ExamplePartial View
<h2>Partial View Contents</h2>
<h3>#ViewBag.Message</h3>
<p>Some More Static Content</p>
Script:
<script>
$(document).ready(function () {
$('#btnGetData').click(function () {
var requestUrl = '#Url.Action("GetSomeData", "Home")';
$.get(requestUrl)
.done(function (responsedata) {
console.log("success");
$("#partialViewContent").html(responsedata);
$('#myModal').modal('show')
})
.fail(function () {
alert("error");
})
.always(function () {
console.log("finished");
});
})
});
</script>
I'm trying to display a modal dialog when data is submitted on my create view. I need the modal to force the submit to wait for user confirmation on the modal dialog. Then the data needs to be submitted. Below is my create view code using bootstrap 3.0 modal-dialog:
<div class="form-group">
#Html.LabelFor(model => model.Name, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Name)
#Html.ValidationMessageFor(model => model.Name)
</div>
</div>
<div class="col-md-offset-2 col-md-10">
<input id="create" type="submit" value="Create" class="btn btn-default"/>
</div>
</div>
<div id="modalBox" class="modal">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<a class="close" data-dismiss="modal">X</a>
<h1>Confirmation</h1>
</div>
<div class="modal-body">
<h6>Click YES to confirm</h6>
</div>
<div class="modal-footer">
<button id="noPost" class="btn btn-default" name="postConfirm" value="false" data-dismiss="modal">No Thanks</button>
<button id="yesPost" class="btn btn-primary" name="postConfirm" value="true" data-dismiss="modal">YES</button>
</div>
</div>
</div>
#section scripts{
<scripts>
$(function () {
var modalBox = function (e) {
e.preventDefault();
$("#modalBox").modal({ show: true });
};
$("#create").click(modalBox);
});
<scripts>
}
This does interrupt the submit function and brings up the modal dialog but I don't know how to submit the data back to the controller once a selection is made on the dialog. I have also tried using the jquery ui modal dialog with the script below:
<script>
$("#create").click(function (e) {
e.preventDefault();
$("#postModal").dialog("open");
});
$("#postModal").dialog({
autoOpen: false,
width: 400,
resizable: false,
modal: true,
buttons: {
"No Thanks": function (data) {
$("#create").submit();
$(this).dialog("close");
},
"YES": function () {
$("#create").submit();
$(this).dialog("close");
}
}
});
</script>
This does bring up the modal dialog but I still can't get it to submit the model data back to the controller. Any help would be appreciated.
UPDATE
By inspecting the produced html I discovered my input fields resided within a form that I didn't put there. I suspect this is due to me using the #Html.ValidationSummary(true) or something built into MVC. So instead of using:
$("#create").submit();
I used:
$("form:first").submit();
To submit the first, and only form, on the page and it worked!
Change your create button type to type=button, and make it to just open modal view. And make your yespost button in modal div holder to type submit . Also you can try to put whole modal div holder inside your form-group div. Here you are making post before openning modal view. It s because your button have 2 logic task, separate those task and this should work.
I have a bootstrap modal dialog that is inside a form. The form is submitted via AJAX. I want the submit button to also dismiss the modal (otherwise i end up with the modal overlay remaining)
Code for the modal is:
#using (Ajax.BeginForm("SaveConfiguredReport", new AjaxOptions { HttpMethod = "POST", InsertionMode = InsertionMode.Replace, UpdateTargetId = "report-details", OnBegin="preProcessing" }))
{
<div class="modal fade" id="add-filter-dialog" tabindex="-1" role="dialog" aria-labelledby="add-filter-dialog" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h4>Add a Filter</h4>
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
</div>
<div class="modal-body">
<p>Adding filters allows you to sort what data will be included in the report. These filters will be default for all ongoing usage of this report.</p>
<div id="field-templates"></div>
<input type="hidden" id="field-template-id" name="FieldTemplateID" />
#Html.DropDownList("OperatorID", Model.Operators.Select(x => new SelectListItem { Text = x.Name, Value = x.OperatorID.ToString() }))
<input type="text" name="FilterValue" class="typeahead" id="filter-value" />
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button type="submit" class="btn btn-success" data-dismiss="modal" name="Command" value="Add">Add Filter</button>
</div>
</div>
</div>
</div>
}
<!-- other code -->
<script>
function preProcessing() {
$('.modal').each(function (index, element) {
$(element).modal('hide');
});
}
</script>
If i keep the data-dismiss attribute on the submit button, it will dismiss the form but not submit it. If i remove it, the form will be submitted but not dismissed. Anyone had any luck with this?
EDIT
I have added a pre-processor to the AJAX call to hide all forms at the start. Hiding them at the end did not work because the form was replacing the modal but not the overlay. This is a workaround until a proper solution is suggested
What I usually do is close it via Javascript after the form has been validated and AJAX post/get was successful.
$('#add-filter-dialog').modal('hide');
See more options here http://getbootstrap.com/javascript/#modals-usage