I have this in my HTML. Ignore any inline style, I'm testing,
<label class="toggle" style="float: right;">
<input id="check" type="checkbox" ng-model="check" ng-change="funCheck(check)">
<div class="track">
<div class="handle"></div>
</div>
</label>
<div ng-init="fromClock='01:00'; toClock='03:30';">
<clock-editor from="fromClock" to="toClock"
on-change="fromClock = from; toClock = to; funClock(from, to);">
</clock-editor>
<strong>{{fromClock}}</strong>
<strong>{{toClock}}</strong>
</div>
That's a toggle radio button and a clock.
Then I have these two functions in my controller:
$scope.funCheck = function(check) {
alert(check);
};
$scope.funClock = function(f_from, f_to) {
console.log(f_from + "---" +f_to)
$scope.check = false;
}
};
When the toggle is turned on I send the time from the clock somewhere. This works alright. However, what I want to do is uncheck the toggle if the time was changed.
I can do that with document.getElementById('check').checked = false; and the toggle moves back, but the ng-change on that radio won't fire again until I double check it. Like the value didn't change even if I can see how it's turned off visually.
ng-model does not work on strong element and there is no ng-change event for strong element. So basically you can achieve this by using two watch variables like this, Hope this will help you.
$watch(function(){
return $scope.fromClock;
}, function() {
$scope.funCheck();
})
$watch(function(){
return $scope.toClock;
}, function() {
$scope.funCheck();
})
The whole point of using angular is the fact that you shouldn't have to edit the DOM manually like you're doing.
Change this part of your code which unchecks the checkbox
$scope.funClock = function(f_from, f_to) {
if (document.getElementById('check').checked) {
document.getElementById('check').checked = false;
}
};
to
$scope.funClock = function(f_from, f_to) {
if($scope.check){
$scope.check = false;
}
};
Also, you shouldn't care about checking if it's already checked or not as if you set the checked to false and it's already false there will be no change so just remove the if statement completely.
Edit
Seems like ng-change will only fire if there is a change on the input itself and not if that change has happened programmatically, so there are two ways to do this.
Call the change function inside of the funClock.
This would be the code for that
$scope.funClock = function(f_from, f_to) {
if($scope.check){
$scope.check = false;
funCheck($scope.check);
}
};
Add a watch for check.
Or the code for the watch
$scope.$watch('check', function(newValue, oldValue) {
if (newValue != oldValue) {
funCheck(newValue);
}
});
In angularjs , we cann't directly change elements value. we need to
use $compile . First include it in controller and then make use of
it like wise -
var list = '<input id="check" type="checkbox" ng-model="check" checked ng-change="funCheck(check)">';
var selctr = $("#selector");
var ele = angular.element(list);
compiled = $compile(ele);
selctr.html(ele);
compiled($scope);
Related
I have many checkbox with onchange event that change line color where is checked :
<input type="checkbox" onchange="cocheCommande($(this))" name="${NAME_SELECTION}" value="<%=command.getCdeId()%>" />
function cocheCommande(chk)
{
alert("test cocheCommande");
var tr=chk.closest('tr');
if (chk.is(':checked'))
{
tr.css('background','#33EE33');
tr.nextUntil("tr.entete","tr").css('background','#FFFF33');
}
else
{
tr.css('background','#D0EED0');
tr.nextUntil("tr.entete","tr").css('background','#EEEED0');
}
}
I have a function that allows to check everything or uncheck. But if I use, onchange event is never call even though everything is checked.
Why ? And how can I do ?
As others said, you can't use $ in the html template; you can, however, pass this as the argument to your onchange handler:
HTML:
<input onchange="change(this)" type="checkbox" />
JS:
function change(elem) {
var element = $(elem);
console.log(element.next())
}
https://plnkr.co/edit/dx8GoJxHwKa52VFCkn2G?p=preview
This is the html:
<div class="btn btn-stock-report" id="superman">
Superman <input type="checkbox" name="superman" />
</div>
this is the JQuery:
$('#superman').on('click', function () {
if ($(this).children('input:checkbox:first').is(':checked')) {
superman = true;
$(this).children('input:checkbox:first').removeAttr('checked');
}
else {
superman = false;
$(this).children('input:checkbox:first').attr('checked', 'checked');
}
console.log("superman: " + superman);
});
What I'm trying to achieve it simply change the state of the child checkbox and change the value of a superman variable, but for some reason it always prints out superman: false in the console log. Even when I manually check the checkbox and click the div, even though the checkbox is now checked, it reports superman: false
What could be causing this?
You could just change the <div> to <label> and get rid of all the jQuery code and it will just work.
You should use .prop() instead of attr as checked is property of checkboxes. also you can narrow down your code to:
$('#superman').on('click', function () {
var chk = $(this).find('input:checkbox:first')
chk.prop("checked", !chk.prop("checked"));
});
Working Demo
$('#superman').on('click', function () {
superman = !$(this).children('input:checkbox:first').is(':checked');
$(this).children('input:checkbox:first').prop('checked',superman);
console.log("superman: " + superman);
});
I'm dynamically building a set of checkboxes. Clicking any of the checked boxes should uncheck the first (index wise) checked box. Clicking any of the unchecked boxes should check the last unchecked box.
I'm building the checkboxes using ng-repeat like this:
<input
type="checkbox"
ng-checked="values[$index]"
ng-repeat="n in values track by $index"
ng-click="click($event,$index)" />
And my controller looks like this:
.controller("myCtrl", function ($scope) {
$scope.values = [true,true,true,true];
$scope.click = function (event,n) {
event.preventDefault();
if ($scope.values[n] === true) {
$scope.values[$scope.values.indexOf(true)] = false;
} else {
$scope.values[$scope.values.lastIndexOf(false)] = true;
}
}
Here's a codepen of it all together http://codepen.io/anon/pen/rVLewJ
The problem that I'm running into is that using preventDefault seems to prevent ng-checked from updating the rendering of the box you click on (the others boxes re-render correctly). This causes the display to become out of sync with $scope.values.
Likewise, removing preventDefault doesn't prevent the box you're clicking on from changing its rendering, but (I believe because of ng-repeat's conservative re-rendering) ng-checked doesn't fire so it also gets out of sync.
I'm not using ng-changed because I'm specifically trying to prevent the checkboxes from changing if you're clicking on the "wrong" one. Regardless, I've tried using it instead of ng-clicked and it didn't fix anything.
I've tried using ng-model instead of ng-checked, but that seemed to prevent $scope.values from changing at all. Using $scope.$apply(), didn't help. Some of the things I've read have lead me to think I may need to use $watch but I'm teaching myself Angular with this project so I'm not sure exactly how to apply that.
Update
Nagasimha Iyengar provided a working solution here which I've simplified thusly
<input
type="checkbox"
ng-model="values[$index]"
ng-repeat="n in values track by $index"
ng-change="click($index)" />
Controller:
.controller("myCtrl", function ($scope) {
$scope.values = [true,true,true,true];
$scope.click = function (n) {
if ($scope.values[n] === true) {//clicking on unchecked box
$scope.values[n] = false;
$scope.values[$scope.values.lastIndexOf(false)] = true;
} else {//clicking on checked box
$scope.values[n] = true;
$scope.values[$scope.values.indexOf(true)] = false;
}
}
Codepen: http://codepen.io/anon/pen/zGBKxr
This solution is based on allowing the click event to happen, then undoing it before proceeding with the custom logic. It's certainly a simple solution but feels somewhat improper. Is it the most correct way of solving this problem?
Another small update. I dropped in ngTouch to try and make the app feel a bit quicker on mobile. At least in iOS Safari 8, ngTouch broke this solution. Still works fine on desktop, but the overridden ngClick prevents this solution form working. If you switch back to the original proposed logic it fixes iOS, but of course doesn't work on the desktop. I feel like this confirms my suspicion that the solution was not the correct one.
Here it is - the logic was reversed. And I used $apply with a timeout. Modified codepen: http://codepen.io/nagasimhai/pen/VLjjPe
angular
.module("myApp", [])
.controller("myCtrl", function ($scope) {
$scope.values = [true,true,true,true];
$scope.click = function (event,n) {
//event.preventDefault();
//console.log("b", n, $scope.values,$scope.values.indexOf(true), $scope.values.lastIndexOf(false));
if ($scope.values[n] === true) {//clicking on unchecked box
$scope.values[n] = false;
$scope.values[$scope.values.lastIndexOf(false)] = true;
//console.log("11");
} else {//clicking on checked box
$scope.values[n] = true;
$scope.values[$scope.values.indexOf(true)] = false;
//console.log('22');
}
//console.log("a",n, $scope.values);
setTimeout(function () {
$scope.$apply(function () {
});
}, 2000);
}
});
Your answer was a bit confusing but I believe I'm on the correct path. The problem. What you want to use is event.stopPropagation() to stop the event from propagating. In other words, you only want the event to apply to the specific element. If you use event.preventDefault() it cancels the event if cancelable, without stopping further propagation of the event.
angular
.module("myApp", [])
.controller("myCtrl", function ($scope) {
$scope.values = [true,true,true,true];
$scope.click = function (event,n) {
event.stopPropagation();
if ($scope.values[n] === true) {
$scope.values[$scope.values.indexOf(true)] = false;
$scope.values[n] = false;
} else {
$scope.values[$scope.values.lastIndexOf(false)] = true;
}
}
});
Try the code out at the codepen http://codepen.io/anon/pen/bdepPW
I'm currently working on a photography store website. Customers will be allowed to view photosets ranging from 100-500 images on a page. I want those customers to be able to click a "Select All" button (or other element) that checks all the checkboxes on the page. I am currently using jQuery to successfully accomplish this "Select All" feature after researching here on Stack Overflow.
Currently, the code that I am working with puts a checkbox on each image in the photoset. If the user clicks the checkbox, it triggers a custom event. However, I want the checkbox state of being checked (or the change from being unchecked to checked) to trigger the event, not the click. If the click triggers the event, the Select All feature I have using jQuery fails to work, since jQuery isn't "clicking" each of the checkboxes on the page, only changing the checkbox to selected. This means that the custom event doesn't load.
The code that currently works to trigger the event I need by clicking (which I do not want to do) the checkbox is:
$('.select-product').on('click', this.QuickOrder.loadProduct);
The code I am trying to develop isn't working, but it goes something like:
$('.select-product').change(function(){
var isChecked = $(this).is(':checked');
if(isChecked) {
this.QuickOrder.loadProduct;
}
});
I've used the .change() function after researching and finding that the change function registers the change in the condition of the checkbox. When this condition changes to true, I want QuickOrder.loadProduct to trigger. After that, everything should work.
Here is my jQuery "Select All" script for reference:
$(document).ready(function() {
$("#select_all").change(function(){
if(this.checked){
$(".select-product").each(function(){
this.checked=true;
})
}else{
$(".select-product").each(function(){
this.checked=false;
})
}
});
$(".select-product").click(function () {
if (!$(this).is(":checked")){
$("#select_all").prop("checked", false);
}else{
var flag = 0;
$(".select-product").each(function(){
if(!this.checked)
flag=1;
})
if(flag == 0){ $("#select_all").prop("checked", true);}
}
});
});
Any ideas on how to make this happen? Thank you!
As explained in Why isn't my checkbox change event triggered?:
The change event does not fire when you programmatically change the value of a check box.
Below I give two solutions (the first is from the aforementioned link):
1: Explicitly trigger the change event after changing the checkbox setting.
this.checked = true;
$(this).trigger('change');
2: Just programmatically delegate to the click event.
$(this).trigger('click');
Demo:
window.loadProduct = function(id) { alert('loadProduct() called on #'+id+'.'); };
// propagate select-all checkbox changes to all individual checkboxes
$("#select_all").change(function() {
if (this.checked) {
$(".select-product").each(function() {
// original code
//this.checked = true;
// solution #1: explicitly force a change event
this.checked = true;
$(this).trigger('change');
// solution #2: trigger click
//$(this).trigger('click');
});
} else {
$(".select-product").each(function() {
this.checked = false;
});
} // end if
});
// propagate individual checkbox changes back to the select-all checkbox
$(".select-product").click(function() {
if (!$(this).is(":checked")) {
$("#select_all").prop("checked", false );
} else {
var flag = 0;
$(".select-product").each(function() {
if (!this.checked)
flag = 1;
});
if (flag == 0) {
$("#select_all").prop("checked", true );
} // end if
} // end if
});
// call loadProduct() for any change of an individual checkbox
$('.select-product').change(function() {
var isChecked = $(this).is(':checked');
if (isChecked) {
loadProduct(this.id);
} // end if
});
.select_container {
margin-bottom:8px;
}
.img_container {
display:flex;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="select_container">
<input id="select_all" type="checkbox"/>
</div>
<div class="img_container">
<div>
<div><img src="https://www.gravatar.com/avatar/4fa45261dec56004145c653832504920?s=128&d=identicon&r=PG&f=1"/></div>
<input id="check1" class="select-product" type="checkbox"/>
</div>
<div>
<div><img src="https://www.gravatar.com/avatar/fc03f6eed7d4d5e3233c5dde9f48480d?s=128&d=identicon&r=PG&f=1"/></div>
<input id="check2" class="select-product" type="checkbox"/>
</div>
<div>
<div><img src="https://www.gravatar.com/avatar/fd882c2b5e410936a4a607b2e87465d9?s=128&d=identicon&r=PG&f=1"/></div>
<input id="check3" class="select-product" type="checkbox"/>
</div>
</div>
I have a radio input group. If a radio is checked and I click again it becomes unchecked.
Is there a way to get the previous status of the radio onClick event?
<input name="options" type="radio" onClick="resetMeIfChecked()">
<input name="options" type="radio" onClick="resetMeIfChecked()">
<input name="options" type="radio" onClick="resetMeIfChecked()">
jQuery edition
// bind to retrieve old status
$('input[type="radio"]').mousedown(function() {
// if it was checked before
if(this.checked) {
// bind event to reset state after click is completed
$(this).mouseup(function() {
// bind param, because "this" will point somewhere else in setTimeout
var radio = this;
// apparently if you do it immediatelly, it will be overriden, hence wait a tiny bit
setTimeout(function() {
radio.checked = false;
}, 5);
// don't handle mouseup anymore unless bound again
$(this).unbind('mouseup');
});
}
});
But again, this is not how radio buttons are intended to be used. I think you'd be better of with a set checkbox'es where you could uncheck all other checkboxes than the current clicked (hence always max 1 selected)
A working example
I use this. You simply store the pre-click value and ! it into the value.
<input type=radio name="myoptions" value="1"
onmousedown="this.tag = this.checked;" onclick="this.checked = !this.tag;">
This behavior is not the expected one for radio buttons and I don't recommend it at all. Try to find another way of achieving this. Use another widget or another option to reset the field value:
http://jsfiddle.net/marcosfromero/rRTE8/
try this:
function resetMeIfChecked(radio){
if(radio.checked && radio.value == window.lastrv){
$(radio).removeAttr('checked');
window.lastrv = 0;
}
else
window.lastrv = radio.value;
}
<input value="1" name="options" checked="checked" type="radio" onClick="resetMeIfChecked(this)" />A
<input value="2" name="options" type="radio" onClick="resetMeIfChecked(this)" />B
<input value="3" name="options" type="radio" onClick="resetMeIfChecked(this)" />C
Its quite simple. Just follow the simple example and
var rdblength=document.formname.elementname.length;
alert('length='+rdblength);
for(i=0;i<rdblength;i++){
document.formname.elementname[i].checked=false;
}
Just find the length and make every index checked=true/false.
Ping me at:-
http://manojbardhan2009.blogspot.com
I had the same problem and figured it out. None of the answers above work exactly as I wanted - most of them require an additional button to reset the radio. The goal was to uncheck radio by clicking on the radio itself.
Here's the fiddle: http://jsfiddle.net/MEk5Q/1/
The problem was very complicated because the radio button value changes BEFORE the click event fires so when we're listening to the event we can't tell if the radio button was already checked or not. In both cases it is already checked.
Another approach was to listen to mousedown event. Unlike click, it fires before changing radio checked attribute but unchecking it inside event handler gives us nothing since it is checked back again during mouseup event.
My answer is a little ugly workaround so I generally don't suggest it to others and I'll probably abandon it myself. It works but it involves 20ms timeout function which I'm not fond of in cases like this.
Here is the code explanation:
$('input[type="radio"]').on('mousedown', function() {
if (this.checked) { //on mousedown we can easily determine if the radio is already checked
this.dataset.check = '1'; //if so, we set a custom attribute (in DOM it would be data-check="1")
}
}).on('mouseup', function() {
if (this.dataset.check) { //then on mouseup we determine if the radio was just meant to be unchecked
var radio = this;
setTimeout(function() {radio.checked = false;}, 20); //we give it a 20ms delay because radio checking fires right after mouseup event
delete this.dataset.check; //get rid of our custom attribute
}
});
As a timeout function I could use a string (less writing) but as far as I know it would be eval'ed. Though I don't trust eval function, I prefered anonymous function.
One more thing - one could ask why spreading the code into two separate event handlers while we can fire the timeout function on mousedown? Well, what if someone press the mouse on a radio and holds it for a few secs or even someone is simply a very slow person ;). Generally, with this solution we omit the problem of lag between mousedown and mouseup.
If you need some more info about dataset, here's the MDN reference:
https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement.dataset
This property came with HTML5 and might be not cross-browser, I guess, so if you want 100% compatibility, replace it with any other solution that'll contain the data, you name it.
Sorry about jQuery here and there but I hope you're fine with it - it was much easier that way.
Hope you'll enjoy it.
$('input[type="radio"]').on("mousedown", function () {
if (this.checked) {
$(this).one("click", function () {
this.checked = false;
});
}
});
I was never too happy about being forced to aim at that tiny radio button, so I came up with a larger target AND a way to turn a radio group off without resorting to anything that would upset the HTML / JavaScript purists.
The technique relies on not molesting the radio buttons at all via event handlers, but checking for a readonly proxy for each one instead. Everything is contained in what's below in pure JavaScript using a radio group to select a type of cheese, or no cheese at all.
I purposely used no styling in this example to avoid that added layer. The dump button will tell you what the three checked states are, so use it to interrogate what happened after hitting the radio or text input elements. For example simplicity I used a global to remember the former state, but a more elegant method is to use a dataset, which I what I use in the real code of my application.
<!DOCTYPE html>
<html>
<head>
<title>Uncheck a radio button</title>
<script>
function attachEventListener(target, eventType, functionRef, capture) {
"use strict";
if (typeof target.addEventListener !== 'undefined') {
// Most modern browsers
target.addEventListener(eventType, functionRef, capture);
} else if (typeof target.attachEvent !== 'undefined') {
// IE
target.attachEvent('on' + eventType, functionRef);
} else {
eventType = 'on' + eventType;
if (typeof target[eventType] === 'function') {
var oldListener = target[eventType];
target[eventType] = function() {
oldListener();
return functionRef();
};
} else {
target[eventType] = functionRef;
}
}
}
</script>
</head>
<body>
<form>
<input id="Cheddar-radio" class="radio" type="radio" name="Cheeses-0" value="Cheddar Cheese" tabindex="-1"></input>
<input id="Cheddar-text" type="text" readonly value="Cheddar Cheese" tabindex="-1"></input><br>
<input id="Swiss-radio" class="radio" type="radio" name="Cheeses-0" value="Swiss Cheese" tabindex="-1"></input>
<input id="Swiss-text" type="text" readonly value="Swiss Cheese" tabindex="-1"></input><br>
<input id="American-radio" class="radio" type="radio" name="Cheeses-0" value="American Cheese" tabindex="-1"></input>
<input id="American-text" type="text" readonly value="American Cheese" tabindex="-1"></input><br><br>
<input onclick="dumpStates()" type="button" name="button" value="dump" tabindex="-1"></input>
</form>
<script>
window.onload = addRadioListeners;
function addRadioListeners() { // But do it on the -text elements.
attachEventListener(document.getElementById('Cheddar-text') , 'mousedown', rememberCurrentState, false);
attachEventListener(document.getElementById('Swiss-text') , 'mousedown', rememberCurrentState, false);
attachEventListener(document.getElementById('American-text'), 'mousedown', rememberCurrentState, false);
attachEventListener(document.getElementById('Cheddar-text') , 'mouseup', checkNewState, false);
attachEventListener(document.getElementById('Swiss-text') , 'mouseup', checkNewState, false);
attachEventListener(document.getElementById('American-text'), 'mouseup', checkNewState, false);
}
function dumpStates() {
console.log(document.getElementById('Cheddar-radio').checked +
' ' + document.getElementById('Swiss-radio').checked +
' ' + document.getElementById('American-radio').checked);
}
var elementWasChecked; // Global - Could just as well use a dataset attribute
// on either the -radio or -text element and check it instead.
function rememberCurrentState(event) {
var element;
var radioElement;
element = event.target;
radioElement = document.getElementById(element.id.replace(/text/,'radio'));
elementWasChecked = radioElement.checked;
radioElement.checked = true;
}
function checkNewState(event) {
var element;
var radioElement;
element = event.target;
radioElement = document.getElementById(element.id.replace(/text/,'radio'));
var currentState = radioElement.checked;
if (elementWasChecked === true && currentState === true) {
console.log('Changing ' + radioElement.id + ' to false.');
radioElement.checked = false;
}
};
</script>
</body>
</html>
If you click on the radio buttons they work as expected. If you click on the text items next to each, they are a proxy for the radio buttons with one exception. If you click on a text item that has an associated radio button that's already checked, it will uncheck it. Therefore, the text proxy's are event triggered, and not the radio buttons.
The added benefit is that you can now hit the larger text target too.
If you want to make it simple and wouldn't mind using a double-click event try something like this:
<input name="options" type="radio" ondblclick="this.checked=false;">
#jerjer's answer is almost perfect, but radios can be switched also by arrows if the radio group has the focus (so mousedown event is not enough). Alas, the radio group also gets checked when activated by focus shift (Tab), which can undesirably check one option. Therefore space should uncheck the focused radio, just like the checkbox behavior.
This code fixes that for all radios (Most credit still goes to jerjer):
window.addEventListener("DOMContentLoaded", function() {
var radios = document.querySelectorAll("input[type=radio]");
for(var i=0; i<radios.length; ++i) {
radios[i].addEventListener("click", function(e) {
if(e.target.checked && e.target.value == window.lastrv){
e.target.checked = false;
window.lastrv = 0;
}
else
window.lastrv = e.target.value;
});
radios[i].addEventListener("keypress", function(e) {
if(e.keyCode==32) e.target.click();
});
}
});