Keep checkbox status after page reload/refresh ajax - javascript

I am working around a script that keeps one or multiple checkbox values checked on page reloaded or refreshed. The code below was executed to maintain the checkboxes values but it's not working. Any help will be appreciated.
<script>
function onClickBox() {
let checked=$("#check").is(":checked");
localStorage.setItem("checked", checked);
}
function onReady() {
let checked="true"==localStorage.getItem("checked");
$("#check").prop('checked', checked);
$("#check").click(onClickBox);
}
$(document).ready(onReady);
</script>
This line of code return '<input type="checkbox" id="check" href="#"' + 'order_id="'+ data + '">Yes</>'; allows admin to check a checkbox, after which the code takes the ID and then runs the check_payment.php that has the query that inserts yes to that ID row.
aoColumnDefs: [
{
aTargets: [6],
mData: "userId",
mRender: function (data, type, full) {
return '<input type="checkbox" id="check" href="#"' + 'order_id="'+ data + '">Yes</>';
//return '<button href="#"' + 'order_id="'+ data + '">Yes</button>';
}
}
],
language: {
url: 'https://cdn.datatables.net/plug-ins/9dcbecd42ad/i18n/English.json'
}
});
$('#example').on( 'click', 'input:checkbox', function () {
var data = table.row( $(this).parents('tr') ).data();
var order_id = data['order_id'];
console.log(order_id);
$.ajax({
type: "POST",
url: 'check_payment.php',
data: "order_id=" + order_id,
});
} );

Here's a VanillaJS approach. We have document.querySelector now, so in my view, jQuery has been depreciated for a while. As far as I can tell your logic is solid, so I can only assume it's one of the jQuery calls that's breaking, and I honestly don't know which one.
// get element #check
var checkbox = window.check;
// checking and setting
isChecked = () => localStorage.getItem("checked") == "true";
setCheck = (v) => checkbox.checked = v;
// event handlers
onClickBox = () => localStorage.setItem("checked", checkbox.checked);
onReady = () => setCheck(isChecked());
// bindings
checkbox.addEventListener("click", onClickBox);
document.addEventListener("load", onReady);
Edit: I think what might be happening is the onLoad handler (or onReady, with jQuery) is never firing because the code is embedded in the body. If the script is in the head, use the eventHandler; if the script is in the body, just call onReady() after setting the click handler for the checkbox.

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

Slickgrid changes the ID from my data and dont clean up the empty row

Im trying to update my grid without the need for refreshing! Right now, it updates only the grid, but dont know why, it changes the id to the last one inserted and dont "clean up" the empty row! When I try to insert data, it clears it .
Im kinda new with ajax and slickgrid! I've tried to see the ajax example from slickgrid, but I got some errors!
Do I need to re-upload the onCellChange and so on ? I just wanted to update th grid with the new data.
Any help?
Thanks in advance
So, I've tried re-draw the table re-using my actual drawning code, but im failling to re-draw with correct data.
Function to re-draw grid
function desenhaGrid() {
$("#myGrid").ready(function () {
$(function () {
$.ajax({
type: "GET",
url: '/SlickGrid/GetData',
dataType: 'json',
success: function (jsonResult) {
for (var key in jsonResult) {
if (jsonResult.hasOwnProperty(key)) {
//print table
var d = (data[key] = {});
for (var i = 0; i < data.length; i++) {
d["#"] = i + 1;
}
d["id"] = jsonResult[key].id;
d["t_nome"] = jsonResult[key].t_nome;
d["t_prof"] = jsonResult[key].t_prof;
d["t_data"] = jsonResult[key].t_data;
d["t_morada"] = jsonResult[key].t_morada;
d["t_percCompleto"] = jsonResult[key].t_percCompleto;
}
}
grid = new Slick.Grid("#myGrid", dataView, columns, options);
dataView.beginUpdate();
grid.invalidateAllRows();
dataView.setItems(data);
grid.render();
dataView.endUpdate();
}
});
});
});
}
and this is my onAddNewRow
grid.onAddNewRow.subscribe(function (e, args) {
var idData = jsonResult[key].id + 1;
var item = { "id": idData, "t_nome": '', "t_prof": '', "t_data": '', "t_morada": '', "t_percCompleto": '' };
$.extend(item, args.item);
dataView.addItem(item);
//if user press enter
grid.onKeyDown.subscribe(function (e) {
var keyPressed = event.keyCode || event.which;
if (keyPressed == 13) {
alert("add");
var myJSON = JSON.stringify(item);
$.post("/SlickGrid/addGridEnter", $("input[name=mydata]").val(myJSON));
console.log(myJSON);
desenhaGrid();
}
});
});
I expected it to re-draw my grid with all the data. Instead, its changing all the id's to the last one inserted and when I try to insert data in the last row, wont let me (it clears it after I leave the cell).
UPDATE:
I've udpate the function to draw the grid
function desenhaGrid() {
$("#myGrid").load(function () {
$(function () {
$.ajax({
type: "GET",
url: '/SlickGrid/GetData',
dataType: 'json',
success: function (jsonResult) {
dataView.beginUpdate();
grid.invalidateAllRows();
dataView.setItems(jsonResult);
dataView.endUpdate();
grid.render();
}
});
});
});
}
I don't think this is a SlickGrid issue. There are all kind of problems with the javascript. For example:
why are you using $("#myGrid").ready( ? the ready event only fires when the DOM has finished loading
the entire copy operation from jsonResult to data just ends up with the same data. why not use jsonResult directly?
the section for (var i = 0; i < data.length; i++) { d["#"] = i + 1; }
runs once for each row added to data, it should just run once at the end, outside of the loop
you are subscribing to the keydown event once for each row added to the grid. you should just subscribe once. listening for an Enter key is also a very poor method of determining if a row has been entered. what if someone clicks on another row before pressing Enter?
Slickgrid is a client-side grid. This means data does not need to be persisted after every change. It's a common approach to use a 'save' button, or detect if the active row has changed.

Jquery on click event is not working when ajax call is running at loop

I have two ajax functions that one is recursively working at loop and other is working when click event invoked. I tested both of the functions that are able to work properly. But when i start recursive function button event is not invoked.
Function that works on click event GET Content from ActionResult (MVC)
function UpdateRequests(url, state, id, cell)
{
$.ajax({
type: "GET",
url: url + id,
success: function (result) {
if (result == "OK")
{
cell.fadeOut("normal", function () {
$(this).html(state);
}).fadeIn();
}
else if(result == "DELETE" || result == "CANCEL")
{
cell.parent().fadeOut("normal", function () {
$(this).remove();
});
}
else
{
$(".modal-body").html(result);
$("#myModal").modal();
}
},
error: function () {
alert("Something went wrong");
}
});
}
Recursive function GET partial view from ActionResult (MVC)
function RefreshRequests()
{
if (isListPage())
{
var id = PageId();
var url = "/Home/List/" + id;
}
else
{
var url = "/Home/Index";
}
$.ajax({
type: "GET",
url: url,
success: function (data) {
$(".ajaxRefresh").html(data);
EditPageHeader();
},
complete: function () {
setTimeout(RefreshRequests, 2000);
}
});
}
Click event
$(".tblRequests").on("click", button, function (e) {
e.preventDefault();
var id = $(this).data("id");
var currentRow = $(this).closest("tr");
var cell = currentRow.children('td.requestState');
UpdateRequests(url, state, id, cell);
});
Main
$(document).ready(function () {
EditPageHeader();
RefreshRequests();
ButtonEvent(".btnPrepare", "/Home/Prepare/", "PREPARING");
ButtonEvent(".btnApprove", "/Home/Approve/", "APPROVED");
ButtonEvent(".btnCancel", "/Home/Cancel/", "CANCELED");
RefreshRequests();
});
Assumptions:
The Ajax Calls bring you data that end up as HTML elements in the modal body.
These new elements added above need to respond to the click event (the one that doesn't work correctly right now)
If the above 2 are true, than what is happening is you are binding events to existing elements (if any) and new elements (coming from API response) are not bound to the click event.
The statement
$(".tblRequests").on("click", button, function (e) {
...
})
needs to be executed every time new elements are added to the body. A better approach for this would be to define the event handler as an individual method and then bind it to each new element.
var clickHandler = function (e) {
e.preventDefault();
var id = $(this).data("id");
var currentRow = $(this).closest("tr");
var cell = currentRow.children('td.requestState');
UpdateRequests(url, state, id, cell);
}
// Then for each new record that you add
$(".tblRequests").on("click", button, clickHandler);
It would be helpful if you can try to explain what exactly you are trying to achieve.
Problem is that the $(this) will hold all elements of the selector. And will also now with one as it will be triggered one time and then never again. Also as can be seen from here, delegate events should be at the closest static element that will contain the dynamic elements.
function ButtonEvent(button, url, state)
{
$("body").on("click", button, function (e) {
e.preventDefault();
var button = e.target;
var id = $(button).data("id");
var currentRow = $(button).closest("tr");
var cell = currentRow.children('td.requestState');
UpdateRequests(url, state, id, cell);
});
}

Class not changing after get request Jquery

I'm having trouble changing the class after making a jquery get request.
code:
<script>
//global variable
var table = []
var numberofaccounts = 0
$(document).ready(function() {
$('#form1').validate();
// add numbers to select ids
$(".select_changer").each(function(){
numberofaccounts++;
var new_id = "select_class"+numberofaccounts;
$(this).addClass(new_id);
});
$('#apply_btn').click(function() {
table = []
var count = 0;
var text = "";
var tracker = 0
$('#stats_table tr').each(function(){
count = 0;
text = "";
$(this).find('td').each(function(){
count++;
if (count == 4) {
text += $( ".select_class"+ tracker + " option:selected" ).val();
} else {
text += " " + $(this).text() + " ";
}
})
table.push(text);
tracker++;
});
$.post("/apply_changes", {"data": JSON.stringify(table)}, function(data) {
var res = JSON.parse(data);
if (res.data == true){
$('#updated').text("Update Successful").css('color', 'green');
$.get("/", function( data ) {
$('#stats_table').load("/ #stats_table");
numberofaccounts = 0
$(".select_changer").each(function(){
numberofaccounts++;
var new_id = "select_class"+numberofaccounts;
$(this).addClass(new_id);
});
});
} else {
$('#updated').text("Update Unsuccessful").css('color', 'red');
}
});
});
});
</script>
So when the page first loads this method changes the class on dynamically created select elements.
$(".select_changer").each(function(){
numberofaccounts++;
var new_id = "select_class"+numberofaccounts;
$(this).addClass(new_id);
});
After I make a post to flask the if the response data is true I go ahead and make a get request to grab the updated items from the db. I then refresh the table. This works great if I make one request. However on the second post nothing happens. This is because the classes that I modified at the start of the page load no longer exist. So i added the method above to also trigger after the get response (I also tried at the end of the post response). The problem is that the method doesn't seem to run again. The classes aren't there and as a result when I go to make another post request it can't find the element. How do I go about fixing this?
Things to note: The get request is necessary, the ids and classes cannot be statically assigned.
You are trying to assign classes before you even refresh your table.
$('#stats_table').load("/ #stats_table"); is called asynchronously and returns before it even completes.
You need to put you code, for assigning classes, inside the complete callback of your .load() call:
$('#stats_table').load("/ #stats_table", function() {
numberofaccounts = 0
$(".select_changer").each(function(){
numberofaccounts++;
var new_id = "select_class"+numberofaccounts;
$(this).addClass(new_id);
});
});

JS JQuery Method to clear inputs works too well

I made a method for my UI class that clears inputs in a containing div.
The problem is, once it is called, The checkboxes never get set through AJAX calls until you refresh the page. The example below is for my group/user management. If you click on a group to edit, a jQuery UI dialog pops up with the attributes and permissions of that group. If you cancel, and try to add a new one, the inputs are cleared. If you then goto edit a group after that, the inputs are not updated.
Edit: It seems the checkboxes stop working if the cancel button is clicked regardless if my clearInputs method is called or not.
Here is the method of the UI class:
clearInputs: function(container) {
$(container + " :input").val("");
$(container).find('input[type=checkbox]:checked').prop('checked', false);
}
And an example of the calling code (copied from my project, but I cut some of the fat out...
/* The user clicks the edit group button... */
$(document).delegate('.group_edit', 'click', function() {
var groupId = $(this).attr('id').replace("group_edit_", "");
// This call to the clearInputs method is commented out,
// and behaves as I described above.
// ui.clearInputs("#dialogGroup");
$.ajax({
type: "POST",
url: "ajax.users.php",
data: {
action: "get_privs",
group: groupId
},
success: function (result) {
if (result.success == true) {
// Set the name value
$("#name").val(result.GroupName);
// Update each of the checkboxes
$.each(result.privs, function(priv, grant) {
grant = Boolean(parseInt(grant));
$('#dialogGroup input[value=' + priv + ']').prop('checked', grant);
});
/* Create the dialog */
$("#dialogGroup").dialog({
buttons: {
"OK" : function () {
$(this).dialog("close");
var form_data = new Array();
$.each($("input[#name='cbox[]']:checked"), function() {
form_data.push($(this).val());
});
$.ajax({
/* Saves the form data */
});
},
"Cancel": function() {
ui.clearInputs("#dialogGroup");
$(this).dialog("close");
}
}
});
And finally to add a group:
$(document).delegate('#group_add', 'click', function() {
var dialog = "#dialogGroup";
// ui.clearInputs(dialog);
$(dialog).dialog({
modal: true,
title: "Create Group",
buttons: {
"OK": function() {
$(this).dialog("close");
$("#dialogNotify").html("Saving...");
$("#dialogNotify").dialog('open');
var form_data = new Array();
$.each($("input[#name='cbox[]']:checked"), function() {
form_data.push($(this).val());
});
$.ajax({
/* Save the form data */
});
},
Cancel: function() {
$(this).dialog("close");
}
}
});
});
I hope I included everything... If not I will update.
try this:
$( document ).ready(function()
{
var search_on = $('#formX');
$( search_on )
//CHANGE "input" for "input,select" to search all fields
.find('input')
.each(function( e )
{
if( $(this).attr('type') == 'radio' || $(this).attr('type') == 'checkbox' )
{
$(this).attr('checked',false);
//USE RESET() IF IS A FORM FIELD
$(this).reset();
}
//IF IS A DROPDOWN
/*
else if( $(this).attr('type') == undefined )
{
$(this).find('option').attr('selected',false);
}
*/
else
{
$(this).val('');
//USE RESET() IF IS A FORM FIELD
//$(this).reset();
}
});
});
Or use this function( if is a form ):
jQuery.fn.reset = function () {
$(this).each (function() { this.reset(); });
}
And Call
$('#formX').reset();
I figured it out. The problem was inside of my method, I had:
clearInputs: function(container) {
$(container + " :input").val("");
$(container).find('input[type=checkbox]:checked').prop('checked', false);
}
The first line of the method, I guess is doing something to all inputs.
If you change the first line to
$(container + " :input[type=text]").val("");
It works fine...

Categories