Why is the button click event not handled? - javascript

I'm doing a simple NodeJS-MongoDB todo list application where the todo-items added can be updated. When the edit button is clicked, I'm changing the corresponding element to a form to update it. The edit button when pressed is successfully handled and is converted to a form, whereas when the update button is clicked it is not handled by the event listener and the default refresh action takes place. Why?
Javascript Part:
$(document).ready(function(){
$('.update').on('click', function(){
var id = $(this).parent().find('input:hidden');
var item = $(this).parent().find('input:text');
var priority =$(this).parent().find('select option:selected');
var todo = {item: item.val(), priority: priority.val()}
$.ajax({
type: 'PUT',
url: '/todo/' + id.val(),
data: todo,
success: function(data){
location.reload();
}
});
});
$('.edit').on('click', function(){
var id = $(this).parent().find('input:hidden');
var item = $(this).parent().find('b');
$(this).parent().html(
"<form>"+
"<input type = 'text' name = 'item' value='" + item.text() + "' required />"+
"<select name = 'priority' required>"+
"<option value = 'high'> High </option>"+
"<option value = 'medium'> Medium </option>"+
"<option value = 'low'> Low </option>"+
"</select>"+
"<input type = 'hidden' value='" + id.val() + "'/>"+
"<button class = 'update'> Update Item </button>"+
"</form>");
});
});
HTML Part:
<ul>
<% for(var i=0; i < todos.length; i++){ %>
<li>
<input type = "hidden" value = <%= todos[i]._id %> />
<b> <%= todos[i].item %> </b>
<button class = "edit"> 📝 </button>
</li>
<% } %>
</ul>

I think this will solve your problem
$(document).on('click', '.update', function(){
//Rest of your code
})

If your page was dynamically creating elements with the class name dosomething you would bind the event to a parent which already exists, often "document"
$(document).on('click', '.update', function(){
// what you want to happen when click
// occurs on elements that match '.update'
});
Or you can use a parent DOM element, That always remain in your page load Eg:
$('ul').on('click', '.update', function(){
// do something here
});

You can put console.log(); to double check if it is going in. Button in a form's default action is going to form's action page which you don't have and you are not doing any POST, GET etc. with form, you are doing it with ajax. If you don't want to use form's functionality, you can just give type=button to button. If you are going to not use the form to post, get or anything in the future, removing the form tag is another option.
EDIT
After other answers, I noticed that the correct answer can be given by mixing my and their answers. So I decided to add this part too. You are giving onClick eventhandler before the DOM element was created. You must give event handler after creating the element. Your options here are:
Adding the whole .update onClick inside .edit onClick's bottom.
Giving onClick event handler to an object which was already created before any javascript action.
$(document).on('click', '.update', function(){
//update's onClick actions here
}

Related

Javascript: script for menu not reacting when menu is dynamically created

I have this menu, statically, it is as follows:
<div class="dropdown col-sm-3">
<button type="button"
class="btn btn-select btn-block"
data-toggle="dropdown">Plane <span class="caret"></span>
</button>
<ul class="dropdown-menu dropdown-menu-select" id="plane">
<li><label class="dropdown-radio"> <input type="radio" value="3" name="plane"> Plane: A360 </label></li>
<li><label class="dropdown-radio"> <input type="radio" value="2" name="plane"> Plane: AR45 </label></li>
<li><label class="dropdown-radio"> <input type="radio" value="1" name="plane"> Plane: A380 </label></li>
</ul>
</div>
...
<script>
$('.dropdown-radio').find('input').change(function() {
var dropdown = $(this).closest('.dropdown');
var radioname = $(this).attr('name');
var checked = 'input[name=' + radioname + ']:checked';
//update the text
var checkedtext = $(checked).closest('.dropdown-radio').text();
dropdown.find('button').text( checkedtext );
//retrieve the checked value, if needed in page
var thisvalue = dropdown.find( checked ).val();
console.log( thisvalue );
});
</script>
This version worked: the user could select one (and only one) option, and the option would then be displayed in the main button. I have now created this same menu dynamically with data from a MySQL database.
<script>
var socket = io.connect('http://localhost:3000');
socket.on('sess', function(message) {
if(message == 0){
alert('No planes associated.');
}else{
for(var i = 0; i < message.length; i++){
$('#session').prepend( '<li><label class="dropdown-radio" > <input type="radio" value="'
+ message[i].idSession + '" name="session"> Session: '
+ message[i].idSession + ' </label></li>');
}
}
});
</script>
Here the menu still drops down but now the user can check as many radios as they want and the first script isn't activated (nothing appears in the console). I have tried putting the second script both before and after the previous one, both give the same results.
Is there a workaround for this? I'm new to Javascript (jQuery) and its sensibilities.
Thanks
What you want is to bind the change event to a higher on hierarchy element rather then directly at the inputs that didn't exist yet:
$('#plane').on('change', 'input', function() {
var dropdown = $(this).closest('.dropdown');
var radioname = $(this).attr('name');
var checked = 'input[name=' + radioname + ']:checked';
//update the text
var checkedtext = $(checked).closest('.dropdown-radio').text();
dropdown.find('button').text( checkedtext );
//retrieve the checked value, if needed in page
var thisvalue = dropdown.find( checked ).val();
console.log( thisvalue );
});
Doing so, you are binding the change event to the parent div, so doesn't matter how you modify its children on a later moment, it will always fire an event for it if the target element was an input (second function argument).
You don't need to execute this script AFTER the inputs were loaded, just go with your initial approach on dynamically loading content but tweak that change with the on('change' version.
I've combined my comments to an answer for easier reading/for anyone else looking at this.
The first script runs once inline of the page load and due to the asynchronous call to your database, that means it doesn't find anything to bind change to and then the script is never run again. You'll need to update your script so that it is run again after the new radio buttons have all been loaded into the DOM (this is after in time, not on the page).
Consider saving your first script to a function and calling it from your database call success, post rendering your radio buttons. You may need to use .off('change') also to remove any existing change bindings before creating new ones.
With regards to your radio buttons allowing multiple selected, as long as they share a name then they shouldn't allow multiple as per the documentation.

How to toggle form visibility dynamically?

I have page where user can dynamically create new forms. For every new form button is created. Form is hidden by default. I need to toggle form visibility on that button click. Right now i am using javascript code below and its working
$(document).ready(function(){
$("#button1").click(function(){
$("#1").css({"display":"block"});
$("#2").css({"display":"none"});
$("#3").css({"display":"none"});
});
$("#button2").click(function(){
$("#2").css({"display":"block"});
$("#1").css({"display":"none"});
$("#3").css({"display":"none"});
});
...
Now when user create form i manually modify javascript but problem is that i have too many forms right now and ill have even more.
I need solution to bind button for form and toggle its visibility. Any advice is appreciate.
EDIT
Code i am actually using:
while ($row = $result9->fetch_assoc())
{
echo "<input class='btn btn-default' type='button' id='".$row['o_ime']."' name='button' value='".$row['o_ime']."'>";
}
echo "<form class='form-inline' role='form' name='$i' id='$i' style='display:none' action='naruci.php' method='POST' onsubmit='return validateForm()'>";
form elements
echo "</form>";
First of all, you cannot have the same ID in your DOM.
So instead of IDs use classes. And use jquery's class selector.
So to capture the event, just use the class selector.
And also use hide and show jquery APIs to show/hide elements.
$(".new-btn").click(function(){
$("form").hide(); // close all forms
$("this").closest("form").show(); // show parent form
});
And the next thing I notice, for dynamic elements it cannot be captured by normal click event. Use jquery on API.
$(".new-btn").on('click', function(){
$("form").hide(); // close all forms
$("this").closest("form_").show(); // show parent form
// This is the reason it is not working because I forgot the underscore
});
Update:
It should look like this:
while ($row = $result9->fetch_assoc())
{
echo "<input class='btn btn-default' type='button' id='".$row['o_ime']."' name='button' value='".$row['o_ime']."'>";
// We changed the form ID in this section
echo "<form class='form-inline' role='form' name='$i' id='form_".$row['o_ime']."' style='display:none' action='naruci.php' method='POST' onsubmit='return validateForm()'>";
form elements
echo "</form>";
}
In my query I will create an event to capture my button clicks:
$('.btn').on('click', function(){ // Listen all click events of buttons with class `btn`
var id = $(this).attr('id'); // Get ID of focus button
var formName = 'form' + id; // Append form string in the id to match form's ID
$('form').hide(); // Hide all forms
$('#' + formName).show(); // Show exact form
});
you'll find the best way of what you want to do by following the example here in this link
http://www.w3schools.com/jquery/eff_toggle.asp
$("button").click(function(){
$("p").toggle();
});
You can add unique class for all of your forms. Refer this code
<form class="test" id="1"></form>
<form class="test" id="2"></form>
<form class="test" id="3"></form>
$(document).on("click",".test",function(event){
$(".test").css({"display":"none"});
$(this).css({"display":"block"});
});
Just make your own class for display block.
.db{
display:block;
}
Then on your jquery just toggle class.
$("button").click(function(){
$("#1").toggleClass('db');
})
\\对于动态生成的元素需要使用`on`来监听事件的触发
Try the following
$(function(){
//动态构造form元素
//Dynamic construction of form elements
$('#cnf').on('click',function(){
$('#container').append('<div>' +
'<button>toggle</button>' +
'<form><input value="value"></form>' +
'</div>')
});
//通过冒泡监听按钮事件
//The bubble monitor button event
$('#container').on('click','button',function(){
$(this).next().toggle();
})
})
祝顺利!

How to Replace a Div with another Div but only once

I am trying to replace a div with another div onclick using the code below. It works fine for one instance. However, the problem is when the class appear more than once which is the case for me (multiple instances)it obviously changes all instance as they have the same class name.
Is there a way to make it only change the clicked instance? Thanks
HTML
<div id="test"></div>
JavaScript (dynamically creating HTML)
var html =
'<form action="test.php" method="get" class="myForm">' +
'<input type="hidden" name="mID" value="' + this.id + '"/>' +
'<input type="image" class="send" src="this.image" name ="send" alt="submit"/>' +
'</form>';
$('div#test').append(html);
$("#test").on('click', '.send', function(e) {
e.preventDefault();
var $form = $(this).closest('form');
$.get($form.attr("action"),
$form.find(":input").serializeArray(),
function(data) {
$('.myForm').replaceWith('<div class="myForm2"><img src="Icons/PNG/tick 2.png" alt="submit"/></div></div>');
});
});
$("#test").on('submit', '.myForm', function(e) {
return false;
});
SOLUTION;
Instead of;
$('.myForm').replaceWith('<div class="myForm2"><img src="Icons/PNG/tick 2.png" alt="submit"/></div></div>');
CORRECT WAY;
$form.replaceWith('<div class="myForm2"><img src="Icons/PNG/tick 2.png" alt="submit"/></div></div>');
You're already most of the way there with $form = $(this).closest('form'); but for some reason you started selected all the forms instead by using $('.myForm'), so
replace
$('.myForm').replaceWith(...
with
$form.replaceWith(...
First of all, you are not replacing a div, you are replacing a form (with class .myForm). As this form is inside the div you are clicking on when you want to change your form you could use:
$(this).find(".myForm").replaceWith...
$(".targetClass").click(function(){
var theDivBeingClicked = $(this);
//Do something
})
Simple!
I am no JQuery Expert, but we doit the traditional way!
var elements = document.getElementByID('test')
we would have elemements[0] and elements[1] .... everything with the id="test" inside. but only the first element needs to be replaces.
so, our choice falls on elements[0].
$('.myForm').replaceWith(.....)
take myForm away, and add the elements array number you'd like having to be replaces, then it's always this element in the doc that is being replaces.
have fun!

Disabling the Submit button

I have a form which contains several elements and one of them being the select value element.However what i have done is that i have attached the quantity that has to be shown on the select menu, whose values comes from the database.
Example:
Suppose i have set 10 in my database for quantity then , the select element will show me options from 1-10.
Code:
<?php
if(#$dbqty>=10)
{
$selectbox='<p> Quantity: <select name="product_qty">';
for($i=1;$i<=10;$i++)
{
$selectbox.='<option value="'.$i.'">'.$i.'</option>';
}
$selectbox.='</select></p>';
echo $selectbox;
}
else if(#$dbqty<10 && #$dbqty>0)
{
$selectbox='<p> Quantity: <select name="product_qty">';
for($i=1;$i<=#$dbqty;$i++)
{
$selectbox.='<option value="'.$i.'">'.$i.'</option>';
}
$selectbox.='</select></p>';
echo $selectbox;
}
if(#$dbqty==null || #$dbqty==0)
{
echo '<input type="button" name="product_qty" value="Sold Out" disabled="disabled"/>';
}
?>
In the javascript part i have set a function which submit the form to a php file and loads its response text.
Code:
$(document).ready(function(){
$(document).on('submit','#submitform',function(event){
event.preventDefault();
var button_content = $(this).find('button[type=submit]');
button_content.html('Adding...');
var data=$(this).serialize();
$.ajax({
type:'POST',
url:'../cart/index.php',
data:data,
success : function(content)
{
if ($('#ajaxview').find('#popupcart')) {
$('#popupcart').hide();
$('#ajaxview').append(content);
button_content.html('Add');
}
else
{
$('#ajaxview').append(content);
button_content.html('Add');
}
}
})
})
})
What i was trying to do is that when the quantity for the item comes out to be sold out the submit button gets disabled.Is it possible? If yes,How to do this one then?
Thanks!
A better approach, in my opinion, would be to get the data from database using javascript and then based on the retrieved value, use jQuery to enable/disable the button.
use this jquery to remove the submit events on the buttons which has value sold out
$('input[value="Sold Out"]').on('click',function(e){
e.preventDefault(); //stop the event
});
Or if the elements are appended dynamically, then you got to use delegated event handlers to attach the event. like below
$(document).on('click','input[value="Sold Out"]',function(e){
e.preventDefault(); //stop the event
});
$(document).on('submit','#submitform',function(event){
event.preventDefault();
var input=$("#submitform :input[name='product_qty']").val();
if(input==null)
$(this).find('button[type=submit]').prop('disabled', true);
}
This is what i did.It worked.However not a correct way to do this but it does the work.Stops the submit button to send any request.

javascript onchange with 2 different dropdown lists

Im pretty new with javascript programming.
I have some .php code, where 2 dropdown lists (in the same FORM) are populated by 2 different mysqli queries, this works without any problem.
Im trying to get javascript to handle the selected parts of the dropdown lists, with onchange, this works for only one dropdown list, and i cant really figure out how to get around this one.
This is the code that works with one dropdown menu, and it updates automaticly the page without submitting:
$chosen_location = $_GET['Lid'];
$chosen_car = $_GET['Cid'];
?>
<script type="text/javascript">
function changeDropDown(dropdown){
var location = dropdown.options[dropdown.selectedIndex].value;
*var car = dropdown.options[dropdown.selectedIndex].value;*
document.getElementById("form1").action = "test.php?Lid=" + location + "&Cid=" + car;
document.getElementById("form1").submit();
}
</script>
Part of the .php code:
<select size="1" name="form_location_id" id="form_location_id" onchange='changeDropDown(this);'>
<option value = <?php echo ($location_id) ?> selected><?php echo ($location_name) ?></option>
<select size="1" name="form_car" id="form_car" onchange='changeDropDown(this);'>
<option value = <?php echo ($car_type_id) ?>><?php echo "" . ($car_class) . " - " . ($car_manufacturer) . " - " . ($car) . "" ?></option>
The italic marked I know will not catch the correct value, but this is where im at right now...
How is it possible to get an action URL with both selected values ? as this is going to be used in a mysqli query to show data from the actual selection
Thanks in advance... :)
Currently, you are submitting the form through JavaScript. If the selects are inside the form, their values will automatically be submitted when you submit the form. You don't even have to change the action of the form.
So, you can just generate a normal form (including submit button, if you will), and it will work. Then, add a little JavaScript sauce to make it submit automatically.
The code below does just that. JavaScripts adds a class to the body. This is a way to easily change styling based on JavaScript being enabled or not. In this case, I use it to hide the submit button, which is only needed in a non-JavaScript situation.
Then, I bind the on change handler, not unlike yours, to submit the form when a value is selected. By giving the selects a proper name, their values will automatically be added as intended.
Note how the event handlers are bound through code. You don't have to hardcode any calls to JavaScript in the HTML, so you can keep the HTML clean and separate (readability!).
// Bind to load event of the window. Alternatively, put the script at the end of the document.
window.addEventListener("load", function() {
// Indicate that JavaScript works. You can use this to style the document, for instance
// hide the submit button, if the form is automatically submitted on change..
document.body.classList.add("js");
// With JavaScript, you can automatically submit the form, but you still don't have to modify it.
var theform = document.getElementById("theform");
var selects = document.querySelectorAll("#theform select");
for (var i = 0; i < selects.length; ++i) {
selects[i].addEventListener("change",
function() {
alert("submitting now");
theform.submit();
});
}
});
.js button[type="submit"] {
display: none;
}
<!-- Just a form with selects is enough. You don't even have to have JavaScript to post this. -->
<form id="theform" action="test.php" method="get">
<select name="Lid">
<option>Example...</option>
<option>Use PHP,</option>
<option>to fill these.</option>
</select>
<select name="Cid">....</select>
<button type="submit">Post</button>
</form>
You can update your code to following
function changeDropDown(){
var elLocation = document.getElementById('form_location_id');
var elCar = document.getElementById('form_car');
var location = elLocation.options[elLocation.selectedIndex].value;
var car = elCar.options[elCar.selectedIndex].value;
document.getElementById("form1").action = "test.php?Lid=" + location + "&Cid=" + car;
document.getElementById("form1").submit();
}
try to do this
<script>
// get select elements
var form_location_id = document.getElementById('form_location_id');
var form_car = document.getElementById('form_car');
// on change
form_location_id.addEventListener('change', changeDropDown1);
form_car.addEventListener('change', changeDropDown2);
</script>
And change the 'changeDropDown1' and 'changeDropDown2' to your handler function
try this
<script type="text/JavaScript">
var dropdownLocation = document.getElementById("form_location_id");
var dropdownCar = document.getElementById("form_car");
function changeDropDown() {
var location = dropdownLocation.options[dropdownLocation.selectedIndex].value;
var car = dropdownCar.options[dropdownCar.selectedIndex].value;
document.getElementById("form1").action = "test.php?Lid=" + location + "&Cid=" + car;
document.getElementById("form1").submit();
}
</script>
dropdownLocation et dropdownCar are outside the function to save time because this 2 vars need only to be set one time

Categories