I'm making a chrome extension that has an options.html page.
On the options page I have 3 checkboxes. When one of the checkboxes is checked/unchecked the value of that checkbox is saved to- or removed from chrome.storage using chrome.storage.sync.set(). But I can't seem to retrieve the data once it is saved using chrome.storage.sync.get().
Here's the code I have:
options.html:
<div class="checkboxes">
<input id="test1" name="test1" type="checkbox">
<input id="test2" name="test2" type="checkbox">
<input id="test3" name="test3" type="checkbox">
</div>
options.js:
$(document).ready(function() {
var storage = chrome.storage.sync;
//Retrieve existing settings
$(':checkbox').each(function() {
$(this).prop('checked', function() {
var name = this.name;
storage.get(name, function(test){
console.log(test[name]);
});
});
});
$(".checkboxes").on("change", ":checkbox", saveSettings);
//Save or delete settings
function saveSettings() {
var name = this.name;
if($(this).is(':checked')) {
storage.set({name:'checked'},function(){
console.log("saved");
});
}
else {
storage.remove(name, function(){
console.log("removed");
});
}
}
});
Above outputs:
console.log(test[name]); > undefined
console.log("saved"); > saved
console.log("removed"); > removed
Why do I get "undefined"?
I tired the same thing using localStorage which worked fine on only option.js. But when I tried to retrieve the stored data on background.js it didn't work. I figured their localStorage details are not accessible to each other.
I should also mention I'm not the best at javascript/jquery and I'm still learning, so please excuse my mistakes.
You've got two main issues:
chrome.storage.sync.get is asynchronous, while the function in jQuery.fn.prop(propertyName, function(index, oldPropertyValue) ) must synchronously return the desired value.
storage.set({name:'checked'}, ...); will create a property called "name" with value "checked", not a property with the name as specified in the name variable with value "checked".
To solve the first problem, swap the order of operations: First read the preference, then set the property:
//Retrieve existing settings
$(':checkbox').each(function(index, element) {
var name = this.name;
storage.get(name, function(items) {
element.checked = items[name]; // true OR false / undefined (=false)
});
});
To solve the second issue, first create an object, assign the new property, and save the result. Note: Since a checkbox can only have two states, I recommend to not save the string "checked", but use a boolean (true / false):
function saveSettings() {
var name = this.name;
var items = {};
items[name] = this.checked;
storage.set(items, function() {
console.log("saved");
});
}
PS. When you're certain that you're dealing with checkboxes, use element.checked instead of $(element).is(':checked'). The former is shorter and faster. Using jQuery adds no value here. See also: When to use Vanilla JavaScript vs. jQuery?
Related
Note: I'm using vanilla js only.
I currently have a working script to add/remove classes via select options as well localStorage. All works great, see jsfiddle here.
Now, I'm wanting to add two checkbox's to perform in the same way. My problem is I'm not sure how to add checkboxes to my current localStorage script.
Here are my checkbox's:
<input type="checkbox" name="checkbox1" id="checkbox1" onchange="checkbox1(this)">
<input type="checkbox" name="checkbox2" id="checkbox2" onchange="checkbox2(this)">
And add/remove class on check/uncheck for checkbox1:
var checkbox = document.getElementById('checkbox1');
checkbox.addEventListener("change", checkbox1, false);
function checkbox1() {
var isChecked = checkbox.checked;
if (isChecked) {
[].map.call(document.querySelectorAll('body,.nc,.tags'), function(el) {
el.classList.add('classname');
});
} else {
[].map.call(document.querySelectorAll('body,.nc,.tags'), function(el) {
el.classList.remove('classname');
});
}
}
Works fine. Now I just need to add it to localStorage.
Here's my localStorage script that works for my select options (full example in my jsfiddle). How do I modify it to work for my checkbox's as well? I'm assuming I have to modify the second line to check for checkbox instead of options but I'm not sure how.
function selectTest(element) {
const a = element.options[element.selectedIndex].value;
setTest(a);
localStorage['test'] = a;
}
function setTest(a) {
if (a == "option1") {
//add+remove classes here
}
}
(function() {
if (localStorage['test'])
document.getElementById("test").value = localStorage['test'];
setTest(localStorage['test'])
})();
Here is the JS Fiddle if you just directly want to see the code https://jsfiddle.net/qctn08ym/44/
The idea is that since multiple checkboxes can be ticked and we need to preserve that we can store it as an array. Note that you can only store string in localStorage so you would need to convert the array to string and vice versa.
On any checkbox value changed we can call the function below that will set the localstorage
function checkboxChanged(e) {
//Get the id of all checked checkboxes and store them as array
// You can do this in loop as well by setting common class on checkboxes
var c = []
if(document.getElementById('checkbox1').checked) {
c.push('checkbox1');
}
if(document.getElementById('checkbox2').checked) {
c.push('checkbox2');
}
localStorage['test'] = c.toString();
}
Then you can just call the function below on document load
function checkOnLocalStorage() {
if(!localStorage['test']) return;
var checked = localStorage['test'].split(',');
checked.map((id) => {
document.getElementById(id).checked=true;
})
}
I have followed this JS Fiddle from this question.
Here's my HTML code:
<div id="paramStart">
<div id="gameType">
<div id="UserVsComputer" class="checkbox" style="margin-left: 8px;">
<label><input type="checkbox" value="">User vs Computer</label>
</div>
<br>
<br>
<div id="User1VsUser2" class="checkbox" style="margin-left: 8px;">
<label><input type="checkbox" value="">User1 vs User2</label>
</div>
</div>
I did in JavaScript:
var gameType = document.getElementById('gameType');
gameType.addEventListener('click', setGameType, false);
function setGameType() {
var checkInput = $('#gameType .checkbox > label > input');
console.log(checkInput);
checkedState = checkInput.attr('checked');
checkInput.attr('checked').each(function () {
$(this).attr('checked', false);
});
checkInput.attr('checked', checkedState);
}
But I get the following error:
TypeError: checkInput.attr(...) is undefined
I try to access the <input> tag for setting true to the clicked <input>
Where is my error?
Update
#Mohamed-Yousef
To get the array of checked inputs, I did:
var checkInput = $('#gameType > div > input[type="checkbox"]');
console.log(checkInput.attr());
I get:
TypeError: a is undefined jquery-latest.min.js:4:9978
This entire thing can be simply:
NOT capturing the current state:
$('#gameType').on('click','.checkbox',function(){
$(this).siblings().find('input[type="checkbox"]')[0].checked = false;
});
OR
$('#gameType').on('click','.checkbox',function(){
$(this).siblings().find('input[type="checkbox"]').prop('checked', false);
});
Un-check the other box no matter what the current checkbox state is:
$('#gameType').on('click','.checkbox',function(){
var checkBoxState = $(this).find('input[type="checkbox"]')[0].checked;
$(this).siblings().find('input[type="checkbox"]')[0].checked = false;
});
OR
Make the OTHER checkbox the opposite of this one:(NOTE: both cannot be "unchecked" using this.)
$('#gameType').on('click','.checkbox',function(){
var checkBoxState = $(this).find('input[type="checkbox"]')[0].checked;
console.log(checkBoxState);
$(this).siblings().find('input[type="checkbox"]')[0].checked = !checkBoxState;
});
EDIT: Note that this way, you can click the label as well as the checkbox which might enhance the user experience but you would need to decide that.
IF the syntax above is not desired you can also manage the property with jQuery as:
$(this).siblings().find('input[type="checkbox"]').prop("checked", false);
OR
EDIT: Here, we then use the .prop() to both get and set:
$('#gameType').on('click','.checkbox',function(){
var checkBoxState = $(this).find('input[type="checkbox"]').prop("checked");
console.log(checkBoxState);
$(this).siblings().find('input[type="checkbox"]').prop("checked", checkBoxState);
});
EDIT: here is another method using .is()
$('#gameType').on('click','.checkbox',function(){
var checkBoxState = $(this).find('input[type="checkbox"]').is(":checked");
console.log(checkBoxState);
$(this).siblings().find('input[type="checkbox"]').prop("checked", checkBoxState);
});
up to your html structure you can change the game type when user checked the checkbox and unchecked another one
var gameType = $('input[type="checkbox"]');
gameType.on('click', function(){
setGameType($(this));
});
function setGameType(el) {
if(el.is(':checked')){
$('input[type="checkbox"]').not(el).prop('checked' , false);
}
}
Working Demo
and about your code
$('#gameType .checkbox > label > input').attr();
Its an array of inputs not just one input to get attr for.. You can use it inside .each to get attr for each checkbox by using
checkInput.each(function () {
alert( $(this).attr('checked'));
});
I am trying to do a checkbox change so when it is clicked it pushes a value into my object. (yes i know push is a array method). So i wondering what i can do to make this work.. i have used a onclick event because jquery was not working for me.. here is my code:
My object is called Contact() and holds 'address1' in there. Contect() is a object NOT function. i just need to know how to push a object value into it?
<label><input type="checkbox" class="no-custom" id="CheckBox" onclick="CheckBox()" > <span class="BlackColor">Use my email.</span></label>
function CheckBox() {
Contact().push({Key: 'address1', Value: 'hello#hotmail.com' });
}
I would rather do my jquery way which is:
$(document).ready(function () {
$('#CheckBox').change(function() {
if($(this).is(":checked")) {
Contact().push({Key: 'address1', Value: 'hello#hotmail.com' });
}
});
});
But this was not firing on the checkbox being clicked.. can anyone guide me to know how to push a object value and sort my checkbox event.
Thanks
You have to initialize a contact:
var c = new Contact();
then in your code:
c.address1 = 'hello#hotmail.com';
It seems to fire the event as show in this fiddle http://jsfiddle.net/dzaLj0pv/1/
$(document).ready(function () {
$('#checkBox').change(function() {
if($(this).is(":checked")) {
alert("This is checked");
}
});
});
I'm trying to assign a function to a couple of checkboxes, but I only want them added based on a condition, in this case the step number of the form. This is a roundabout way of making the checkboxes readOnly AFTER they have been selected (or not). So, at step 1 I want the user to choose cb1 or cb2, but at step 2 I want to assign the function that will not let the checkboxes values be changed.
What am I doing wrong?
function functionOne() {
this.checked = !this.checked
};
if (document.getElementById("stepNumber").value == 2) {
document.getElementById("cb1").setAttribute("onkeydown", "functionOne(this)");
document.getElementById("cb2").setAttribute("onkeydown", "functionOne(this)");
}
You are passing the element in an argument, so use that:
function functionOne(elem) {
elem.checked = !elem.checked
};
You could also use properties:
document.getElementById("cb1").onkeydown = functionOne;
document.getElementById("cb2").onkeydown = functionOne;
function functionOne() {
this.checked = !this.checked
};
This is a solution that requires jquery but you can use the .click function to disable checkboxes once one is clicked.
Here is a working example:
http://jsfiddle.net/uPsm7/
Why not on the selection disable the checkbox?
Function onCheck(elm)
{
document.getElementById("cbValue").value = elm.value;
elm.disabled = true;
}
<input id="cbValue" type="hidden" />
Use the hidden input field to allow form to send data back to server.
Just wondering if there is any way to check if the value of a select box drop-down matches the original value at the time of page load (when the value was set using selected = "yes") ?
I guess I could use PHP to create the original values as JavaScript variables and check against them, but there are a few select boxes and I'm trying to keep the code as concise as possible!
That's not too hard at all. This will keep track of the value for each select on the page:
$(document).ready(function() {
$("select").each(function() {
var originalValue = $(this).val();
$(this).change(function() {
if ($(this).val() != originalValue)
$(this).addClass('value-has-changed-since-page-loaded');
else
$(this).removeClass('value-has-changed-since-page-loaded');
});
});
});
This will apply a new class value-has-changed-since-page-loaded (which presumably you'd rename to something more relevant) to any select box whose value is different than it was when the page loaded.
You can exploit that class whenever it is you're interested in seeing that the value has changed.
$(document).ready(function() {
var initialSelectValue = $('#yourselect').val();
// call this function when you want to check the value
// returns true if value match, false otherwise
function checkSelectValue() {
return $('#yourselect').val() === initialSelectValue;
}
});
PS. You should use selected="selected" not selected="yes".
On page load, create an array with the initial value of each select box indexed by name:
var select_values = [];
$(document).ready(function() {
$("select").each(function() {
select_values[$(this).attr('name')] = $(this).val();
});
});
later when you need to check if a value has changed:
function has_select_changed(name) {
return $("select[name="+name+"]").val() != select_values[name];
}
First, a snippet:
$('select').each(
function(){
if( this.options[ this.selectedIndex ].getAttribute('selected') === null ){
alert( this.name +' has changed!')
}
});
Now the explanation:
Assuming selectElement is a reference to a <select /> elementYou can check which option is selected using
selectElement.selectedIndex
To get the <option /> element which is currently selected, use
selectElement.options[ selectElement.selectedIndex ]
Now when you know which option element is selected you can find out if this element has the selected='selected' attribute (as in the source code, it doesn't change - this is not the same as .selected propery of a DOM node, which is true for the currently selected option element and changes when the selection is changed)