Setting ng-checked doesn't allow unchecking? - angularjs

I set the ng-checked directive in the Create page (used in edit too) based on data from the database. but the problem is that I can't uncheck it, so I can't edit the data:
<md-input-container class="md-block" flex-gt-sm="25" flex="45" content-layout-align="center start" ng-repeat="tab in allTabs">
<md-checkbox class="chbox" aria-label="tab.name" checklist-model="entity.tabs" checklist-value="tab" ng-checked="setCheck(tab.id)">
{{tab.name}}
</md-checkbox>
</md-input-container>
controller:
$scope.setCheck = function (id) {
var alltabs = $scope.allTabs;
for (var i = 0; i < alltabs.length; i++) {
if (alltabs[i].id == id)
return true
return false
}
}
is there a way to allow this in angular?

First of all, your for-loop is wrong. Put your return false statement outside the for-loop:
for (var i = 0; i < alltabs.length; i++) {
if (alltabs[i].id == id)
return true;
}
return false;
Secondly, if you want to be able to check/uncheck the checkboxes, you should not use ng-checked. This directive reads every digest if the checkbox should be checked and behaves accordingly (see the note in the documentation).
If you're using ng-model (or in this case checklist-model) you can just remove the ng-checked, because the checklist-model will just check the array for the already checked tabs.

Related

Angularjs how to user ng-default with ng-repeat

I am having below data as input json,
"values":[
{"_attributes":{"name":"data.domain"},"_text":"${url}"},
{"_attributes":{"name":"data.port"}},
{"_attributes":{"name":"data.comments"},"_text":"Defaults Comments"},
{"_attributes":{"name":"data.concurrent"},"_text":4}]
]
I am showing comments in my html page using this directive,
<b style="padding-top:5px;"> Comments:</b>
<span class="input">
<input class="inputtxt" type="text" ng-repeat="x in ValueArr" ng-if="x._attributes.name == 'data.comments'" ng-model="x._text">
</span>
which is working fine and showing as expected. But the problem is that sometimes, the comments node
{"_attributes":{"name":"data.comments"},"_text":"Defaults Comments"},
may not be present in array. like this,
"values":[
{"_attributes":{"name":"data.domain"},"_text":"${url}"},
{"_attributes":{"name":"data.port"}},
{"_attributes":{"name":"data.concurrent"},"_text":4}]
]
In that case it shows only "Comments:" and blank screen after that. It does not show input box. In this case, I want to show empty input box. I tried ng-default and and ng-init but that didn't work. How to display input box for absence of matching condition ?
jsfiddle
Not getting any idea, how to achieve that. Please suggest something.
Thanks
The solution works with ng-init.
Just put it on the input like this:
<span class="input" ng-init="initValues()">
<input class="inputtxt" type="text" ng-repeat="x in values" ng-show="x._attributes.name == 'data.comments'" ng-model="x._text" ng-init="initInput(x)">
</span>
And add the function in the Controller:
$scope.initInputComments = function(x) {
if (!x._text || x._text == "") {
x._text = "Defaults Comments"
}
}
Note that you need to test that x._text exists/is defined.
$scope.initValues = function() {
var containsComment = false;
for (var i = 0; i < $scope.values.length; ++i) {
if ($scope.values[i]._attributes.name == 'data.comments') {
containsComment = true;
}
}
if (!containsComment) {
$scope.values.push({
"_attributes": {
"name": "data.comments"
}
});
}
}
Check the working fiddle

TR element triggers checkbox via ng-click, but ng-change on checkbox will not fire

I have successfully created functionality to check a hidden checkbox on the ng-click of the row that the checkbox exists in that is generated with an ng-repeat. However, I also have functionality that adds that item to a separate array when the checkbox is checked using the ng-change directive.
My code works perfectly if I un-hide the element and check the checkbox directly, but if I use the ng-click directive on the TR, the checkbox gets checked (visibly) but the array isn't updated. If I then click on it again, it remains checked and the item is added to the new array.
This isn't an issue where the ng-click is taking two clicks to fire. Here is my markup:
<tr ng-cloak ng-repeat="item in mostRecent | orderBy:sortType:sortReverse | filter: query" class="hovered" ng-class="{'hide':showReports && item.status == 'Not Started' || showReports && item.status == 'inProgress','rep-checked': bool}" ng-click="bool = !bool">
<td class="hidden"><div class="checkbox">
<label class="checkbox">
<input type="checkbox" ng-change="sync(bool, item)" ng-model="bool" ng-checked="isChecked(item)">
</label>
</div></td>
and the js:
$scope.isChecked = function(id) {
var match = false;
for(var i=0 ; i < $scope.selectionData.length; i++) {
if($scope.selectionData[i].id == id){
match = true;
}
}
return match;
};
// Create a new array from the selected data
$scope.selectionData = [];
var selectionData = $scope.selectionData;
var result = selectionData.filter(function(e){ return e.id == id; });
$scope.sync = function(bool, item){
if ($scope.selectionData) {
$scope.selectionData.push(item);
}
else {
$scope.selectionData.splice(item);
}
console.log('check' + $scope.selectionData);
};
After some deeper research, I found that the ng-click function on the input isn't registering because the ng-click function of the tr element isn't actually emulating a click event on the input. I added a dynamic ID and replaced the ng-click function with a javascript function of
getElementById('checkboxID').click();
And it worked as expected.

Include the check boxes before selected angular js

Is it possible to include all check boxes in the list if one is selected. For example, 10 checkboxes on the page and we check the 5th - so 1,2,3,4,5 should be checked.
Does anybody have an example of this with angular JS?
As pointed out by Blackhole, a possible solution would be using ng-change on your checkboxes.
your html:
<input type="checkbox" ng-repeat="bx in boxes" ng-model="bx.value" ng-change="boxChecked($index, bx.value)">
in controller:
$scope.boxChecked = function(index, value) {
for (var i = 0; i < index; i++) {
$scope.boxes[i].value = value;
}
}

How to update ng-class based on ng-change?

I have an ng-repeat that creates several widgets, each with it's own select dropdown.
<div ng-repeat="item in widget.items" class="col-md-6">
<select ng-model="item.chosenTag"
ng-change="widget.updateTag(item)"
ng-class="widget.getButtonClass(item.tag, item.id)">
<option value="companies"
ng-selected="{{item.tag == 'companies'}}"
changed="companies">companies</option>
<option value="news"
ng-selected="{{item.tag == 'news'}}"
changed="news">news</option>
<option value="people"
ng-selected="{{item.tag == 'people'}}"
changed="people">people</option>
</select>
</div>
As the view is loaded, the ng-class="widget.getButtonClass(item.tag, item.id)" calls a function to check if 2 values are met, then sets ng-class to either btn-success or btn-default.
// This checks the view after load to change the class on each widget select
var vm = this;
vm.getButtonClass = function(tag, id) {
console.log('in getButtonClass');
if (tag && id) {
return 'btn-success';
} else {
return 'btn-default';
}
};
Next if the user now updates a select within any widget, ng-change will update to the correct value.
However I need to somehow re-run the ng-class check or rather just go ahead and add btn-success to the select without having to refresh the page.
How would you go about accomplishing this?
Is there a way to do something like this?
ng-class="{ functionToUpdateAll | boolean based on ng-change }"
Is there any specific reason that you need to call the function? Why dont you bind directly to those variables?
ng-class="'btn-success':item.tag && item.id, 'btn-default': !(item.tag && item.id)"
In that way you take advantage of mutual binding i.e. whenever the item.tag or item.id are changed, the class will be evaluated accordingly.
I suggest that instead of calling the function in ng-class, just assign it to a variable:
<select ng-model="item.chosenTag"
ng-change="widget.updateTag(item)"
ng-class="mySelectClass">
And in your updateTag function in the controller update that variable:
vm.updateTag = function(item) {
if (item.tag && item.id) {
vm.mySelectClass = 'btn-success';
} else {
vm.mySelectClass = 'btn-default';
}
};

angular $index numbering with condition in ng-repeat & ui-sortable

I'm trying to achieve customized numbering while listing all items in an array.
All items in array are rendered using ng-repeat & ui.sortable.
Numbering must be done in such a way that, for an array item "statement", count should not be increased & displayed.
(Else I may be used $index instead of an external count.)
For any other array item, count should be increased & displayed.
The solution that got me the the closest result was the one where I passed $index into a filter function written in the controller.
like in HTML:
<li ng-repeat="question in questions">
<div class="no"> {{ filterIndex(question.question, $index) }} </div>
<div>{{question.question}}</div>
</li>
in controller:
var filterValue = 0;
$scope.filterIndex = function (value, count) {
if (count === 0) {
filterValue = 0;
}
if (value !== 'statementText') {
filterValue = filterValue + 1;
return filterValue;
}
else {
return '"';
}
};
Even it was working without any errors, the count returned from function is not get updated like we get with $index when we update the order using ui-sortable.
see it here: js-fiddle using filter function
means, once it rendered (4) in <[ (4) fourth question ]> will remain same even if we moved it to top or bottom by dragging.
I tried different ways and almost everything ended up on 'Maximum iteration limit exceeded.'.
Real scenario is a little bit complex as it contains nested ng-repeats and similar counting with digits and numbers alternatively in child loops.
Here is link to start fresh:
js-fiddle
You can inject this to your controller, it will listen for array changes, and update the indexes:
var update = function(){
var currentCount = 0;
var questions = $scope.questions;
for(var j = 0; j < questions.length; j++){
if(questions[j].question != null){
if(questions[j].question.indexOf("statement") < 0){
questions[j].calculatedIndex = ++currentCount;
}
}
}
};
$scope.$watchCollection('questions', function(){
update();
});
update();
probably needs a bit fine-tuning as I didn't concentrate on your question completely. In the ng-repeat, you now have access to calculatedIndex. It will be "NULL" for statement items, you can use ng-show for that.
just try to add extra option:
ng-init='question.index = $index+1'
http://jsfiddle.net/ny279bry/

Resources