Blazor EditForm Submit handler not called when the form is in a bootstrap modal end the submit button is the modal dismissal command - bootstrap-modal

Let's consider the following page in a client side blazor app:
#page "/test"
<div id="modalDialog" class="modal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-body">
<EditForm Model="#model" OnSubmit="#SubmitHandler">
<div class="form-group d-flex justify-content-between">
<label class="col-form-label col-3" for="editDT">Time</label>
<InputText bind-Value="#model" id="editDT" Class="form-control" />
</div>
<button type="submit" class="btn btn-primary" #*data-dismiss="modal"*#>Submit</button>
</EditForm>
</div>
</div>
</div>
</div>
<button data-toggle="modal" data-target="#modalDialog" class="btn btn-primary">Open</button>
#functions {
private string model { get; set; } = "Model";
private void SubmitHandler()
{
Console.WriteLine("Submit");
}
}
When I click the Open button, the modal appears as expected. Then clicking on the Submit button in the modal, "Submit" gets printed in the browser console, again as expected.
But I need also to close the modal when I click Submit so I uncomment the data-dismiss attibute.
Now, the modal closes as expected, but the Submit handler is not called anymore (browser console remains empty).
1) Is this the expected behaviour?
2) If yes, is there a way to close the modal in the Submit handler without javascript interop?
3) If not, is there another way to both close the modal and have the Submit handler called when clicking on the Submit button, again without js interop?

Your biggest issue is using bootstrap as is. BS uses it’s own JS to manipulate the DOM, this won’t work with Blazor as Blazor needs to control the DOM. Same as Angular, React or Vue. If something else modifies the DOM then odd things can happen, as you’re finding.
I would suggest swapping to one of the Blazor-fied bootstrap libraries such as BlazorStrap. Or if you’re just after a modal I’ve written one called Blazored.Modal

To make the form submit inside the bootstrap modal do the following:
Give your form an id
<EditForm id="my-form-ref">
Then add attribute form to the submit button with the value of the form id
<button type="submit" class="btn btn-danger" form="my-form-ref">Submit Form</button>

I guess that dismiss="modal" is viable only if you use <button type="button"></button>, but this would not enable "submission of the form". To really solve this issue, I'd suggest you use the <form> tag
and <button type="button"> tag instead.
But a better solution is to follow what Chris Sainty suggested in his answer.
I may add that it doesn't seem to me a good practice to embed the Bootstrap dialog box in Blazor, when such object can easily implemented in Blazor...
Hence, I would suggest that you yourself create a dialog-box component, a templated one, perhaps based on the Bootstrap dialog box...After all, I guess that like all of us, you are in the learning phase of Blazor. So it can be a good exercise.
Hope this helps...

All good suggestions. However, for the sake of completeness, I found a way to achieve what I wanted, even if it is a not very elegant workaround:
#page "/test"
#using System.ComponentModel.DataAnnotations;
<div id="modalDialog" class="modal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-body">
<EditForm EditContext="#EC">
<DataAnnotationsValidator />
<ValidationSummary />
<div class="form-group d-flex justify-content-between">
<label class="col-form-label col-3" for="editDT">Time</label>
<InputText bind-Value="#model.Name" id="editDT" Class="form-control" />
</div>
#if (EC.Validate())
{
<button type="button" onclick="#SubmitHandler" class="btn btn-primary" data-dismiss="modal">Submit</button>
}
else
{
<button type="button" onclick="#SubmitHandler" class="btn btn-primary">Submit</button>
}
</EditForm>
</div>
</div>
</div>
</div>
<button data-toggle="modal" data-target="#modalDialog" class="btn btn-primary">Open</button>
#functions {
public class ModelClass
{
[Required]
public string Name { get; set; }
}
private ModelClass model { get; set; } = new ModelClass { Name = "My Name" };
private EditContext EC { get; set; }
private void SubmitHandler()
{
Console.WriteLine("Submit");
}
protected override void OnInit()
{
EC = new EditContext(model);
base.OnInit();
}
}

Related

How to identify button selected in cakephp 3.x?

I viewed the answer Which Submit Button was Clicked in CakePHP?. That situation doesn't apply to me, because I have the same action for each button.
I want to reuse a bootstrap modal and I want to know which item was selected when the modal was invoked. Very simply, I have a table with grades for each school object. When the user clicks the add button, I want to invoke the modal and add a grade for that object. I want to know which object was selected, because I want to reuse the modal for all objects. How can I do that in cakephp 3.x ?
After a teacher wants to add a grade and press the + button how do I know if he/she selected Mathematics or English if I use the same modal for grade saving? .
okey, most simple way is in modal to have hidden field, which contains a subject. I think this has not much to do with cakephp.
Example should look like this:
function modalopen(subject) {
$('#modal #subject').val(subject);
$('#modal').modal('toggle');
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.11.0/umd/popper.min.js" integrity="sha384-b/U6ypiBEHpOf/4+1nzFpr53nxSS+GLCkfwBdFNTxtclqqenISfwAzpKaMNFNmj4" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/js/bootstrap.min.js" integrity="sha384-h0AbiXch4ZDo7tp9hKZ4TsHbi047NrKGLO3SEJAg45jXxnGIfYzk4Si90RDIqNm1" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css" integrity="sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M" crossorigin="anonymous">
</head>
<body>
<button type="button" class="btn btn-info" onclick="modalopen('english')">+</button>
<button type="button" class="btn btn-info" onclick="modalopen('math')">+</button>
<div class="modal fade" id="modal" tabindex="-1" role="dialog" aria-labelledby="" 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=""></h4>
</div>
<div class="modal-body">
sub (will be hidden):<br>
<input type="text" name="subject" id ="subject" value="" placeholder="will be hidden"><br>
Mark:<br>
<input type="text" name="mark" id ="mark" value="" placeholder="mark">
</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</button>
</div>
</div>
</div>
</div>
</body>
</html>
The only way of determining which button was pressed is to use Javascript. This means not using the html-tag-option based method on the button to launch the modal, ie:
<!-- Button trigger modal: CAN *NOT* USE THIS TECHNIQUE!! -->
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#exampleModal">
Launch demo modal
</button>
I assume the form inside your modal is a cake-generated form, and the submit button is a normal form submit, which triggers a redraw of the page, effectively killing the modal (IE there's no "modal takedown").
To keep as close as possible to Cake's paradigm, I would send it back to the server in a hidden form field.
Something like:
on the cake side in your ctp while creating your form:
// HTML WRAPPER FOR MODAL
<?= $this->Form->create(yourentity); ?>
(your form stuff)
<?= $this->Form->hidden("subject_id",["id"=>"subject-id-field"]);
(end of form stuff including submit)
<?= $this->Form->end(); ?>
// HTML WRAPPER FOR MODAL
This will generate something in your form like
<input type="hidden" name="subject_id" id="subject-id-field"/>
We'll need to grab this hidden field in Javascript, so I'm giving it both a name (form-specific) and an id (global), since I prefer referring to everything with #id-syntax, but you could also use form[name=subject_id] and get rid of the id clause
On the browser side in HTML, to create your buttons:
<button type="button" class="btn btn-primary" onclick="launch_dialog('MATH')">Add Math</button>
On the browser side in javascript, the function to call when the button is clicked, which sets the subject id in the form and then launches the modal/form:
<script>
function launch_dialog(subject) {
$("#subject-id-field").val(subject); // use the id of the hidden field
$("#your-modal").modal("show"); // or whatever you do to launch the modal
}
</script>
On the server side in the function that the form targets:
# in your controller php file
function formAction() {
if($this->request->data["subject_id"]=="MATH") { // use the name of the hidden field
// do math record
}
// etc
}
Another note - if your grade record really does have a subject_id field which belongsTo a Subject record, you can have the button's onclick function call the launch_dialog function with that constant, and then you won't need any IF function inside the server action code. Just make sure to use the original record to generate the id, eg:
In controller before render:
$this->set("subjects",$this->[entity]->Subjects->find("list");
In ctp file, something like:
<?php foreach($subjects as $id=>$name): ?>
<button type="button" class="btn btn-primary"
onclick="launch_dialog(<?= $id ?>)">Add <?= $name ?></button>
<?php endforeach; ?>

Bootstrap Datepicker goes bottom

I am not an expert in Bootstrap 3. It was my first time to use the widget "datepicker". I have two date pickers that need to be displayed inline to each other. When I try a normal input it works but if it is a date picker it goes a little far at the bottom. I tried the position relative however it did not resolve the issue. See screen shot attached.Date picker goes at the bottom
Hope some one can give me some light. Below is my code.`
<div class="horiz-search-bar-wrapper">
<form class="form-inline">
<div class="form-group">
<label><strong>Search</strong></label>
</div>
<div class="input-daterange">
<div class="form-group rel-position-date">
<label>Check-In:</label>
<div class="input-group input-append date" id="from">
<input type="text" class="form-control">
<span class="input-group-addon"><i class="glyphicon glyphicon-calendar"></i></span>
</div>
</div>
<div class="form-group rel-position-date">
<label>Check-Out</label>
<div class="input-group input-append date" id="to">
<input type="text" class="form-control">
<span class="input-group-addon"><i class="glyphicon glyphicon-calendar"></i></span>
</div>
</div>
</div>
<div class="form-group mar-left">
<button type="button" class="btn btn-primary">
Submit
</button>
</div>
</form>
</div>
`
Just an update to this, we were able to fixed the issue by replacing the <label></label> tag to <span></span>. The bootstrap datepicker adds top pixels when it sees more than 1 label.
Hope this could help the others.
I was also seeing issues with the Datepicker appearing too low. Whether the targeted element was toward the top or bottom of the viewport and the Datepicker was respectively orienting itself above or below the element, I was seeing a Datepicker appear "too-low."
Stumbled on to a fix with some JavaScript hackery bound to the DP's "show" event/hook.
Note the use of the native Boostrap CSS utility classes datepicker-orient-top and datepicker-orient-bottom.
$('#DateOfBirthForEditing').datepicker().on("show", function (e) {
var refDatePicker = $('div.datepicker.datepicker-dropdown');
var refDatePickerField = $('#DateOfBirthForEditing');
var fieldPositionTop = refDatePickerField.offset().top;
var dpModalTopOffset = 0;
if (refDatePicker.hasClass('datepicker-orient-top')) {
dpModalTopOffset = fieldPositionTop - 255;
} else if (refDatePicker.hasClass('datepicker-orient-bottom')) {
dpModalTopOffset = fieldPositionTop + 30;
}
refDatePicker.css({ "top": dpModalTopOffset });
});

Dropdown Trigger Visually "Active" Like "Hover" [Foundation 6]

See the below code for a basic hover dropdown-pane:
<button class="button" type="button" data-toggle="example">Toggle Dropdown</button>
<div class="dropdown-pane" id="example" data-dropdown data-dropdown data-hover="true" data-hover-pane="true">
<div class="row">
<div class="medium-12 columns">
<p>When I am hovering over any content in this dropdown-pane, how can I make the above button appear as "active" i.e. Same state as hovering over the button.</p>
</div>
</div>
</div>
Now what I'd like to have happen is that when the user is viewing any content within that dropdown-pane, the button that triggered the event has a visual indicator that it is the "active" trigger. Here's a picture example:
Any insight you can provide would be very much appreciated.
Foundation has you covered here.
When the .dropdown-pane (content wrapper) is active, the button is given the class .hover (not to be confused with :hover state).
So you can simply add specific styles to that class (relative to your button if you want multiple different types of effect in different scenarios). You would have to manually ensure that your Foundation :hover matched your new .hover state.
HTML (e.g.)
<button class="button" type="button" data-toggle="example-dropdown">Toggle Dropdown</button>
<div class="dropdown-pane" id="example-dropdown" data-dropdown data-auto-focus="true">
Example form in a dropdown.
<form>
<div class="row">
<div class="medium-6 columns">
<label>Name
<input type="text" placeholder="Kirk, James T.">
</label>
</div>
<div class="medium-6 columns">
<label>Rank
<input type="text" placeholder="Captain">
</label>
</div>
</div>
</form>
</div>
<button class="button" type="button" data-toggle="example-dropdown-1">Hoverable Dropdown</button>
<div class="dropdown-pane" id="example-dropdown-1" data-dropdown data-hover="true" data-hover-pane="true">
Just some junk that needs to be said. Or not. Your choice.
</div>
CSS
.button.hover,
.button:hover{
background-color: green;
}
Working example: https://jsfiddle.net/tymothytym/8re4jcy0/ << in this example (and above) I'm manually setting :hover and .hover because I've used a default F6 CSS build which has a set :hover state but if you have already set :hover (e.g. to green) you don't need to re-set it.
Use css. Find the style of the hovered over button and either make an :hover pseudo class and apply the style that way or you can use javascript to add a class to the element that will have the exact css as the hovered over button.
.element:hover{
add styles here
}
or
var element=document.getElementByClassName('.className');
element.addClass('.classToAdd');

How to make modals which have routes like Trello in Emberjs

I want to know how we can make modals which have routes.
In Trello, whenever you click on a card, the route changes from abc.com/b/personal to abc.com/c/some-random-string and the card opens in a modal. Also, when you close the modal, you get redirected to the previous url (abc.com/b/personal).
I want to know how can we achieve this using Emberjs.
Example: https://trello.com/b/ezWgKsol/sales-enterprise-feature-requests-sample
Here is my modal (using foundation) where we delete a record:
<div class="reveal" id="deleteLocationModal" data-reveal>
<div class="row">
<div class="columns">
Are you sure you want to delete this location?
</div>
</div>
<div class="row">
</div>
<div class="row">
<div class="columns">
<button id="cancelButton" class="secondary button" data-close type="button">Cancel</button>
<button id="deleteButton" class="button" {{action "deleteLocation" model}} data-close type="button">Delete</button>
</div>
</div>
</div>
The router has the falling in the actions hash:
actions: {
deleteLocation(model) {
Ember.assert("Params must be provided", model);
model.save().then(( /* response */ ) => {
this.transitionTo('locations'); //locations is my index page.
//flash message to inform the user of success.
});
}, (error) => {
//handle error.
// display flash message
// rollback any dirty attributes
});
}
I hope this helps,
Jeff

double-submit issue in browsers - Bootstrap + Django

I have Bootstrap modal window for updating data everytime I close it, I face the so-called double-submission problem. That is, if I press F5, a message pops up telling me that I'm going to submit the same data for the second time and it inserts records into my table if I press ok. Moreover, if I try to open the modal window for the second time, it is rendered incorrectly ! Does it have anything to do with Django somehow ?
The modal window:
<form class="modal fade" id="openTaskWindow" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" method="post">{% csrf_token %}
<div class="modal-dialog modal-lg form-horizontal" role="form">
<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="exampleModalLabel">Новая задача</h4>
</div>
<div class="modal-body" style="font-size: smaller">
{{ createTask_form.as_p}}
</div>
<div class="modal-footer">
<input class="btn btn-default btn-sm" type="submit" value="Сохранить"/>
</div>
</div>
</div>
</form>
The button that calls the window:
<div><button type="button" data-toggle="modal" data-target="#openTaskWindow" data-backdrop="static" data-keyboard="false">Launch my modal</button></div>
The view (that is called when submit button of the modal window is pressed):
def createTask(request):
taskTable = Tasks.objects.all()
if request.method == 'POST':
task_form = TaskForm(request.POST)
if task_form.is_valid():
temp_form = task_form.save(commit=False)
temp_form.is_important = 0
temp_form.save()
return render_to_response('task_management/task_list.html',{'createTask_form':temp_form, 'taskTable': taskTable},context_instance=RequestContext(request))
else:
task_form = TaskForm()
return render_to_response('task_management/task_list.html',{'createTask_form':task_form, 'taskTable': taskTable, 'task_id':''},context_instance=RequestContext(request))
After reading discussions of the community, I tried to do this:
$('#openTaskWindow').submit(function() {
location.href = location.href;
});
but it did not help. Any ideas?
Well, this has not much to do with Django. The browser cache the post request for re-submission. The easiest way to prevent this is to return HttpResponseRedirect when for is valid.
So instead
if task_form.is_valid():
temp_form = task_form.save(commit=False)
temp_form.is_important = 0
temp_form.save()
return render_to_response('task_management/task_list.html',{'createTask_form':temp_form, 'taskTable': taskTable},context_instance=RequestContext(request))
Try to do
if task_form.is_valid():
temp_form = task_form.save(commit=False)
temp_form.is_important = 0
temp_form.save()
return HttpResponseRedirect('your_url')
And if you need to pass some extra arguments to the view you can accomplish that through query string or session based cache. And you don't need your Javascript hack.