How to identify button selected in cakephp 3.x? - bootstrap-modal

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; ?>

Related

creating an if statement to look for specific button press

first time poster! I'm still fairly new to coding and Django...
I'm looking to create a django if statement to see if a certain button is pressed. I have a toast set up to show an error warning if a search returns no results, but it also pops up if the user clears the search.
Here's the button(s)
<div class="input-group-append">
<button class="form-control rounded-circle btn form-button ml-2" type="submit">
<span>
<i class="fas fa-search"></i>
</span>
</button>
<button class="form-control rounded-circle btn form-button ml-2 closebutton" type="clear" name="clear">
<span>
<i class="fas fa-times"></i>
</span>
</button>
</div>
I'd like it to spot if the button with the name/type "clear" is clicked, then it won't run the toast. Toast is below:
{% if button == 'clear' %}
<div class="toast custom-toast rounded-0 border-top-0" data-autohide="false">
<div class="arrow-up arrow-danger"></div>
<div class="w-100 toast-capper bg-danger"></div>
<div class="toast-header bg-white text-dark">
<strong class="mr-auto">Error!</strong>
<button type="button" class="ml-2 mb-1 close text-dark" data-dismiss="toast" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="toast-body bg-white">
{{ message }}
</div>
</div>
{% endif %}
I'd like it to spot if the button with the name/type "clear" is clicked, then it won't run the toast.
This if statement is only run on the server when it renders the HTML for the web page. It is checking if a variable named button has the string value "clear". This has nothing to do with any HTML elements in the page, let alone the name of a particular <button>. Instead, the value of the variable button comes from the "context" when your Python calls one of the render functions.
I'm looking to create a django if statement to see if a certain button is pressed.
There are two different ways to handle button clicks:
Submit a form to the server which then returns a response with a new page. This can be the same Django template rendered with different values in the context in order to get the behavior that you want.
Add an onclick handler to the button. This should be a JavaScript function that peforms the action you want. It can manipulate the elements in the page to add a toast or anything else.
The first option is very slow because it will require a new network request. The second option is probably preferred here since it will be very responsive to the user's actions.

How can I open a modal from views.py in django? Is there any way?

I have a django application. when a user clicks the submit button two modals should be shown one after another each has to do different functions in views.py in my django app. I am trying to write the code but the problem is not easy and I have looked everywhere and couldn't get the answer.
I have to write the code in the following way:
views.py
def submit(request):
#first modal should pop up which has two options.
#second modal should pop up which also has a two options.
and when the user clicks any of the buttons each should also call the different function in views.py.
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<button class="btn btn-danger custom" style="position:absolute; left:800px; top:180px;" type="submit">Update the data</button>
# user clicks a button in form and modal should pop up
# then 2 modals should pop up
# the first modal has two buttons
# when user clicks the update button the function in the views should be called and also 2nd modal
should pop up
<!--modal 1-->
<div aria-hidden="true" aria-labelledby="exampleModalLabel" class="modal fade" id="UpdateModal" role="dialog"
tabindex="-1">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Update Changes</h5>
<button aria-label="Close" class="close" data-dismiss="modal" type="button">
<span aria-hidden="true">×</span>
</button>
</div>
#when user clicks update button another modal should pop up as well as
another function in the views should be called.
</body>
</html>
You could do that by using the modal system from the bootstrap documentation, you can check the live demo
In your template use a condition with Jinja2 if first condition show modal 1, else show modal 2, just make sure you have 2 different ID for the modal so they open distinctly

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

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();
}
}

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');

Template for modal from remote page

I am implementing modals as an ember component and I was wondering if and how could this be accomplished: If the content of the modal is coming from a different page, how would it be rendered as a template:
Example:
http://jsfiddle.net/koala_dev/NUCgp/918/
The script above opens a modal with this content:
http://fiddle.jshell.net/bHmRB/51/show/
But what if I wanted some extra data that depends on specific users, coming from the routes model? How would I insert something like
{{#each link in links}}
{{#link-to 'link.url'}}{{link.title}}{{/link-to}}
{{/each}}
into the remote page, so it would be rendered as a template, and not regular text?
Here is a very quick and easy example just to give you a right direction. You can play with it and parse the html to extract content (which is not relevant to the question).
You can setup a component for modal element. I've setup a component property (attribute) contentURL where you can set the url of the content.
Component handlebars
Notice the {{content}} which we used later in the action to save the ajax result. Action showModal is added on the link to execute the ajax call.
<script type="text/x-handlebars" id="components/bootstrap-modal">
<a data-toggle="modal" data-target="#myModal" {{action "showModal"}}>Click me !</a>
<!-- Modal -->
<div class="modal fade" id="myModal" 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">Modal title</h4>
</div>
<div class="modal-body">{{content}}</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 -->
</script>
Component JS
App.BootstrapModalComponent = Ember.Component.extend({
/*initModal: function(){
}.on('didInsertElement'),*/
contentURL: null,
content: 'Content is loading...',
actions: {
showModal: function(){
var self = this;
var contentURL = this.get('contentURL');
if(contentURL == null){
this.set('content', '<p>No content url is given</p>');
}
console.log('get content from url > ' + contentURL);
$.ajax({
url: contentURL,
dataType: "html",
beforeSend: function(){console.log('before send');},
error: function(xhr, status, message){
console.log(message);
},
success: function (content) {
// parse and get the right html for the content
self.set('content', content);
}
});
}
}
});
Now you can call the component bootstrap-modal on your template like {{bootstrap-modal}}
For example:
<script type="text/x-handlebars" id="index">
{{bootstrap-modal contentURL="http://fiddle.jshell.net/bHmRB/51/show/"}}
</script>
jsFiddle example http://jsfiddle.net/sisir/NUCgp/1713/