Submit Form in Bootstrap Modal with IronRouter / MeteorJS - javascript

I am trying to submit a new appetizer to a web app I am creating that resembles a cookbook. The layout has a constant header/nav that allows the user to add a new appetizer, which triggers a modal and a form containing the appetizer name, description and a photo. I would like the modal to close upon submission, and remain on the current page of which the modal was triggered. Currently, my submit form is not working and I am not sure where the problem is...
The link to the current deployed version is: http://reed-cookbook.meteor.com/
My router:
// lib/router.js
Router.configure({
layoutTemplate: 'layout'
});
Router.map(function() {
this.route('allRecipes', {
path: '/'
});
this.route('appetizers', {
path: '/appetizers'
});
this.route('appetizerPage', {
path: '/appetizers/:_id',
data: function() { return Appetizers.findOne(this.params._id); }
});
this.route('desserts', {
path: '/desserts'
});
this.route('mainCourses', {
path: '/maincourses'
});
this.route('submit', {
path: '/appetizerSubmit'
});
});
My appetizer html form:
// client/views/forms/appetizerForm.html
<template name="appetizerForm">
<!-- This is the appetizer modal -->
<div class="modal fade" id="myAppModal" 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" aria-label="Close"><span aria-hidden="true">×</span></button>
<h4 class="modal-title" id="myModalLabel">Add An Appetizer</h4>
</div>
<div class="modal-body">
<!-- This is the appetizer form -->
<form>
<div class="form-group">
<label for="inputNewLabel">Name</label>
<input type="text" class="form-control" id="addNewAppetizer" name="appName" placeholder="What is the name of this appetizer?">
</div>
<div class="form-group">
<label for="inputNewLabel">Description</label>
<input type="text" class="form-control" id="addNewAppDesc" name="appDesc" placeholder="Share details about your appetizer.">
</div>
<div class="form-group">
<label for="inputNewLabel">Add Photo</label>
<input type="file" id="addNewAppPic" name="appPic">
<p class="help-block">Upload a photo of your appetizer.</p>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button type="submit" class="btn btn-primary" value="submitApp">Submit Appetizer</button>
</div>
</div>
My appetizerForm.js for this specific html feature:
// client/views/forms/appetizerForm.js
Template.appetizerForm.events({
'submitApp': function(e) {
e.preventDefault();
var appetizer = {
name: $(e.target).find('[name=appName]').val(),
description: $(e.target).find('[name=appDesc]'),
photo: $(e.target).find('[name=appPic]').val()
}
appetizer._id = Appetizers.insert(appetizer);
Router.go('/', appetizer);
}
});

Your event map syntax is wrong, it must be eventType cssSelector.
Template.appetizerForm.events({
"submit form": function(event, template) {
event.preventDefault();
[...]
template.$(".modal").modal("hide");
}
});
If you want the modal to close upon form submission, use the jQuery plugin syntax to call the hide method on the modal.

Related

How can I validate a form inside a Bootstrap modal?

I have a list of items, every row has it's own "action" buttons. One of the actions is editing the record, the other one shows a list of related records (loaded dynamically via an Ajax call), and so on. When the modal opens, the respective ID for the record will be passed to the modal as well.
For each row, when user clicks on the button, a Bootstrap modal will appear, with respective content (as I mentioned, dynamically from the server). The issue is, I cannot validate the forms for edit nor related records. Here is the code snippet I used for building the recordset:
<span class="openRecordsModalBtn" id="7">Records</span>
<span class="openEditModalBtn" id="7">Edit</span>
Modal:
<div class="modal fade" id="editModal" role="dialog" tabindex="-1">
<div class="modal-dialog modal-lg modal-dialog-scrollable" role="document">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">Edit record</h4>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline-secondary" data-dismiss="modal"> Close</button>
</div>
</div>
</div>
</div>
<div class="modal fade bd-example-modal-lg" id="recordModal" role="dialog" tabindex="-1">
<div class="modal-dialog modal-lg modal-dialog-scrollable" role="document">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">Releted records</h4>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline-secondary" data-dismiss="modal"> Close</button>
</div>
</div>
</div>
</div>
The content of the modal generates by ajax (it is a simple HTML form). Here is the Javascript I used for calling the Ajax script and pass record ID to the modal:
$(document).ready(function() {
$('.openRecordsModalBtn').on('click',function(){
var id = $(this).attr('id');
$('.modal-body').load('/ajax/record.php?id=' + id, function(){
$('#recordModal').modal({show:true});
})
})
});
$(document).ready(function() {
$('.openEditModalBtn').on('click',function(){
var id = $(this).attr('id');
$('.modal-body').load('/ajax/edit.php?id=' + id, function(){
$('#editModal').modal({show:true});
})
})
});
My guess is, by the time page loads, the form has not been generated yet. Therefore, validation cannot be done. How can I validate the form created by the Ajax call?
This is the validation function:
document.addEventListener('DOMContentLoaded', function(e) {
FormValidation.formValidation(
document.getElementById('edit-form'),
{
fields: {
name: {
validators: {
notEmpty: {
message: 'Please provide a name.'
}
}
}
},
plugins: {
trigger: new FormValidation.plugins.Trigger(),
bootstrap: new FormValidation.plugins.Bootstrap(),
submitButton: new FormValidation.plugins.SubmitButton(),
defaultSubmit: new FormValidation.plugins.DefaultSubmit(),
icon: new FormValidation.plugins.Icon({
valid: 'fa fa-check',
invalid: 'fa fa-times',
validating: 'fa fa-refresh'
}),
},
});
});
Why are you mixing JQuery and javascript? You should only be using one $(document).ready(function(). I believe to make this work, you need to use event delegation. Haven't tested this but hopefully something like this will work for you. Substitute document with the closest static parent element of the modals.
$(document).on('shown.bs.modal', '#recordModal', '#editModal', function(e) {
FormValidation.formValidation(
document.getElementById('edit-form'), {
fields: {
name: {
validators: {
notEmpty: {
message: 'Please provide a name.'
}
}
}
},
plugins: {
trigger: new FormValidation.plugins.Trigger(),
bootstrap: new FormValidation.plugins.Bootstrap(),
submitButton: new FormValidation.plugins.SubmitButton(),
defaultSubmit: new FormValidation.plugins.DefaultSubmit(),
icon: new FormValidation.plugins.Icon({
valid: 'fa fa-check',
invalid: 'fa fa-times',
validating: 'fa fa-refresh'
}),
},
});
});
This explains about the modal events.

Uncaught RangeError: Maximum call stack size exceeded and [Violation] 'click' handler took

I checked other post like this but honestly I don't find a solution. I have a button "test", and when I hit the button theoretically I gotta open up a new window showing a query result but, I'm getting this error and honestly I'm not understanding why!
In item_action.php I wrote this code just for test:
if ($_POST['btn_action'] == 'item_view') { //View Item details
echo "test";
}
Below the code in the javascript file
//OPEN DETAIL ITEM WINDOW IN MODE VIEW
$('#test').on('click', function() {
//var item_id = $(this).attr("id");
//Declare 2 vars
var item_id = 3;
var btn_action = 'item_view';
$('#productModalView').modal('show');
$.ajax({
url: "item_action.php",
method: "POST",
data: {
product_id: product_id,
btn_action: btn_action
},
success: function(critto) {
$('#itemview').html(critto);
},
error: function() {
$('<div>').html('Found an error!');
}
});
});
<div id="productModalView" class="modal fade">
<div class="modal-dialog">
<form method="post" id="product_form_view">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title"><i class="fa fa-plus"></i>Item Product</h4>
</div>
<!-- Close Modal Header -->
<div class="modal-body">
<div id="itemview"></div>
</div>
<!-- Close Modal Body-->
<div class="modal-footer">
<input type="hidden" name="product_id" id="product_id" />
<input type="hidden" name="btn_action" id="btn_action" />
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
<!-- Close Modal Footer -->
</div>
<!-- Close Modal Content -->
</form>
<!-- Close Form -->
</div>
<!-- Close Modal-Dialog -->
</div>
<!-- Close Product Modal -->
Any idea how to fix it???

Set focus on a input control contained in a second level bootstrap modal

I'm using Vue.js 2.1.10 and Bootstrap 3.3.7 to show a modal that opens another modal dialog. Each modal dialog is contained in a distinct component. Inside the 1st component, there is a reference to the 2nd component (select-travler).
According to the Bootsrap documentation, I have to set the focus by listening to the event shown.bs.modal. This works great to set the focus on an input control contained in the 1st modal. Problem: this way doesn't work when the modal is above another modal.
The 1st modal component looks like this:
<template>
<div ref="tripEdit" class="modal fade" role="dialog">
<!-- Inbeded component -->
<select-travler ref="selectTravler"></select-travler>
<!-- /Inbeded component -->
<div class="modal-lg modal-dialog">
<div class="modal-content">
<div class="modal-body container form-horizontal">
<div class="form-group">
<label for="travler_name" class="control-label">
Travler's name
</label>
<input id="travler_name" ref="travler_name"
v-model="travler_name"/>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data () {
return {
travler_name: null,
}
},
methods: {
show (operationType) {
$(this.$refs.tripEdit).modal('show');
let that = this;
$(this.$refs.tripEdit).on('shown.bs.modal', function () {
$(that.$refs.travler_name).focus();
});
if (operationType === 'newTravel') {
this.$refs.selectTravler.show();
}
},
},
}
</script>
The 2nd component contains a similar layout with the following show method:
show () {
$(this.$refs.selectTravler).modal('show');
let that = this;
$(this.$refs.selectTravler).on('shown.bs.modal', function () {
$(that.$refs.people_names).focus();
});
},
When the 2nd modal opens, the focus is still on the 1st modal behind the 2nd modal dialog (I can see the caret blinking in travler_name). How can I set the focus on people_names when the 2nd modal is shown?
I think there are really several issues at play here. First, as I mentioned in the comment above, you are not properly adding and removing the shown.bs.modal event handlers.
Second, because your second modal is nested inside the first modal, the shown.bs.modal event will bubble up to the parent modal and it's handler will fire. Initially I thought stopPropagation would be a good way to handle this, but in the end, I simply de-nested the submodal component in the template.
Here is an example of this behavior actually working.
console.clear()
Vue.component("sub-modal", {
template: "#submodal",
methods: {
show() {
$(this.$el).modal("show")
},
onShown(event) {
console.log("submodal onshown")
this.$refs.input.focus()
}
},
mounted() {
$(this.$el).on("shown.bs.modal", this.onShown)
},
beforeDestroy() {
$(this.$el).off("shown.bs.modal", this.onShown)
}
})
Vue.component("modal", {
template: "#modal",
methods: {
show() {
$(this.$refs.modal).modal("show")
},
showSubModal() {
this.$refs.submodal.show()
},
onShown(event) {
console.log("parent")
this.$refs.input.focus()
}
},
mounted() {
$(this.$refs.modal).on("shown.bs.modal", this.onShown)
},
beforeDestroy() {
$(this.$refs.modal).off("shown.bs.modal", this.onShown)
}
})
new Vue({
el: "#app",
})
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://unpkg.com/vue#2.2.6/dist/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
<div id="app">
<modal ref="modal"></modal>
<button #click="$refs.modal.show()" class="btn">Show Modal</button>
</div>
<template id="submodal">
<div class="modal fade" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<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">Modal title</h4>
</div>
<div class="modal-body">
<input ref="input" type="text" class="form-control">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary">Save changes</button>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->
</template>
<template id="modal">
<div>
<div ref="modal" class="modal fade" tabindex="-1" role="dialog">
<div class="modal-dialog modal-lg" role="document">
<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">Modal title</h4>
</div>
<div class="modal-body">
Stuff
<input ref="input" type="text" class="form-control">
</div>
<div class="modal-footer">
<button #click="showSubModal" type="button" class="btn btn-primary">Show Sub Modal</button>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->
<sub-modal ref="submodal"></sub-modal>
</div>
</template>
Also, for future readers, I got some useful information about how to construct the template for the modal component used above from this answer. Specifically, unless you manually specify a z-index for the modal, the modal that appears last in HTML will have a higher z-index. The implication being the submodal component needs to come second in the template.
I ran into a similar issue. A b-modal forces focus to stay in the modal. You can disable it by adding a no-enforce-focus attribute.
no-enforce-focus Boolean false Disables the enforce focus routine
which maintains focus inside the modal
https://bootstrap-vue.org/docs/components/modal
This means that the element you're trying to focus is not properly referenced.
Trying to console.log(element); the line before focussing people_names. To see if you're getting the right element.
show () {
$(this.$refs.selectTravler).modal('show');
let element = this.$refs.people_names;
$(this.$refs.selectTravler).on('shown.bs.modal', function () {
$(element).focus();
});
},
Have you considered v-show to open and close your modals ?

Converting Bootstrap 3 remote modal to Bootstrap 4 modal with parameters

So in the near future my shop is going to upgrade to Bootstrap 4 but we cannot do this until we solve the issue with using remote modals. Here is an example of how we load our modals. The reason we use remote modals is because the modal-body is dynamic and may use different file based on the url. I have heard that using jQuery("#newsModal").on("load",..) is an alternative but how could I do this? I found this but I am not sure how my anchor would look and how to build the url to load the remote data.
Global PHP include file:
<div id="NewsModal" class="modal fade" tabindex="-1" role="dialog" data-
ajaxload="true" aria-labelledby="newsLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h3 class="newsLabel"></h3>
</div>
<div class="noscroll-modal-body">
<div class="loading">
<span class="caption">Loading...</span>
<img src="/images/loading.gif" alt="loading">
</div>
</div>
<div class="modal-footer caption">
<button class="btn btn-right default modal-close" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
modal_news.php file:
<form id="newsForm">
<div id="hth_err_msg" class="alert alert-danger display-hide col-lg-12 col-md-12 col-sm-12 col-xs-12">
You have some errors. Please check below.
</div>
<div id="hth_ok_msg" class="alert alert-success display-hide col-lg-12 col-md-12 col-sm-12 col-xs-12">
✔ Ready
</div>
<!-- details //-->
</form>
Here is how we trigger the modals :
<a href="#newsModal" id="modal_sbmt" data-toggle="modal" data-target="#newsModal"
onclick="remote='modal_news.php?USER=yardpenalty&PKEY=54&FUNCTION=*GENERAL'; remote_target='#NewsModal .noscroll-modal-body'">
<span class="label label-icon label-info">
<i class="fa fa-bullhorn"></i>
</span>
Promotional Ordering
</a>
I think I need to do something like this when building anchor dynamically:
a) Replace paramters with data-attrs
b) Use the event invoker to get the data-attrs using event.target.id
Thanks to Tieson T. and this post I was able to effectively pass parameters to the remote modal using this technique except if you have multiple modals
I have also included some helpful techniques inside this example as to how you may pass parameters to the remote modal.
bootstrap_modal4.php:
<div class="portlet-body">
Add Attendee <i class="fa fa-plus"></i>
</div>
<!-- BEGIN Food Show Attendee Add/Edit/Delete Modal -->
<div id="attendee" class="modal fade" tabindex="-1" role="dialog" data-ajaxload="true" aria-labelledby="atnLabel" aria-hidden="true">
<form id="signupForm" method="post">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<label id="atnLabel" class="h3"></label><br>
<label id="evtLabel" class="h6"></label>
</div>
<div class="modal-body">
<div class="loading"><span class="caption">Loading...</span><img src="/images/loading.gif" alt="loading"></div>
</div>
<div class="modal-footer">
<span class="caption">
<button type="button" id="add_btn" class="btn btn-success add-attendee hidden">Add Attendee <i class="fa fa-plus"></i></button>
<button type="button" id="edit_btn" class="btn btn-info edit-attendee hidden">Update Attendee <i class="fa fa-save"></i></button>
<button type="button" id="del_btn" class="btn btn-danger edit-attendee hidden">Delete Attendee <i class="fa fa-minus"></i></button>
<button class="btn default modal-close" data-dismiss="modal" aria-hidden="true">Cancel</button>
</span>
</div>
</div>
</div>
</form>
</div>
<script>
jQuery(document).ready(function() {
EventHandlers();
});
function EventHandlers(){
$('#attendee').on('show.bs.modal', function (e) {
e.stopImmediatePropagation();
if($(this).attr('id') === "attendee"){
// Determines modal's data display based on its data-attr
var $invoker = $(e.relatedTarget);
var fscode = $invoker.attr('data-fscode');
console.log(fscode);
// Add Attendee
if($invoker.attr('data-atnid') === "add"){
$("#atnLabel").text("Add New Attendee");
$(".add-attendee").removeClass("hidden");
}
else{ //edit/delete attendee
$("#atnLabel").text("Attendee Maintenance");
$(".edit-attendee").removeClass("hidden");
}
//insert hidden inputs
//add input values for post
var hiddenInput = '<INPUT TYPE=HIDDEN NAME=FSCODE VALUE="' + fscode + '"/>';
$("#signupForm").append(hiddenInput);
}
});
$('#attendee').on('hidden.bs.modal', function (e) {
$(".edit-attendee").addClass("hidden");
$(".add-attendee").addClass("hidden");
$("#signupForm input[type='hidden']").remove();
});
// BOOTSTRAP 4 REMOTE MODAL ALTERNATIVE FOR BOOTSTRAP 3v-
$('#add-attendee').on('click', function(e){
$($(this).data("target")+' .modal-body').load($(this).data("remote"));
$("#attendee").modal('show');
});
}
</script>
bootstrap_remote_modal4.php:
<form id="signupForm">
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
Hello World!
</div>
</form>
<script>
$(document).ready(function(){
console.log('<?php echo $_GET["USERNAME"]?>'); //passed through url
});
</script>
NOTE: I am having problems with event propagation during the show.bs.modal event which I have a global show.bs.modal that is propagating up to this event handler due to multiple modals so if you have multiple modals make sure to handle them correctly.
Here is a screen shot of the results which clearly show propagation is taking place but the parameter passing techniques are working.
You might find it easier to use something like Bootbox.js, which can be used to dynamically create Bootstrap modals.
Given what you've shown, it would work something like:
trigger modal
with
$(function(){
$('.show-modal').on('click', function(e){
e.preventDefault();
var url = $(this).attr('href');
$.get(url)
.done(function(response, status, jqxhr) {
bootbox.dialog({
title: 'Your Title Here',
message: response
});
});
});
});
This assumes response is an HTML fragment.
Bootbox hasn't officially been confirmed to work with Bootstrap 4, but I haven't run into any problems with it yet (modals seem to be one of the few components that don't have updated markup in BS4).
Disclaimer: I am currently a contributor to Bootbox (mainly updating the documentation and triaging issues).
If you must use only the Bootstrap modal, you're actually after load(). You would probably do something like:
$(function(){
$('.show-modal').on('click', function(e){
e.preventDefault();
var url = $(this).attr('href');
var dialog = $('#NewsModal').clone();
dialog.load(url, function(){
dialog.modal('show');
});
});
});

fullcalendar bootstrap modal with external event data

I'm using full calendar with a asp.net MVC 5 application.
When I click a on a empty space I get a modal view for creating a event. This works perfect.
When I click on a event I want to get the event data but also some other data then just the start date end date and description.
I have the following:
eventRender: function (event, element) {
var id = event.id;
element.popover({
placement: 'top',
html: true,
content: '<button id="customers" class="btn btn-default" onclick="KlantenModal(' + id + ')">Klant overzicht</button>',
animation: true
});
}
The function that calls the modal.
function KlantenModal(event) {
$('#klanten #eventId').val(event);
$('#klanten').modal('show');
}
and the bootstrap modal:
<div class="modal fade" id="klanten" 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" aria-hidden="true">×</button>
<h4 class="modal-title" id="myModalLabel">Klanten</h4>
</div>
<div class="modal-body">
/* here I want some Data eg. names of customers */
<input type="hidden" id="eventId" name="eventId" />
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
<button type="submit" class="btn btn-primary"></button>
</div>
</div>
</div>
If i understood you well the only thing you have to do is to add fields to the event like this:
Somewhere in your code populate an array with diferent customers and add that array to the event properties
var customers = [];
customers.push("im customer x");
customers.push("im customer y");
...
events:[
{
'start': 2013-12-30,
'end': 2013-12-30,
'allDay': true,
'customers': customers
}
and when you click on the event and access the event fields you will get the customers field wich contains your customers for that day.

Categories

Resources