I am quite new to programming but, eager to learn. I am trying to create an app which keeps tracks of goals (I didn't like the ones I found, so I want to make my own). Anyways, there are checkboxes to be checked and when I open a new tab at a later point, I want the checked boxes to be checked. Here is a little snippet from my code:
<label class="container">Drink 2 liters of water
<input type="checkbox" checked="checked">
<span class="checkmark"></span>
</label>
How can I use the chrome.storage function to remember that I clicked this box?. Thank you for your help!.
At a high level, you'll want to use chrome.storage to save your changes any time a checkbox is clicked - or when a button is clicked.
If you're wanting to save every time the checkbox is clicked, you'll bind a listener to the change event of the checkboxes. Then, call chrome.storage to save.
document.querySelectorAll('input[type="checkbox"]').forEach(elem=>{ //Get all input checkboxes
elem.addEventListener('change',(event)=>{ //Add a change listener
const key = event.target.name; //get the name value from the input element
const value = event.target.checked; // has it been checked?
chrome.storage.local.set({[key]: value}, ()=> { //save it
console.log('Value is set to ' + value);
});
})
})
Saving on button press will be similar. You'll bind a click listener to the button then in the callback, select all of the checkboxes and loop over them to save.
When the page is loaded, you'll need to fetch all of the saved values, and set the check state.
chrome.storage.local.get(['goal1','goal2'],(results)=>{ //Fetch goal1, goal2, goalN... from chrome.storage
//.get returns a keyed object you can loop over.
Object.keys(results).forEach((goal)=>{
//Set the check state of each goal.
document.querySelector(`input[name="${goal}"]`).checked = results[goal];
})
})
Related
Here is a summary of my problem:
We have a table with check boxes and file names in a file sharing application.
At the top of the table is a Set Preview button that lets the preview carousel to always display the default preview item.
Users can click a check box and click the set preview button and the preview item will change and the preview carousel will update.
I have a test automation script that tests this behavior written in JavaScript using TestCafe, NodeJS & ES6.
When we test the set Preview we click the checkbox for the item that we want to set the preview for.
Then we click the Set Preview button.
Confirm that the preview icon is set on that row where we just clicked the checkbox.
There are some things to note:
When the user clicks the checkbox, if the checkbox that is selected already has the preview set to that row, than the set preview button is disabled.
Also when the set preview is clicked, whatever row was checked is automatically unchecked.
So if a row that already has a preview set on it is checked then the user will not be able to click the set preview and hence the checkbox is never unchecked.
When the loop resets and the next item is checked, there are now two items that are checked and the set preview is disabled, because it's not possible to set two items with the set preview.
I've added code to check if the current row is checked and if it is; to uncheck it.
The trouble is that when I check the state of the checkbox to see if it is checked:
var checkbox = await projectDetails.tableRowCheckBox(fileName);
if (checkbox.checked === true) {
This returns false, even though the checkbox is checked. So it never gets unchecked and the script is failing.
The TestCafe website gives a similar example of how to do this here:
https://devexpress.github.io/testcafe/documentation/test-api/actions/click.html
So I figured it should work, and there are a few other forms out on the internet that show similar if-condition checks on check-boxes, so this seems like valid code, but yet it still isn't working.
One possible solution I haven't yet tried is to check if the preview row is already set to the current row, and if it is to skip that row completely. However, even if that solves my over-all problem, I'd still like to solve this problem. That is why I have posted it here.
EDIT: On another note, before I added the if-condition (that is failing), it seemed to me that I had the click in there, and I ran the script, and the cursor moved to the checkbox to unselect it, but it didn't actually uncheck the checkbox. Although I could have been mistaken and it was just re-selecting the checkbox after doing the set Preview, which itself automatically unselected the checkbox. (OK now my head is really going in circles)
More complete code:
for (var j = 0; j < dataElementCount; j++) {
// Act
await t.click(projectDetails.tableRowCheckBox(fileName).with({ selectorTimeout: 30000}));
await t.click(projectDetails.setPreviewButton, { selectorTimeout: 5000 });
// Assert
var previewRow = projectDetails.previewRow;
// NOTE: Do not feed in test data that doesn't support the preview, or setting the preview will fail for that item.
// tif and tiff files are not supported for the preview.
await t.expect(projectDetails.rowFileName(previewRow).textContent).eql(fileName);
// Cleanup
// We have to now unselect the item that was just selected, because if we don't then when we go to select the next one,
// the setPreview will fail, because two items would be selected at the same time.
// Yes multi-select is now a thing, and we have to deal with it.
// NOTE: Multi-select may be a thing, but it really only gets in our way with this workflow,
// if we click a checkbox above for an item that already has the preview set.
// After the SetPreview button is clicked the checkbox is unclicked,
// but if the preview is already set for an item, then the item never gets unclicked.
var checkbox = await projectDetails.tableRowCheckBox(fileName);
if (checkbox.checked === true) {
await t.click(projectDetails.tableRowCheckBox(fileName).with({ selectorTimeout: 30000}));
} else {
await t.wait(5000);
console.log('DENIED: The checkbox is NOT checked for the checkbox with the row filename: ' + fileName);
await t.wait(5000);
}
}
Selectors:
const rowFileName = row => row.find('td[data-label="Name"] span');
const setPreviewButton = Selector('div.table-actions')
.find('a.set-preview-button');
const tableRowCheckBox = filename => tableRowName(filename)
.sibling()
.find('td.checkbox-cell span.check');
const previewRow = Selector('td.table-preview-column span')
.filter(node => node.childElementCount === 1)
.parent('tr');
Sorry I cannot give access to the website itself, as that would be a breach of Intellectual Property.
I hope I've included all the information that I can to find a possible solution.
Thank you in advance for any help you can give!
The method:
const tableRowCheckBox = filename => tableRowName(filename)
.sibling()
.find('td.checkbox-cell span.check')
is targeting a <span class="check"> element.
So when you are calling this helper method:
var checkbox = await projectDetails.tableRowCheckBox(fileName);
you obtain a <span>. The problem is that the checked property only exists for <input type="checkbox"> element and does not exist on <span> element.
This means checkbox.checked is always undefined
Your code should be:
const tableRowCheckBox = filename => tableRowName(filename)
.sibling()
.find('td.checkbox-cell span')
.nth(0);
const checkbox = projectDetails.tableRowCheckBox(fileName);
const isChecked = await checkbox.hasClass('check');
if ( isChecked ) {
...
}
I have a problem: my website is searching for checked checkboxes with a javascript.
$(function () {
var $allELements = $('.input-box');
var $selectedElementsListing = $('#selectedElements');
var $selectedElementsLabel = $('#selectedElementsLabel');
var $elementInfo = $('.elementInfo ');
$allELements.on('click', function () {
$selectedElementsListing .html(
$allELements.filter(':checked').map(function (index, checkbox) {
return '<div>' + checkbox.title + '</div>';
}).get().join('')
);
if ($selectedElementsListing .text().trim().length)
{
$selectedElementsListing .show();
$selectedElementsLabel.show();
$elementInfo.show();
}
});
});
So it is searching for checked checkboxes on my main page and is listing the name of the checkboxes on the lower left hand side (as information for the user).
My HTML looks like this:
<div class="elementInfo" >
<p>
<strong id="selectedElementsLabel" ><u>Ausgewählte
Magazine:</u></strong><br />
<span id="selectedElements"></span>
</p>
</div>
And it takes the checkbox names from this input field:
<input class="input-box" title="[[ElementName]]" type="checkbox" id="A[[ID]]" name="ID[]"
value="[[ID]]" checked="[[checked_element]]" />
When I press reload, the information bar for the selected checkboxes isn't appearing. It is showing the checked checkboxes only if I press again any of them (then it shows all which were also selected)
Every time the page is refreshed the DOM is re-rendered and no state is being stored anywhere. To preserve the state of checked boxes you can use localStorage to store the checked state and then upon page load you can read the localStorage and execute a function that checks them by checking local storage data.
// call this every time someone checks a box
window.localStorage.setItem('some key name of data', 'some data structure with checkbox state')
//Do this every time page is loaded
window.localStorage.getItem('previously used key name')
P.S. I assumed you don't have a backend api calling every time someone checks a box where you are preserving state
for further info do visit
A good read to understand state management
Tried to solve this multiple ways. 1. by simply adding the normal html "checked" default option to radio buttons in my form and 2. having js functions do it, being the gist of the ideas tried.
The issue: I'm finding that no matter how I do it, if the radio is designated as checked by default (before the user makes his/her choice), anything done after that will not be saved correctly (if at all) in localStorage. localStorage WILL save the initial default selections, however but, nothing can be changed from then on (even after "physically" selecting another option).
I know localStorage is working because if I leave off the default designation (and for the rest of the inputs) it functions perfectly.
The form code:
<label>Who is the contact person for this event?<span class="requiredtext">*</span></label>
<input type="radio" name="Contact_Person" id="Contact_Person1" value="Submitter is the contact person" onclick="contacthide()" checked required> I am<br />
<input type="radio" name="Contact_Person" id="Contact_Person2" value="Submitter is not the contact person" onclick="contactshow()" required>
The localStorage save code:
function localStoragefunctions() {
localStorage.clear();
if (Modernizr.localstorage) {
//Set variable to show that data is saved
localStorage.setItem("flag", "set");
//Save radio and checkbox data
$(window).bind('unload', function() {
$('input[type=radio]').each(function() {
localStorage.setItem('radio_' + $(this).attr('id'), JSON.stringify({
checked: this.checked
}));
});
});
The code that spits it back out if the user goes back to make changes before final submission:
$(document).ready(function() {
if (Modernizr.localstorage) {
//Browser supports it
if (localStorage.getItem("flag") == "set") {
$('input[type=radio]').each(function() {
var state = JSON.parse(localStorage.getItem('radio_' + $(this).attr('id')));
if (state) this.checked = state.checked;
});
Other than this, I have a confirmation page that grabs all of the variables stored in localStorage and presents them to the user for final inspection before they hit submit for good.
That consists of: var ContactPerson = localStorage.getItem('Contact_Person'); and then a document.write that spits out html and the variable's value. Again, this works fine if I don't try to set default radio choices (and works great for all other input types).
The ideal outcome would be choosing the most likely radio button choices by default so that it could possibly save the user time. I'd like to not have to present them with a form where they have to physically click each radio button if I can "make that decision for them" before hand.
Hope this all makes sense!
I know this an old question, but I've been troubleshooting a similar issue and thought I'd share my solution.
When you set your localStorage item, you are saving both radio inputs and their values, b/c your using the ID attribute as your key.
localStorage.setItem('radio_' + $(this).attr('id'), JSON.stringify({ checked: this.checked }));
This could be ok, but I've taken a different approach. And, I maybe missing something, so comments are welcome.
Instead, I use $(this).attr('name') to set the key. As a result, when either radio button in selected, you are saving the value to the same localStorage key.
In my scenario, I'm storing many inputs to localStorage, so my solution is a bit abstract. I'm calling saveToLocalStorage() using jQuery's .change() method on each input. Also, I'm saving the input's value directly to localStorage.
function saveToLocalStorage(input) {
if ( $(input).attr('type')=='radio' ) {
localStorage[$(input).attr('name')] = $(input).val();
} else {
localStorage[$(input).attr('id')] = $(input).val();
}
}
When retrieving from localStorage, I had to check if the localStorage key:value pair matched the radio input before selecting it. Otherwise, I was selecting both radio inputs. Note, in my scenario, I'm working with jQuery 1.4.4, hence the attr('checked', 'checked').
$('input[type=radio]').each(function() {
var key = $(this).attr('name');
var val = localStorage[key];
if ( $(this).attr('name') == key && $(this).attr('value') == val ) {
$(this).attr('checked', 'checked');
}
});
Example on JS FIddle.
The question is:
If the first click is on the radio button, it behaves normally; But if the first click is on span text (i.e. aaaa), it can not get the checked radio.
Please tell me why and how I can make it the same.
This code, which happens when the radio button is clicked:
var obj = $(e.target||e.srcElement).parent();
score = obj.find('input:checked').val();
Puts the parent in the obj variable, which is the containing DIV. This contains both of the radio buttons. It then finds the FIRST checked input element in that DIV, which is always the one with the 'first' value after it is checked.
You should just get the value of the item which was clicked:
score = $(e.target||e.srcElement).val();
This can be rewritten as
score = $(this).val();
Here's a working example: http://jsfiddle.net/RPSwD/10/
See new fiddle.
The problem is this line:
score = obj.find('input:checked').val();
Change it to:
score = $(this).val();
The reason for this is that you're looking for the selected item in the div but on the first click, the item has yet to become selected. Given that the event is targeted at the radio button, you can assume that radio is the selected one.
Note also that you don't need to use e.target||e.srcElement. jQuery takes care of this for you. Use $(this) instead.
Additionally, you need to set a name on the radio buttons to stop both from becoming selected. Alternatively, if having both selected is desired behaviour, use check boxes instead.
You don't need to use any of the event properties:
var score = $(this).val(); // in your '.x' click handler
$('.y').click(function(e) {
$(this).prev('.x').click();
});
just wrap your radio button inside label tag like this
<label for="radio1">
<input type=radio class="x" id="radio1" value="First"/>
<span class="y">aaaa</span>
</label>
No need for extra jquery or javascript
check the demo here
I have a page that displays a list of records. The user can select the record status using radio buttons, e.g.:
<div id="record_653">
<label><input type="radio" name="status_653" value="new" checked/>new</label>
<label><input type="radio" name="status_653" value="skipped" />skipped</label>
<label><input type="radio" name="status_653" value="downloaded" />downloaded</label>
</div>
I am using JQuery to send the changes made by the user back to the server, where I use them to update the database. This is a simplified version of what I do:
$("#record_653").click(
function(event) {
var url = ...,
params = ...;
post(url,params);
});
The problem is that this code will create requests even if the user clicks the same button that was previously checked. What I actually want is the "on change" event, except its behavior in Internet Explorer is not very useful (e.g. here).
So I figure I somehow have to identify if the click event changed the value.
Is the old value stored somewhere (in the DOM? in the event?) so I could compare against it?
If not, how should I store the old value?
The old value is not stored someplace where you can query it, no. You will need to store the value yourself. You could use a javascript variable, a hidden input element, or jQuery's data() function.
EDIT
The jQuery data function provides access to a key-value-pair data structure as a way to store arbitrary data for a given element. The api looks like:
// store original value for an element
$(selector).data('key', value);
// retrieve original value for an element
var value = $(selector).data('key');
A more developed thought:
$(document).ready(function() {
// store original values on document ready
$(selector).each(function() {
var value = $(this).val();
$(this).data('original-value', value);
})
// later on, you might attach a click handler to the the option
// and want to determine if the value has actually changed or not.
$(selector).click(function() {
var currentValue = $(this).val();
var originalValue = $(this).data('original-value');
if (currentValue != originalValue) {
// do stuff.
// you might want to update the original value so future changes
// can be detected:
$(this).data('original-value', currentValue);
}
});
});
$('#record_653 input:radio').each(function() {
$(this).data('isChecked', $(this).is(':checked'));
$(this).click(function() {
if ( $(this).is(':checked') !== $(this).data('isChecked') ) {
// do changed action
} else {
$(this).data('isChecked', !$(this).data('isChecked') );
}
})
});
This was complicated to do in my head but I think you want something like this.
As was suggested by meder and Ken Browning, I ended up using JQuery's data() to store the previous value and check against it on every click.
Storing an "is checked" boolean for each input radio is one solution. However you need to maintain this value. So in the click event handler, in addition to changing the "is checked" of the current input, you need to find the input that was previously checked and change its "is checked" data to false.
What I chose to do instead was to store, in the parent element, the currently checked object. So my code looks something like:
$(document).ready(
function() {
// find the checked input and store it as "currChecked" for the record
$("#record_653").data("currChecked",
$(this).find("input:radio:checked")[0]);
// add the click event
$("#record_653").click( function(event) {
if ($(event.target).is("input:radio") &&
event.target !== $(this).data("currChecked"))
{
$(this).data("currChecked", event.target);
handleChangeEvent(event);
}
});
});
}
);
Thanks
I had the same problem, but with FF I managed to deal with it using the onchange event rather than the onclick.
This is exactly what I was looking for to deal with IE7. Works like a charm!
Thanks for the detailed solution!