I meet an error on class reactivity and dot not find solution despite a lot of tests.
I modify data with local methods and it work but, application on this DOM (reactivity), does not exceed one. After one modification, the DOM is figed.
I use an Vue extend, i use $set to define value of attribute (because the extend of vue use an return object) or direct access, but the result always the same.
Do you have an idea ?
Thanks in advance.
Jérémy
It's an exemple of code (i use webpack to build my vue app, javascript script separate to html).
<div id="modalMemberEdit" class="modal fade modalmember" v-bind:class="{ 'in':showmodal }" role="dialog" v-bind:style="{'display':displaymodal,'border':bordermodal}">
<div class="modal-dialog">
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" v-on:click="hideModal">×</button>
</div>
<div class="modal-body">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-rouge" v-on:click="hideModal" ></button>
</div>
</div>
</div>
</div>
const modalMemberEdit = Vue.extend({
name: "modalMember",
data: function () {
return {
displaymodal: "none",
bordermodal: "15px solid white",
showmodal: false,
}
},
methods: {
showEditModal: function( id ) {
this.$set(this._data,"showmodal",true);
this.$set(this._data,"displaymodal","block");
},
hideModal: function() {
this.$set(this._data,"showmodal",false);
this.$set(this._data,"displaymodal","none");
}
},
mounted: function() {
this.$set(this._data,"showmodal",true);
this.$set(this._data,"displaymodal","block");
}
});
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 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 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>
I have some strange issue. I use an carousel from bootstrap ui in a modal box from bootstrap. At the beginning is init the images for the carousel. Then i click on a button to show the modal box. This time they appear correctly. But then i reinit the carouseldata (Switch to other data) and open the carousel again and then he is empty. Is there an possible solution for this?
Here you can a example of it: http://plnkr.co/edit/YASfl9nF0cxqlytFjjI0?p=preview
Click first on click me and then you see the modal box. Close the modal box and switch from data and open it again.
<div class="modal fade" id="modal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" 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="myTalkModalLabel">Title</h4>
</div>
<div class="modal-body">
<carousel interval="myInterval">
<slide ng-repeat="slide in getImages()">
<img ng-src="slide.image" />
</slide>
</carousel>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
var app = angular.module('plunker',['ui.bootstrap']);
app.controller('MainCtrl', function($scope) {
$scope.myInterval = 2000;
$scope.images = ["http://nautisme.nc/photos.nautisme.nc/201410/o_193fo6a4ckel17ml1bvif3lo9ki.jpg","http://nautisme.nc/photos.nautisme.nc/201410/o_193fo6a4c1t8t79i15qo99l1jqlj.jpg","http://nautisme.nc/photos.nautisme.nc/201410/o_193fo6a4davv1tplqkf24f1h4vk.jpg"];
var images2 = ["http://nautisme.nc/photos.nautisme.nc/201410/o_193fo6a4dg9gqgvt6o60l8dl.jpg","http://nautisme.nc/photos.nautisme.nc/201410/o_193fo6a4d59tal51dkp1ask69nm.jpg","http://nautisme.nc/photos.nautisme.nc/201410/o_193fo6a4e6st4vcoqii8r1vpgn.jpg","http://nautisme.nc/photos.nautisme.nc/201410/o_193fo6a4e184m10d46264i4buto.jpg"];
$scope.getImages = function(){
return $scope.images;
}
$scope.showModal = function(){
$("#modal").modal("show");
}
$scope.showModal = function(){
$('#modal').modal('show');
}
$scope.switchImages = function(){
var temp = $scope.images;
$scope.images = images2;
images2 = temp;
}
});
Updated Plunker
The main issue is that you're trying to use Bootstrap's jQuery-based plugins (bootstrap.js) in your AngularJS app along with UI-Bootstrap. I swapped your modal for the UI-Bootstrap modal implementation. UI Bootstrap has no dependency on the bootstrap.js, or jQuery for that matter, so I removed both from the page <head> to avoid conflicts.
Maybe it was just a typo in the Plunker but, I also needed to fix the ng-repeat in the carousel. Where you had slide in getImages(), I removed the function and referenced $scope.images with image in images. Further, since $scope.images is an array of image urls, to access them, you just use the expression: {{image}}.
<carousel interval="myInterval">
<slide ng-repeat="image in images track by $index">
<img ng-src="{{image}}" style="width: 100%;" />
</slide>
</carousel>
APP JS:
var app = angular.module('plunker',['ui.bootstrap']);
app.controller('MainCtrl', function($scope, $modal) {
var images2 = ["http://placehold.it/500x300/009999/fff&text=Group%202:%20Image%201", "http://placehold.it/500x300/009999/fff&text=Group%202:%20Image%202", "http://placehold.it/500x300/009999/fff&text=Group%202:%20Image%203"];
$scope.myInterval = 10000;
$scope.images = ["http://placehold.it/500x300/e8117f/fff&text=Group%201:%20Image%201","http://placehold.it/500x300/e8117f/fff&text=Group%201:%20Image%202"];
$scope.open = function (size) {
var modalInstance = $modal.open({
templateUrl: 'myModalContent.html',
controller: 'ModalInstanceCtrl',
size: size,
resolve: {
imgs: function () {
return $scope.images;
}
}
});
};
$scope.switchImages = function(){
var temp = $scope.images;
$scope.images = images2;
images2 = temp;
};
});
app.controller('ModalInstanceCtrl', function ($scope, $modalInstance, imgs) {
$scope.images = imgs;
$scope.cancel = function () {
$modalInstance.dismiss('cancel');
};
});
MARKUP:
<button class="btn btn-primary" ng-click="open()">Launch Modal</button>
<button class="btn btn-primary" ng-click="switchImages()">Switch Image Group</button>
<script type="text/ng-template" id="myModalContent.html">
<div class="modal-header">
<h3 class="modal-title">Title</h3>
</div>
<div class="modal-body">
<carousel interval="myInterval">
<slide ng-repeat="image in images track by $index">
<img ng-src="{{image}}" style="width: 100%;" />
</slide>
</carousel>
</div>
<div class="modal-footer">
<button class="btn btn-warning" ng-click="cancel()">Close</button>
</div>
</script>
I want to show modal(encouragementModal) only when user clicks on Encourage button.
Configuration
GSP View _encourage.gsp is :
<div ng-controller="EncouragementController">
<g:if test="${notEncouraged}">
<button class="btn" ng-click="openEncouragementModal()">Encourage</button>
<div modal="encouragementModal" close="closeEncouragementModal()" options="opts">
<div class="modal-header">
<h3>Encourage!</h3>
</div>
<div class="modal-body">
You are about to encourage with {{amount}}.
</div>
<div class="modal-footer">
<button class="btn btn-info cancel" ng-click="encourage()">Confirm</button>
<button class="btn btn-warning cancel" ng-click="close()">Cancel</button>
</div>
</div>
</g:if>
<g:else>
Thank you for encouraging.
</g:else>
The EncouragementController.js is
function EncouragementController($scope, $http) {
/**
* open payment dialog
*/
$scope.openEncouragementModal = function (amount) {
$scope.encouragementModal = true;
};
$scope.closeEncouragementModal = function () {
$scope.closeMsg = 'You canceled the encouragement’;
$scope.encouragementModal = false;
};
$scope.opts = {
backdropFade: true,
dialogFade:true
};
}
EncouragementController.$inject = [ '$scope', '$http'];
Question
Only the Encourage button should have been visible for the first time, but what I see is button along with the encouragementModal and it's buttons.
So, how do I do that?
References I followed
[1] Modal (ui.bootstrap.modal)
[2] Simple Grails + AngularJS Example
You need to hide it at first and only display it when scope.encouragementModal value is true.
<div modal="encouragementModal" ng-show="encouragementModal" options="opts">