Have input checkbox toggle checked/unchecked in AngularJS 1.x - javascript

I am still new to AngularJS, I am trying to have a simple function that will toggle a checkbox on/off when clicked. So a clicked li element in the code below will either set that checkbox to on or off.
Can anyone suggest the best way to do this using AngularJS, I know jQuery would be simple but i'm trying to do this in the Angular way.
my html template
<ul>
<li ng-repeat="page in rule.pages" ng-click="toggleNetwork(page.id); ruleForm.$setDirty()">
<span class="pull-left"><i class="check material-icons nomargin">{{rule.pages.indexOf(page.id) >= 0 ? 'check_box' : 'check_box_outline_blank'}}</i></span>
</li>
</ul>
my Controller scope logic code
$scope.toggleNetwork = function(networkId) {
// function called when checkbox clicked
}

IF you just want the checkbox to toggle on/off, you don't really need to do anything. Angular will do it for you out of the box.
you only need a boolean variable in your controller, like this:
//myController.js
$scope.myCheckboxValue = false;
And your html should be something like this:
//myTemplate.html
<input type="checkbox" ng-model="myCheckboxValue">
Whenever you click the checkbox, the changes will already be reflected on myCheckboxValue.

I don't see checkbox in your html so I'm assuming that you want to li tag working as checkbox.
You can do it that way, if page can have additional property:
$scope.toggleNetwork = function(network) {
network.toggle = !network.toggle;
}
If you don't want to add property to network model you can store toggled networks in array;
$scope.toggledNetworks = [];
$scope.toggleNetwork = function(networkId) {
var index = $scope.toggledNetworks.indexOf(networkId);
if (index === -1)
$scope.toggledNetworks.splice(index, 1);
else
$scope.toggledNetworks.push(networkId)
}
Then if you want to check if network is toggled you can use function:
$scope.isToggled = function(networkId) {
return $scope.toggledNetworks.indexOf(networkId) !== -1;
}
Note:
rule.pages.indexOf(page.id)
Will always return -1. Pages contains objects, you want index of property of one object which is not in this array

Related

Dynamically how to make checkbox check/uncheck in angularjs controller using ng-click

I am new to Angular JS. When the user check/uncheck on a check box, I am calling a function in a controller using ng-click. I am passing $event to the function in controller. Using the $event, I am able to get the srcElement inside the controller function. Now I would like to set the previous check/uncheck value to the check box based on certain conditions.
$scope.isAccessChanged = function(event){
if (some condition) {
var elem = angular.element(event.srcElement);
/** here how to set the elem value back to whatever it was before.*/
}
};
Lets say you have check box like
<input ng-model="form.isSelected" type="checkbox">
All you need to do is:
$scope.form.isSelected = !$scope.form.isSelected;
Avoid DOM manipulation and limit jQuery use as much as possible in angular.
I recommend using jQuery only in directives to make it less of an available option.
Try this out:
<input type="checkbox" ng-model="foShizzle" ng-click="isAccessChanged()"/>
$scope.isAccessChanged = function(event){
if(some condition){
$scope.foShizzle = !$scope.foShizzle; // This will reverse the user's decision
}
}

Angular js binding list of data dynamically based on checkboxes

I have an angular app in this plunkr
Here the button opens a modal which has a table. When an item in the table is checked or unchecked, it changes the values in the progress bar accordingly.
Below the table, it has a list of all the checked courses shown. How do i bind this data accordingly such that when a checkbox is checked, it also shows the item in this list dynamically? Here is the code i used for displaying this list of items:
<div ng-repeat="child in selectedCourses">
{{child.course.subject}}-{{child.course.course_no}}
</div>
The problem is that you push the same items many times into $scope.selectedCourses, which results into an error (because of duplicate values in ngRepeated items) which in turn causes the view to not be updated.
To prevent adding the same item many time, you should check if it is already present in the array:
$scop.checkplanneddetails = function (course) {
...
for (var k = 0; k < $scope.planneddetails.length; k++) {
if ($scope.requirementcoursename==$scope.planneddetails[k].course_name) {
if (!$scope.checkcoursefunction($scope.selectedCourses, course)) {
// ONLY add the course if it is NOT already present
$scope.selectedCourses.push(course);
}
course.checked = true;
return true;
}
}
return false;
};
There is also a problem with using ng-checked="checkplanneddetails(child), because checkplanneddetails is not idempotent. You should not use it with ngChecked, because it is run every time a $digest cycle takes place.
You should ngInit instead and also make sure you add course.checked = true at the proper place inside checkplanneddetails (see above):
<!-- Change that: -->
<input type="checkbox" ng-checked="checkplanneddetails(child)" ... />
<!-- To this: -->
<input type="checkbox" ng-init="checkplanneddetails(child)" ... />
See, also, this short demo.

How to select Parent Checkbox when a Child is selected inside ng-repeat

I am having a very hard time trying to figure out a solution for this. I have a checkbox group where the first checkbox is the parent and the following in that set will be child. I want the parent checkbox to be selected automatically if one of the child's checkbox is selected. Similarly parent needs to be get unchecked if no child is selected.
Here is my jsfiddle example: http://jsfiddle.net/Alien_time/PqTR7/3/
The main difficulty I am facing is because the checkboxes are created dynamically and it has dynamic ng-models for each. I have tried the following so far:
1) ng-checked: This doesnt work for me since ng-checked doesnt bind the value with ng-model. I need the ng-model of the parent to be updated as well since this is going to reflect in the main form.
2) JS solution: I thought js method will be the solution, but dont know how to add the js to controller as the ng-model is dynamically generated.
3) On other posts, there are some method that uses select all when parent is checked. But I couldnt find a solution for my approach since its the other way around where I only want the parent selected if one of the child is selected.
For my form, I need to have a different ng-model for each checkbox thats why I am using the name to create a dynamic ng-model name. But I just couldnt figure out how to select the parent checkbox if a child is selected in this dynamic list.
I have been stuck on this for 2 days and searched a lot on the net. Can you help me please?
HERE is the working solution based on your fiddle.
JS
$scope.select = function(index){
if(index === 0){
$scope.slaves.forEach(function(slave, ind){
$scope.slaves[ind].isChecked = $scope.slaves[0].isChecked;
});
}
else {
var anyChild = false;
for(var i = 1; i < $scope.slaves.length; i++){
anyChild = anyChild || $scope.slaves[i].isChecked;
}
$scope.slaves[0].isChecked = anyChild;
}
}
HTML
<div ng-repeat="slave in slaves">
<input type="checkbox" ng-model="slave.isChecked" ng-click="select($index)" />
{{slave.name}} - {{ slave.description }}
</div>
To tell the truth I do not find the solution elegant -- you would be better off by encapsulating the logic of it in a custom directive.
Moreover it would be probably better to express parent-child relation by:
var parent = {
... // parent data
childeren : [child_1, ... , child_N] // array of children
}
A solution to this problem is to add a watch.
Add the following in your controller
$scope.$watch('checkboxData', function (newValue, oldValue) {
var anyChecked = false;
// see if any are checked
$scope.slaves.reduce(function (pVal, cVal, idx, arr) {
if (newValue[cVal.name]) anyChecked = anyChecked || newValue[cVal.name];
});
// replace the parent 'checked' in the model
$scope.checkboxData['Parent'] = anyChecked;
}, true);
And add the following to your input elements.
ng-checked='checkboxData[slave.name]'

Angular - Toggling element class inside an ng-repeat based on radio input selection

I'm using Angular to write a questionnaire where the questions are retrieved from a resource. Based on the design, I have to toggle a custom icon instead of the standard radio button icon. The solution I've come up with is to hide the radio input (using opacity/filter) and absolutely position a div over the input with the same dimensions as the radio input. Clicking the radio input will toggle a background image which is the custom icon. Unfortunately, this has to work in IE8 so conventional CSS :checked tactics are out.
The question blocks will look something like this:
<h2>{{ quiz.questions[asked].questionText }}</h2>
<ul>
<li ng-repeat="answer in quiz.questions[asked].answers">
<label>
<input type="radio" ng-model="$parent.picked" name="answer" value="{{ answer.answerID }}"/>
<div class="radio-mimic {{ checked }}"></div>
{{ answer.answerText }}.
</label>
</li>
</ul>
<a class="btn" ng-click="submitAnswer()" ng-show="picked != null">
Submit
</a>
Here is a stripped down version of my controller for reference:
app.controller('QuizController', function($scope, Quiz) {
$scope.quiz = Quiz.get({quizID = X}); // Angular $resource
$scope.picked = null;
$scope.asked = 0;
$scope.answers = [];
$scope.submitAnswer = function() {
$scope.asked++;
$scope.picked = null;
// Push answer selected onto answers array
// Check if # asked == number of questions in quiz to determine flow
// If another question, $scope.quiz = Quiz.get({quizID = newQuizID});
// Else show results
};
});
For each answer I receive to a question, I'm outputting the radio input and the div icon wrapped in a label with the answer text. Clicking on an answer will change the value of 'picked' in the parent scope of the repeat, thus only displaying the submit button when a user has picked an answer.
The problem I'm having is how to handle the logic of {{ checked }} for the div class to show when an input is selected. When I click on an input, the div within its scope needs to get a class called 'checked'. Additionally, if I click on a different answer outside that scope, the other scopes in the ng-repeat need to know in order to reset their 'checked' values to null or ''. I know some value will have to go into the parent scope like 'picked' but the overlap of the parent and ng-repeat scopes is causing me some confusion. I can do this easily enough with jQuery but wanted to keep this purely Angular as part of my learning.
I found a solution to my issue by using ng-class and an expression to compare the parent scope's 'picked' with the answerID of the inner scope:
<div class="radio-mimic" ng-class="{checked: $parent.picked == answer.answerID}"></div>

Jquery click event with binded event

Hi guys I am having a problem with Events. I have a checkbox list and I have a main check box that checks all boxes. When I clickEvent some of my checkbox list items it should add data-id attr to the "selected obj". So in my case when I press main check box to check all others every thing is ok (it simply clicks all other elements). but when i do that it empties my array. I mean if i uncheck it will be the way it supposed to be but checked (when uncheck it fills when i check it empties).
......
var selected = {};
var reload = function(){
selected = {};
$('.checkbox_all').unbind('click');
$('.table_checkbox').unbind('click');
$('.checkbox_all').bind('click', checkAll);
$('.table_checkbox').bind('click', checkMe);
}
var checkMe = function(e){
var checkbox = $(e.target);
var id = checkbox.attr('data-id');
//console.log(id);
if(checkbox.attr('checked')){
selected[id] = id;
}else{
if(selected[id]) delete selected[id];
}
console.log(selected);
}
var checkAll = function(e){
if($(e.target).attr('checked')){
$('.table_checkbox').each(function(){
if($(this).attr('checked') === false){
$(this).click();
}
});
}else{
$('.table_checkbox').each(function(){
if($(this).attr('checked') === true){
$(this).click();
}
});
}
//console.log(selected);
}
.......
HTML:
<tr><th class="table-header-check"><input type="checkbox" class="checkbox_all"/></th></tr>
<tr class=""><td><input type="checkbox" data-id="5" class="table_checkbox"></td></tr>
<tr class="alternate-row"><td><input type="checkbox" data-id="6" class="table_checkbox"</td></tr>
<tr class="alternate-row"><td><input type="checkbox" data-id="8"
....ETC\
My problem is that when i click .checkbox_all it should click on all .table_checkbox(that r cheched or uncheched)... it just clicks all checkboxes like a main checkbox... it works fine, but i have an event all other checkboxes if i click em i add some data to array when i unclick em it removes data from array.... so when im clicking checkboxes sepperatly they add /remove data to array properly... but when im clicking on main checkbox... it clicks on right checkboxes but the data array is empty when all checked and full when all unchecked... it must be the opposite way
Could you instead go for a cleaner solution, and generate selected on the fly? See here for an example (and a JSFiddle for everyone else): http://jsfiddle.net/turiyag/3AZ9C/
function selected() {
var ret = {};
$.each($(".table_checkbox"),function(index,checkbox) {
if($(checkbox).prop("checked")) {
ret[$(checkbox).prop("id")] = true;
}
});
return ret;
}
** EDIT: **
If you're looking to have an array that is added to and removed from, then this JSFiddle (http://jsfiddle.net/turiyag/pubGb/) will do the trick. Note that I use prop() instead of attr(), in most cases, especially this one, you should use prop() to get the value you want.
To work with your own code you need to understand the order of events. When you programmatically call click() on the checkbox the javascript (checkMe() for children) executes before the state of each child checkbox is changed (e.g., adding attribute 'checked'). It is because of this reason that the checkMe() function was adding and removing ids in the selected array in the reverse order. You can confirm this by adding the following debug line in the checkMe function:
console.log('Checked state of checkbox id:' + id + ' is: ' + checkbox.prop('checked'));
Case1: Clicking checkAll when it is Unchecked; it calls checkMe() for each child checkbox but finds the 'checked' attribute as undefined. So it executes the delete code. After executing checkMe the 'checked' attribute is added on the checkbox.
Case2: Clicking checkAll when it is Checked; the checkMe() function finds the 'checked' attribute previously added and fills the array. Later an event is probably fired to remove the 'checked' attribute.
I changed the following lines to quickly test this and seems to be working:
Bind checkMe on change event instead of click in reload function:
$('.table_checkbox').bind('change', checkMe);
Change the condition for unchecked children in checkAll function when the .checkbox_all is checked:
if($(this).prop('checked') === false) {/*call child click*/}
//Use prop instead of attr because it takes care of 'undefined' cases as well. If you want to keep using attr because you're on an older version of jquery then add something like:
typeof $(this).attr('checked') == 'undefined'
and also the condition when .checkbox_all is unchecked:
if($(this).prop('checked') === true) {/*call child click*/}
Hope this helps. Here's a jsbin to play with..

Categories