ng-checked not updating first time - angularjs

I'm generating check boxes using ng-repeat, and their initial status can be checked or unchecked depending on if that information exists or not in the data. My problem is that altghough it shows their initial checked/unchecked status correctly, when I uncheck a box that has been 'pre-checked', the box physically unchecks but the model doesn't change. Then I check it again, and the model doesn't change but it's correct. Then I uncheck again, and it clears correctly in the model and works correctly from then on. I have been working on this problem for days and I'm totally stuck! Can anyone see if I'm doing something stupid? My feeling is that it's an initialisation problem but I'm too close to it to see now. Thanks!
<!-- if this is a checkbox to be drawn -->
<div ng-if="option.option_type=='checkbox'">
<label class="item-checkbox-right">
{{option.caption}}
<!-- handle multiple options -->
<!-- if answered_options[n]weight exists, make option.ans = weight --></label>
<ul ng-repeat="opti in questionpart.survey_answer[0].answered_options">
<li style="list-style: none; display: inline">
<!-- if option is set in the received data, set it in the model -->
<div ng-if="opti.id == option.id">
<div ng-init="option.ans = option.weight"></div>
</div>
</li>
</ul>
<label class="item-checkbox-right">
<!-- show the checkbox and bind to option.ans-->
<input class="checkbox-light"
type="checkbox"
name="{{questionpart.id}}"
ng-false-value="0"
ng-true-value="{{option.weight}}"
ng-model="option.ans"
ng-checked="option.ans==option.weight" />
</label>
</div>

Here is a simple, but not pretty example. Using the default Angular directives for checkboxes never quite worked for me.
app.js
$scope.data = [{checkboxValue: 0}, {checkboxValue: 1}, {checkboxValue: 2}];
$scope.dataCopy = angular.copy( $scope.data );
$scope.setCheckboxValue = function( checkbox, index ) {
checkbox.checkboxValue = checkbox.checkbox ? $scope.dataCopy[index].checkboxValue : 0;
}
$scope.parseCheckboxes = function() {
for( var i = 0, len = $scope.data.length ; i < len ; i++ ) {
$scope.data[i].checkbox = $scope.data[i].checkboxValue > 0 ? true : false;
}
}
$scope.parseCheckboxes();
Basically what I do at the controller is handling the logic for checkboxes all by myself. I create a copy of the array so that when we toggle from false to true, we get the initial value.
I make an additional key in every object which keeps track of the status of the checkbox (true or false) so it doesn't interfere with the actual value.
The initial marking is done by parsing the array of objects and setting all the checkboxes to true or false depending on their values.
html
<body ng-controller="MainCtrl">
<label ng-repeat="d in data track by $index">
<input type="checkbox" ng-model="d.checkbox" ng-change="setCheckboxValue(d, $index )" />
{{d.checkbox}}
{{d.checkboxValue}}
<br>
</label>
</body>
The html part is pretty self explanatory.
There probably is better ways to solve this, but this is the solution I came up with. Not pretty, but it works.

Related

AngularJS - How to correctly use ng-show inside a ng-repeat? My boolean isn't getting updated

I have a ng-repeat that loops over 9 divs, each one has a different color.
When the user clicks on one div, its color it's gonna be the background color of a section.
I'm trying to do this:
The array that gets repeated is structured like this:
interface colorBoxes {
color: string;
isSelected: boolean;
}
in the view:
<div ng-repeat="s in vm.colorBoxes track by $index">
<div class="pointer" ng-click="w.backgroundColor = s.color; vm.pickColor(s, $index)" ng-style='{"background-color": s.color}'>
<i ng-show="vm.isColorSelected($index) === true" class="fa fa-check fa-1x checkOnSelectedLegend"></i>
</div>
</div>
in the controller:
pickColor(array: any, index: number) {
for(var i = 0; i<=this.colorBoxes.length; i++) {
this.colorBoxes[i].isSelected = false;
}
array[index].isSelected = true;
}
I use this function so when you click on a DIV, its variable: isSelected gets true, and all the other DIV's have theirs set to false.
I use this variable in the view with a ng-show, to show a check mark on the DIV that is currently selected, but this isn't working, below the function I put in that ng-show
isColorSelected(index:number):boolean {
return this.colorBoxes[index].isSelected
}
What am I doing wrong?
To summarize, I want that when you click on a box, its color string gets applied to another element (that is working correctly with my code), then, that box need to have a check mark appear on top of it, I tried with the above functions, by setting the isSelected var to true when clicked, but it doesnt work.
I'm pretty sure the problem is that angular isn't checking for changes in that ng-show, I just don't know exactly how to make it check for changes, and maybe there is a cleaner way to obtain what I'm trying to do!
Thank you
addded fiddle: http://jsfiddle.net/7zymp2gq/1/
Ok, here you have your code fixed and working:
http://jsfiddle.net/7zymp2gq/4/
Basically there were 2 things wrong with the function $scope.pickColor:
The loop was entering into not existing fields, I have changed the <= with a <
It was updating array[index], and it should be updating $scope.colorBoxes[index]
Instead of using function at ng-show you can use the isSelected property:
<div ng-app="app" ng-controller="Ctrl">
<div class="class1" ng-repeat="s in colorBoxes track by $index">
<div class="pointer class2" ng-click="pickColor(colorBoxes,$index);" ng-init="lastselected=s.isSelected?$index:null" ng-style='{"background-color": s.color}'>
<i ng-if="s.isSelected" class="fa fa-check fa-1x checkOnSelectedLegend"></i>
</div>
</div>
<div class="changeColor" ng-style='{"background-color": chosenColor}'></div>
</div>
Check this demo.

Change the style of the selected ng-repeat item and remove the other item's style

I'm a freshman to AngularJS. I try to modify the item's style using AngularJS, but I meet this bug:
when I select another item, the background of the first item is still blue. How to change my code to fix this?
Here is my plnkr.
And here is the code.
<div ng-init="selectedNode = false">
<div ng-repeat="item in items" ng-click="selectedNode=true" ng-class="{selected: selectedNode == true}">{{item.value}}</div>
</div>
When I click on 2 after click on 1, the background color of 1 should be removed. It means only one item should be selected. How to slove this problem?
The problem is subtle -- ng-repeat creates a new isolated scope for each of its entries. So when your click handler sets selectNode to true, it happens on its own scope, and not its parent.
Easily remedied. (I surrounded your example with some mock data -- I'm sure you have your own):
<div ng-app ng-init="items = [{value: 'red'},
{value: 'green'},{value: 'blue'},{value: 'yellow'},
{value: 'orange'}]">
<div ng-init="selection = { selectedNode: null }">
<div ng-repeat="item in items"
ng-click="selection.selectedNode = item"
ng-class="{selected: selection.selectedNode == item}">
{{item.value}}
</div>
</div>
</div>
https://jsfiddle.net/kfnkn827/
First, I create an object in the parent scope that can be modified by the children. Notice that instead of a boolean, I just use a reference in the parent. This relieves you from storing a bunch of flags.
Edit: I saw your Plinkr after submitting. Sorry! :-P
A couple things. Don't use ng-init to init the variable, do it in a controller. Second, ng-repeat creates a child scope, so you should make a data model for this, so data.selectedNode. Then just set the selectedNode to the currently repeated item, and then style it if the selectedNode equals the current item.
<div ng-init="data.selectedNode ={}"> <!-- do this in a controller, not ng-init -->
<div ng-repeat="item in items" ng-click="data.selectedNode=item" ng-class="{selected: data.selectedNode == item}">{{item.value}}</div>
</div>
Please try out bellow code.
if click on row, bind clicked item value in selectedNode variable and apply active-row class.
<style>
.active-row{
background-color: #D4D0D0;
}
</style>
<div ng-init="selectedNode = false">
<div ng-repeat="item in items" ng-click="selectedNode=item.value" ng-class="(selectedNode == item.value) ? 'active-row' : ''">{{item.value}}</div>
<br />
</div>

Is it possible to bind and unbind an element on button click? - AngularJS

I created a display text and an input field and bind them together with ng-model as follow.
HTML
<div ng-app ng-controller="test">
<div ng-bind="content"></div>
<input id="txtElem" type="text" ng-model="content">
<button ng-click="stopBinding()"> Unbind</button>
<button ng-click="binding()"> Bind </button>
</div>
JS
function test( $scope ) {
$scope.content = 'Welcome';
$scope.binding = function() {
angular.element(document.getElementById('txtElem')).bind();
};
$scope.stopBinding = function() {
angular.element(document.getElementById('txtElem')).unbind();
};
};
Display
I found this(http://jsfiddle.net/jexgF/) for unbind method, but don't know how to bind it again, if "Bind" button is clicked. Anyone could help?
Apart from bind and unbind between elements of <div> and <input>, anyone know how to bind and unbind two <input> fields?
I'm not sure where the test() function in your example resides, but it is not a good idea - an anti-pattern, in fact - to manipulate the DOM in the controller.
The proper way is to create a variable, separate from the input variable content, represents the preview part.
You could do this simply in the View; if this logic, in your opinion, is a View-only logic. lastBound represents the last bound value of content:
<div ng-init="binding = true">
<input ng-model="content">
<button ng-click="binding = false">Unbind</button>
<button ng-click="binding = true">Bind</button>
<div ng-bind="lastBound = (binding && content) || lastBound"></div>
</div>
(the use of ng-init here is just for illustration purposes - you should set binding in the controller).
EDIT:
If the intent is to bind to another ng-model, then the solution is different, but not dissimilar. You still need to use 2 variables:
<input ng-model="content" ng-change="preview = (binding && content) || preview">
<input ng-model="preview" ng-change="content = (binding && preview) || content">

Angular checkboxes

I'm trying to make a check box that should be ticked when a value from the controller is filled (!= null).
It also need to be able to be ticked off and on, but I can't get it to work:
<input type='checkbox'
ng-false-value="''"
ng-model="entry[element.propertyName]"
id="q{{element.id}}"
ng-checked="entry[element.propertyName] != ''"
>
The check box is ticked when entry[element.propertyName] is filled, so far so good. But when I untick the check box the model remains unchanged, even though I've set ng-false-value, and the 'selected=selected' attribute doesn't disappear. When I tick and untick again, then the model starts to change to true and ''
Should be the easiest thing in the world, what am I missing here?
I'm using Angular 1.3.11
I have no idea why you are using ng-false-value, never saw that before.
Here is a snippet with a button updating a checkbox.
function testCtrl($scope){
// Initialise the checkbox as unckecked
$scope.testIsChecked=false;
// This function makes the checkob checked
$scope.makeItCHecked = function(){
$scope.testIsChecked=true;
}
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app>
<div ng-controller="testCtrl">
<div><input type="checkbox" ng-model="testIsChecked">
$scope.testIsChecked value : {{testIsChecked}}</div>
<button ng-click="testIsChecked=true">Make it checked</button>
</div>
</div>
See this link for explanation.
You can include the array in an object like:
public class objElement
{
string[] propertyName;
}
and then bind to your checkbox.

ng-click showing all the hidden text field on ng-repeat rather than one in Angular

I started to work with Angular, it's pretty good to implement, I stuck with a single issue at ng-click
I am getting data dynamically and showing with ng-repeat, and I want to update the data at pencil click and for it I am using input text element, but when I click on pencil It's opening all the text fields
Here is my HTML code
<
div ng-repeat="item in scroller.items track by $index">
<div class="secHead text-center">
<button class="common btnDarkGrey" data-ng-hide="hideCatButton">{{item.category_name}}</button>
<input type="text" id="focus-{{$index}}" class="common btnDarkGrey editDashboardCategory" name="editCategory" value="" data-ng-model="item.category_name" data-ng-show="hideField">
<span data-ng-click="updateCategory(item.category_id,item.category_name,$index)" class="chkOneDone" data-ng-show="hideOkButton">Done</span>
<div class="pull-right">
</div>
</div>
</div>
And here I Angular code
$scope.updateCategory=function(category_id,updated_cat_name, $index){
Category.updateCat($rootScope,$scope,$index,$http,$timeout,updated_cat_name,old_cat_name,category_id);
};
$scope.updatePen=function($index){
old_cat_name=$scope.scroller.items[$index].category_name
$scope.hideField=true;
$rootScope.hideOkButton=true;
$rootScope.hideCatButton=true;
};
I created a Category service to perform task like update
I didn't get any proper solution yet.
Can anybody help me?
Thank You.
If you only want to hide/show one of the elements in the list you need to specify that in some fashion. Right now you have a three rootScope booleans:
$scope.hideField=true;
$rootScope.hideOkButton=true;
$rootScope.hideCatButton=true;
being set for the entire list, and you need to set a show properties on each individual in the list.
In your controller function you can do something like this before you expect a click:
//normal for loop so that you have the index
for(var i=0; i < $scope.scroller.items.length; i++){
$scope.scroller.items[i].show = false;
}
Then you can do something like this to actually show the fields:
HTML:
div ng-repeat="item in scroller.items track by $index">
<div class="secHead text-center">
<button class="common btnDarkGrey" ng-hide="!item.show">
{{item.category_name}}</button>
<input type="text" id="focus-{{$index}}" class="common btnDarkGrey editDashboardCategory" name="editCategory" value="" ng-model="item.category_name" ng-hide="!item.show">
<span data-ng-click="updateCategory(item.category_id,item.category_name,$index)" class="chkOneDone" ng-show="item.show">Done</span>
<div class="pull-right">
</div>
</div>
</div>
Controller:
//controller declaration --
$scope.updatePen = function(index){
$scope.scroller.items[index].show = true;
};
It's my understanding that you need all three properties to show once a click happens, so I condensed all the show properties into one single show property.
Your view only sees that hideField is true and performs that action for all of the items in your array. I hope this helps!

Resources