How to run script when a button is clicked - javascript

Hi I'm running a sum and multiplication script for some field input values to a form i made. How can I get this script to run on a button click so that after a user enters a new value they can click a update form button to run the calculations script and update the total sum.
<script>
var $form = $('#contactForm'),
$summands = $form.find('.sum1'),
$sumDisplay = $('#itmttl');
$form.delegate('.sum1', 'change', function ()
{
var sum = 0;
$summands.each(function ()
{
var value = Number($(this).val());
if (!isNaN(value)) sum += value;
});
$sumDisplay.val(sum);
});
function multiply(one, two) {
if(one && two){
this.form.elements.tax.value = one * two;
} else {
this.style.color='blue';
}
}
</script>

Define a function and put the code you want to run inside it.
var doStuff = function () {
// do some stuff here
};
Select your button and call that function on click. If you're using an A or BUTTON tag you may want to prevent the default action, which I've included in this example.
$('.button').on('click', function (event) {
doStuff();
event.preventDefault();
});
This assumes that you're using jQuery 1.7+.

Related

Is there a way to catch an onchange trigger with a focusout by a button click?

The scenario is this modal window:
The inputs 2, 3 and 4 with an .on('change', function () {}); makes an AJAX call to a specified controller, that update the recod values and reload the value 1.
So the right, but not functional way is to:
click the input 1 and set the value
focusout it by clicking outside the input
AJAX reload value 1 updated
click input 2 and set the value
focus out it by clicking outside the input
AJAX reload value 1 updated
The user click confirm that call another controller that make some checks and change the status of an object (from Draft to Confirmed)
The problem
If I try this way:
click the input 1 and set the value
focusout it by clicking outside the input
AJAX reload value 1 updated
click input 2 and set the value
Click confirm button that call another controller and trigger the input change
Now, with this way the problem occurs because the confirm method doesn't receive yet the update from last onchange trigger and the check is not correct.
Is there a way to manage multiple AJAX from different triggers like onchange and onclick?
Something like if the below onclick is triggered:
// Trigger for button confirm inside timesheet sheet modal
$(document).on('click', 'button.js_confirm_timesheet_sheet', function (ev) {
var $button = $(this);
var wizard_id = $button.data()['wizardId'];
var sheet_id = $button.data()['sheetId'];
var values = {
'wizard_id': wizard_id,
'sheet_id': sheet_id,
};
confirm_sheet_distribution_hours(values);
});
Check if the click come from an input focus out, if yes trigger the onchange first and after the onclick
Maybe this solution can be a bad way to do this.
Little, triggers recap:
The inputs have an onchange trigger that writes data to backend object with an AJAX call that recompute values and return the new one
The confirm button check if everything is ok with an AJAX call and change the backend object status
The other workaround maybe can be to declare an object that keeps track of each changed input boxes and clear it on each AJAX success return.
Something like:
var changedData = {};
function update_wizard_data_and_modal(values, $input_elem, event) {
changedData[key] = $input_elem;
ajax.jsonRpc("/my/controller/path", "call", values)
.then(function (new_modal_values) {
$input_elem.removeClass('input-value-error');
if (!jQuery.isEmptyObject(new_modal_values)) {
if (new_modal_values.error_msg) {
var $content = $(new_modal_values.error_msg);
$content.modal({
backdrop: 'static',
keyboard: false
});
$content.appendTo('body').modal();
// Show error class
$input_elem.val('00:00');
$input_elem.addClass('input-value-error');
}
// Update the header values with hours to be distribuited
$('#header-wizard-values').html(new_modal_values.header_values);
// Update the hours to get payed available
$('.js_hours_to_get_payed').html(new_modal_values.hours_get_payed_values);
// Clear the changedData object
for (var member in changedData) delete changedData[member];
}
});
}
function confirm_sheet_distribution_hours(values) {
if jQuery.isEmptyObject(changedData){
ajax.jsonRpc("/confirm/controller/path", "call", values)
.then(function (response) {
if ('error' in response) {
//response in this case is the modal error template
$(response.error).appendTo('body').modal();
} else {
// Close modal and refresh the grid for current period
$('#modal_timesheet_sheet_confirm').modal('hide');
var sheet_item_data = {
'year': response.year,
'month': response.month,
};
update_grid_and_bars_values(sheet_item_data);
}
});
} else {
// TODO: trigger the change for element inside object and confirm
}
}
$(document).on("change", "input.distribution-input", function (ev) {
var $input = $(this);
var sheet_id = $('input[name="sheet_id"]').val();
var wiz_line_id = Number($input.attr('id').match(/\d+/)[0]);
var row_wizard_data = $input.closest('div.row').data();
var leave_type_id = row_wizard_data['leaveTypeId'];
var wizard_id = row_wizard_data['wizardId'];
var values = {
'sheet_id': Number(sheet_id),
'wizard_id': wizard_id,
'wiz_line_id': wiz_line_id,
'leave_type_id': leave_type_id,
'input_value': $input.val(),
};
var is_good_formatted = check_string_time_format($input, {});
if (is_good_formatted) {
update_wizard_data_and_modal(values, $input, ev);
}
});
// Trigger for button confirm inside timesheet sheet modal
$(document).on('click', 'button.js_confirm_timesheet_sheet', function (ev) {
ev.preventDefault();
ev.stopPropagation();
var $button = $(this);
var wizard_id = $button.data()['wizardId'];
var sheet_id = $button.data()['sheetId'];
var values = {
'wizard_id': wizard_id,
'sheet_id': sheet_id,
};
confirm_sheet_distribution_hours(values);
});
As suggested by Taplar I used a similar approach.
Here the javascript that manages the "onchange" of a wizard in the Odoo Frontend.
// Variable used for the last input changed when user click the Confirm button
var canConfirm = true;
/* Variable used for keep trace of the number of retry inside method
* confirm_sheet_distribution_hours
* */
var nr_of_try = 0;
function update_wizard_data_and_modal(values, $input_elem, event) {
if (event.type !== 'input') {
ajax.jsonRpc("/controller/path/...", "call", values)
.then(function (new_modal_values) {
canConfirm = true;
$input_elem.removeClass('input-value-error');
if (!jQuery.isEmptyObject(new_modal_values)) {
if (new_modal_values.error_msg) {
var $content = $(new_modal_values.error_msg);
$content.modal({
backdrop: 'static',
keyboard: false
});
$content.appendTo('body').modal();
// Show error class
$input_elem.val('00:00');
$input_elem.addClass('input-value-error');
}
// Update the header values with hours to be distribuited
$('#header-wizard-values').html(new_modal_values.header_values);
// Update the hours to get payed available
$('.js_hours_to_get_payed').html(new_modal_values.hours_get_payed_values);
}
});
} else {
canConfirm = false;
}
}
function set_the_amount_on_wizard($input, values, event) {
if (event.type !== 'input') {
ajax.jsonRpc("/controller/path/...", "call", values)
.then(function (response) {
canConfirm = true;
if ('error' in response) {
//response in this case is the modal error template
$(response.error).appendTo('body').modal();
// Reset input value (backend reset the TransientModel value)
$input.val('00:00')
}
});
} else {
canConfirm = false;
}
}
function confirm_sheet_distribution_hours(values) {
if (canConfirm) {
ajax.jsonRpc("/controller/patH/...", "call", values)
.then(function (response) {
if ('error' in response) {
//response in this case is the modal error template
$(response.error).appendTo('body').modal();
} else {
// Close modal and refresh the grid for current period
$('#modal_timesheet_sheet_confirm').modal('hide');
var sheet_item_data = {
'year': response.year,
'month': response.month,
};
update_grid_and_bars_values(sheet_item_data);
}
});
} else {
/*Try six times to confirm the sheet (Until the onchange doesn't write
* new values the AJAX call doesn't set canConfirm as True
* */
if (nr_of_try <= 5) {
setTimeout(function () {
nr_of_try++;
confirm_sheet_distribution_hours(values);
}, 500);
}
}
}
//Trigger that monitorate hours distribution change
$(document).on("input change", "input.distribution-input", function (ev) {
var $input = $(this);
var sheet_id = $('input[name="sheet_id"]').val();
var wiz_line_id = Number($input.attr('id').match(/\d+/)[0]);
var row_wizard_data = $input.closest('div.row').data();
var leave_type_id = row_wizard_data['leaveTypeId'];
var wizard_id = row_wizard_data['wizardId'];
var values = {
'sheet_id': Number(sheet_id),
'wizard_id': wizard_id,
'wiz_line_id': wiz_line_id,
'leave_type_id': leave_type_id,
'input_value': $input.val(),
};
var is_good_formatted = check_string_time_format($input);
if (is_good_formatted) {
update_wizard_data_and_modal(values, $input, ev);
}
});
//Trigger that monitorate hours distribution change
$(document).on("input change", "input.payment-hour-input", function (ev) {
var $input = $(this);
var row_wizard_data = $input.closest('div.row').data();
var wizard_id = row_wizard_data['wizardId'];
var values = {
'wizard_id': wizard_id,
'input_value': $input.val(),
};
var is_good_formatted = check_string_time_format($input);
if (is_good_formatted) {
set_the_amount_on_wizard($input, values, ev);
}
});
// Trigger for button confirm inside timesheet sheet modal
$(document).on('click', 'button.js_confirm_timesheet_sheet', function (ev) {
var $button = $(this);
var wizard_id = $button.data()['wizardId'];
var sheet_id = $button.data()['sheetId'];
var values = {
'wizard_id': wizard_id,
'sheet_id': sheet_id,
};
// Variable used for retry sheet confirmation until canConfirm is not True
// Max repeat call is 6 times
nr_of_try = 0;
confirm_sheet_distribution_hours(values);
});
In simple words.
When the user is typing on inputs boxes the type input inside on.() set the variable canConfirm to false.
This prevents case when user changes values and click to the Confirm buttons immediately after.
In fact if the user changes some input box and immediately click "Confirm" the AJAX call starts only if the flag is true, if not the method calls it's self six times every 500 ms.
Let me know if there is some better way to doing that.
Thanks
PS: I will try a better approach with a DTO backend that clone data from model and manage updates like onchange cache.
Inspired by: https://python-3-patterns-idioms-test.readthedocs.io/en/latest/Messenger.html

Triggering of JS functions on page load isn't working

I have two functions that are triggered whilst the user is inputting data. They essentially add up the values of the options they choose, and output them.
On this form, in particular, the options are already pre-populated. Because of this, the functions have not been triggered, leaving their calculation as null.
The functions are shown just above </body>
Functions:
$(calculateScore);
function calculateScore () {
var fields = $('.form-group #input').change(calculate);
function calculate () {
var score = 0;
fields.each(function () {
score += +$(this).val();
});
$('#score').html(score.toFixed(0));
}
}
$(calculateHiddenScore);
function calculateHiddenScore () {
var fields = $('.form-group #input').change(calculate);
function calculate () {
var score = 0;
fields.each(function () {
score += +$(this).val();
});
$('#hidden_score').val(score.toFixed(0));
}
}
Code placed underneath the functions to try and trigger them:
$(function () {
calculateHiddenScore();
calculateScore();
});
and I have also tried:
window.onload = function () {
calculateScore();
calculateHiddenScore();
};
How can I trigger these two functions when the page has loaded please? Many thanks.
DOM ready will not trigger an onchange event even if your items are pre-populated.
Therefore you have to modify a bit your script like:
function calculateScore() {
var fields = $('.form-group #input'); // Cache only!
function calculate() {
var score = 0;
fields.each(function() {
score += +$(this).val();
});
$('#score').html(score.toFixed(0));
$('#hidden_score').val(score.toFixed(0));
}
calculate(); // Calculate ASAP (on DOM ready)
fields.on("change", calculate); // and also on change
}
jQuery(function($) { // DOM is ready and $ alias secured
calculateScore(); // Trigger
// other jQuery code here
});
P.S: BTW even if the above is a bit improved, it makes not much sense to loop using each over a single ID #input element - I'll leave that to you...

Function never calls the second function

I have this javascript code
function editRerenderFix() {
console.log("edit render start");
textAreaFix();
console.log("edit render middle");
setupDates();
console.log("edit render end");
}
/** Function to auto expand out the text area to hold all content **/
function textAreaFix() {
jQuery('textarea').on( 'change keyup keydown paste cut', function (event){
jQuery(this).height(100);
jQuery('textarea').each(function() {
jQuery(this).height(jQuery(this).prop('scrollHeight'));
});
});
return null;
}
/** Function to fix and set the custom date/time picker **/
function setupDates() {
jQuery('.dateFormat').remove();
var inputs = jQuery('.inputDate');
jQuery(inputs).each(function() {
var input = jQuery(this).val().split('/')[2];
if(input.length > 4) {
input = input.split(" ")[0];
}
if(input < '2015') {
jQuery(this).val("");
}
});
console.log("Setup Dates function ran");
jQuery('.inputDate').datetimepicker();
}
This function is called using the onComplete ajax method. The problem is that when it runs only textAreaFix() is called. In the console only "edit render start" and "edit render middle" show up.
The reason that "Setup Date function ran" first is because I have this function,
jQuery(document).ready(function() {
jQuery.material.init();
textAreaFix();
setupDates();
tourStep();
easterEgg();
});
How can I get the setupDates() function called?
EDIT:
I added more debugging to setupDates(),
/** Function to fix and set the custom date/time picker **/
function setupDates() {
jQuery('.dateFormat').remove();
var inputs = jQuery('.inputDate');
console.log(inputs);
jQuery(inputs).each(function() {
var input = jQuery(this).val().split('/')[2];
console.log(input);
if(input.length > 4) {
console.log("Input > 4");
input = input.split(" ")[0];
console.log(input);
}
if(input < '2015') {
console.log("Fix 2015 dates");
jQuery(this).val("");
}
});
console.log("Setup Dates function ran");
jQuery('.inputDate').datetimepicker();
}
When I run this I get,
I am not sure where the "undefined" comes from though.
My guess is that it is displaying undefined because the loop is repeating and jQuery(this).val().split('/')[2] is causing a problem. Maybe console.log on this and this.val() right at the beginning of the loop's block? – James Nearn 30 mins ago

Get image ids in a div every second

I was successful in getting the id of all images within a div when clicking the div with the following codes below:
<script type="text/javascript">
function getimgid(){
var elems = [].slice.call( document.getElementById("card") );
elems.forEach( function( elem ){
elem.onclick = function(){
var arr = [], imgs = [].slice.call( elem.getElementsByTagName("img") );
if(imgs.length){
imgs.forEach( function( img ){
var attrID = img.id;
arr.push(attrID);
alert(arr);
});
} else {
alert("No images found.");
}
};
});
}
</script>
The codes above works perfectly, doing an alert message of the image id when clicking card div. Now what I want is to run this function without clicking the div in every 5 seconds. I have tried setInterval (getimgid, 5000), but it doesn't work. Which part of the codes above should I modify to call the function without clicking the div. Any help would be much appreciated.
JSFiddle
You should be calling it this way:
setInterval (function(){
getimgid();
},5000);
also remove binding of click event for element.
Working Fiddle
Use elem.click() to trigger click
function getimgid() {
var elems = [].slice.call(document.getElementsByClassName("card"));
elems.forEach(function (elem) {
elem.onclick = function () {
var arr = [],
imgs = [].slice.call(elem.getElementsByTagName("img"));
if (imgs.length) {
imgs.forEach(function (img) {
var attrID = img.id;
arr.push(attrID);
alert(arr);
});
} else {
alert("No images found.");
}
};
elem.click();
});
}
setInterval(getimgid, 1000);
DEMO
Problem: You are not triggering the click in setInterval. You are only re-running the event binding every 5 secs.
Solution: Set Interval on another function which triggers the click. Or remove the click binding altogether if you don't want to manually click at all.
Updated fiddle: http://jsfiddle.net/abhitalks/3Dx4w/5/
JS:
var t;
function trigger() {
var elems = [].slice.call(document.getElementsByClassName("card"));
elems.forEach(function (elem) {
elem.onclick();
});
}
t = setInterval(trigger, 5000);

Is it possible to bind to the Click event and not use an anonymous function -- I just want to call a named function

I have the following code. The first attempt at binding to click event does not work. The second way does. The first shows the alert "CheckBox1" during Page_Load. The second one shows the alert "CheckBox4" during the proper time -- during clicks.
$(document).ready(function () {
$(document.getElementById(checkBox1ID)).click( SetCheckBox1State(this.checked) );
$(document.getElementById(checkBox4ID)).click(function () { SetCheckBox4State(this.checked) });
});
function SetCheckBox1State(checked) {
alert("CheckBox2");
var radNumericTextBox1 = $find(radNumericTextBox1ID);
var wrapperElement = $get(radNumericTextBox1._wrapperElementID);
var label = $(wrapperElemenet.getElementsByTagName("label")[0]);
if (checked) {
radNumericTextBox1.enable();
label.addClass("LabelEnabled");
label.removeClass("LabelDisabled");
}
else {
radNumericTextBox1.disable();
label.addClass("LabelDisabled");
label.removeClass("LabelEnabled");
}
}
function SetCheckBox4State(checked) {
alert("CheckBox4");
var radNumericTextBox2 = $find(radNumericTextBox2ID);
var wrapperElement = $get(radNumericTextBox2._wrapperElementID);
var label = $(wrapperElemenet.getElementsByTagName("label")[0]);
if (checked) {
radNumericTextBox2.enable();
label.addClass("LabelEnabled");
label.removeClass("LabelDisabled");
}
else {
radNumericTextBox2.disable();
label.addClass("LabelDisabled");
label.removeClass("LabelEnabled");
}
}
Am I doing something improper? I'd rather not use an anonymous function...but maybe this just how things work?
This code:
.click( SetCheckBox1State(this.checked) );
Assigns the .click() function to be the output of this function: SetCheckBox1State(this.checked).
You will have to get rid of the argument (make it internal) and just pass the function name:
.click( SetCheckBox1State );

Categories