AngularJS Checkbox not working - angularjs

I have a class called Case that contains a list of executionSteps. Each executionStep has a boolean property called enabled. I am trying to set in on the HTML side but it never gets updated on the JS side.
HTML side
<td>
<input type="checkbox"
ng-checked="acase.executionSteps[0].enabled"
ng-model="aa" ng-change="updateCaseExecutionStep('{{study.id}}','{{acase.id}}','{{acase.executionSteps[0].id}}','{{acase.executionSteps[0]}}')"/>
</td>`
On the controller side I have the function
updateCaseExecutionStep
defined as shown below
$scope.updateCaseExecutionStep = function(studyId,caseId,executionStepId,executionStep){
...
...
}
Problem is when I update my checkbox or even manually update the enabled property of the executionStep
$scope.updateCaseExecutionStep = function(studyId,caseId,executionStepId,executionStep){
executionStep.enabled = true;
...
}
I don't see any change. The enabled property of executionStep passed in the JS does not change. Please help.
Do I have to modify somehow on the The HTML side ?

You are trying to force too complex solution. To start with, you do not need ng-checked nor ng-change when you are using ng-model.
Let's say you have the following controller
app.controller('MainCtrl', function($scope) {
$scope.case = {
caseId: 0,
steps: [
{ id: 1, name: 'First step', enabled: true },
{ id: 2, name: 'Second step', enabled: false },
{ id: 2, name: 'Third step', enabled: false }]
};
});
And related HTML
<div ng-repeat="step in case.steps">
<input type="checkbox" ng-model="step.enabled"> {{ step.name }}
</div>
That's all it takes!
Example Plunk here http://plnkr.co/edit/QjD91l
Edit:
If you need to do some processing based on selection, then yes, you could add ng-change to input control. Then HTML becomes
<input type="checkbox" ng-model="step.enabled" ng-change="stateChanged(step)"> {{ step.name }}
And in controller
$scope.stateChanged = function(step){
console.log('Changed step id:' + step.id + ' enabled state to ' + step.enabled;
};

I had to abandon ng-model for my checkbox as it was not picking up the initial value that was set in the model (in response to a service call). All of the other input controls were responding correctly to the model (and, interestingly, were correctly enabled/disabled based on the value backing the checkbox).
Instead, I used the 'checked' attibute and ng-click, as so:
<input type="text" ng-disabled="!myModel.isFruit" ng-model="myModel.seedCount">
<input type="checkbox" checked="{{myModel.isFruit}}" ng-click="onFruitClicked()"> Is Fruit
In my controller:
$scope.myModel = {
isFruit : myServices.getIsFruit(),
seedCount : myServices.getSeedCount()
};
$scope.onFruitClicked = function() {
// toggle the value
$scope.myModel.isFruit = !$scope.myModel.isFruit;
// save the new value
myServices.setIsFruit($scope.myModel.isFruit);
};

Related

Selectpicker doesn't fill when using with AngularJS

I'm trying to fill a select options (selectpicker), but without success. My competenceArray is filled correctly, but in my HTML never appears the options.
Someone can help me with the selectpicker ?
JS
(() => {
angular
.module('talent')
.controller('FunctionalityCreateCtrl', Create);
function Create($timeout, GatewayService) {
const vm = this;
vm.form = {};
vm.competencesArray = [];
getCompetences();
function getCompetences() {
GatewayService.get('/competences')
.then((data) => {
vm.competencesArray = data._embedded;
})
.catch(() => {
console.log('nope');
});
}
}
})();
HTML
<select
class="selectpicker"
data-style="select-with-transition"
title="Select a value"
data-size="7"
ng-model="functionality.form.comp"
ng-options="s.name for s in functionality.competencesArray">
<option value=""> Select</option>
<select>
You should refresh select picker after complete ajax request . From the docs :
To programmatically update a select with JavaScript, first manipulate
the select, then use the refresh method to update the UI to match the
new state. This is necessary when removing or adding options, or when
disabling/enabling a select via JavaScript.
When complete ajax request , you need refresh select , and put it in $timeout for angular re-render dom . Here is example :
function getCompetences() {
GatewayService.get('/competences')
.then((data) => {
vm.competencesArray = data._embedded;
$timeout(function(){
$('.selectpicker').selectpicker('refresh'); //put it in timeout for run digest cycle
},1)
})
.catch(() => {
console.log('nope');
});
}
Hope it help
You haven't posted the full context of your code so I'm assuming that you have defined the angular module "talent" and that the element is within the scope of the FunctionalityCreateCtrl. I have wrapped your example HTML in a div with ng-app and ng-controller attributes just so the example is functional.
The first error I see in the code example you posted is the element is not closed properly. The close tag is missing a forward slash: </select>.
The other error is you are setting the model of the select element to be form.comp but form.comp doesn't seem to be set to anything. I've added it in the code example below.
Also notice that I've added an id to the ng-options expression ng-options="s.id as s.name for s in functionality.competencesArray"> This is just so I can set the model (form.comp) to a value I know. Your data may be different.
Working html snippet:
<div ng-app="talent" ng-controller="FunctionalityCreateCtrl as functionality">
<select
class="selectpicker"
data-style="select-with-transition"
title="Select a value"
data-size="7"
ng-model="functionality.form.comp"
ng-options="s.id as s.name for s in functionality.competencesArray">
<option value=""> Select</option>
</select>
</div>
Working Javascript snippet (I've added the talent module definition and removed the api call just so the example is functional):
(() => {
angular.module('talent', []);
angular
.module('talent')
.controller('FunctionalityCreateCtrl', Create);
function Create() {
const vm = this;
vm.form = {};
vm.competencesArray = [];
getCompetences();
function getCompetences() {
vm.competencesArray = [
{ id: 1, name: 'test 1' },
{ id: 2, name: 'test 2' },
{ id: 3, name: 'test 3' }
];
vm.form.comp = 1;
}
}
})();
Here is a working JSFiddle using your example code: https://jsfiddle.net/g8r9ajtL/

$scope.formName.$setPristine() does not work ; How to reset form in angular?

create a form in angular 1.5
< form name="movieForm" ng-submit="addMovie(movie) ../>
and when I try to reset the form after form submission using
$scope.movieForm.$setPristine()
BUT it gives error in console : Cannot read property '$setPristine' of undefined
form.html
<form name="movieForm" novalidate role="form" ng-submit="movieForm.$valid && addMovie(movie)">
<input type="text" ng-model="movie.name" name="mName" required />
<input type="text" ng-model="movie.star" name="mStar" />
<input type="number" ng-model="movie.year" name="mYear" required />
<input type="submit" value="Save" />
<input type="button" value="Reset" ng-disabled="movieForm.$pristine" ng-click="reset()" />
</form>
app.js
(function() {
var app = angular.module('app', []);
app.controller('movieController', function($scope) {
$scope.title = "Home Page";
$scope.movieData = [{
name: 'PiKu',
star: 'Irrfan Khan',
releaseYear: '2015'
}];
$scope.addMovie = function(movie) {
if(movie && movie.name) {
$scope.movieData.push({
name : movie.name,
star : movie.star,
releaseYear : movie.year
});
}
};
$scope.reset = function() {
$scope.movieForm.$setPristine();
$scope.movieForm.$setUntouched();
};
// **un-commenting below line gives error in console**
//$scope.reset();
});
}());
also checked $scope.movieForm() in console but its undefined ?
What is the issue?
see the DEMO
You're trying to access $scope.movieForm before bindings actually initialized.
Edit
To be clear: $setPristine - not clears form fields. For clearing form fields you can just reset the object that form controls are bound to:
$scope.movie = {};
here's working demo
I think you are using $setPristine wrong.
"This method can be called to remove the 'ng-dirty' class and set the form to its pristine state (ng-pristine class). This method will also propagate to all the controls contained in this form."
So this only clears classes but not the $scope variables. You have to reset $scope.movie variable.
for example I added this default form variable
var defaultForm={
name: "",
star: "",
year: ""
}
and modified your reset code
$scope.reset = function() {
$scope.movie = angular.copy(defaultForm);
$scope.movieForm.$setPristine();
};
This works fine.
Check out the fiddle.
http://output.jsbin.com/hugiye/2
As per the angular docs $setPristine():
"This method can be called to remove the 'ng-dirty' class and set the form to its pristine state (ng-pristine class). This method will also propagate to all the controls contained in this form."
This only reset classes not the actual scope variable.
If you want to set scope variable to default state then you should reset scope variable too.
`
var movie = {
name: '',
star: '',
year: ''
};
and in your reset function you have to add this
$scope.movie = angular.copy(movie);
`

How can I make ng-init to trigger ng-change?

I just started learning Angular. There is a <select> element that should fill the input elements below with one of some presents.
This is my view.
<select
ng-model="selection"
ng-options="preset.name for preset in presets"
ng-init="selection=presets[0]"
ng-change="select()"></select>
<input ng-model="name" type="text"/>
<textarea ng-model="description"></textarea>
This is my controller.
$scope.presets = [
{ name: 'Lorem ipsum', description: 'Dolor sit amet.' },
{ name: 'Consectetur', description: 'Adipisicing elit.' },
{ name: 'Sed do', description: 'Eiusmod tempor.' },
];
$scope.select = function() {
$scope.name = $scope.selection.name;
$scope.description = $scope.selection.description;
};
When I load the page, I can see the first option selected. But the input fields remain blank until I manually change the selection. Why doesn't Angular set the input fields automatically in the first place and what can I do about it?
The reason it does not set the text fields initially is because there is no binding setup for $scope.name and $scope.description until select() is called. You could set it up initially in your controller function:
$scope.init = function(selected) {
$scope.selection = selected;
$scope.name = $scope.selection.name;
$scope.description = $scope.selection.description;
}
$scope.select = function() {
$scope.name = $scope.selection.name;
$scope.description = $scope.selection.description;
};
And in your HTML:
<select
ng-model="selection"
ng-options="preset.name for preset in presets"
ng-init="init(presets[0])"
ng-change="select()"></select>
Alternative Method:
Alternatively, you can have the input fields bind to the same selection model. That way,
when the selection model is updated on the scope, it will update all the associated views.
Change the model to 'selection.name' and 'selection.description':
<input ng-model="selection.name" type="text"/>
<textarea ng-model="selection.description"></textarea>
There is no need for the select() function anymore because there is already a two-way binding setup between the selected model and the input fields.

Saving a checkbox list in Angularjs with node

I want to save and load a checkbox list using binding in angularjs with a node backend. This SO question (How do I bind to list of checkbox values with AngularJS?) answers how I can load the check box from a static javascript object but how can I save the checkbox values after the user selects them?
I want to save the checkbox values in a single field but how can I tell angular to bind the checkbox values into a single field defined in a model to my mongodb? I cant just use ng-model as there are multiple checkboxes.
Needless to say that I am new to angular so any help here is greatly appreciated ...
Thanks for any help you can provide.
kseudo
Just add ng-model to your checkbox. By this way you can update model in controller on any checkbox state change.
Here is example:
HTML
<div ng-controller="Ctrl">
<label ng-repeat="fruit in fruits">
<input
type="checkbox"
name="fruit.name"
ng-model="fruit.value"
> {{fruit.name}}
</label>
<pre>{{fruits| json}}</pre>
</div>
JS
var app = angular.module('app', []);
function Ctrl($scope) {
$scope.fruits = [{
name: 'apple',
value: false
}, {
name: 'orange',
value: false
}, {
name: 'pear',
value: false
}, {
name: 'naartjie',
value: false
}];
}
Demo Fiddle
[EDIT]
BTW we can make the copy by using angular.copy() method. When we press button, the new copy of fruits model will be created (and you should send it to server as json). Old model fruits will stay the same:
$scope.fruitsCopy = [];
$scope.init = function(){
$scope.fruitsCopy = angular.copy($scope.fruits );
}
To convert data to JSon I would use:
var jsonData = JSON.stringify($scope.fruitsCopy);
Demo2 Fiddle
Let's say you defined your model as such:
function Ctrl($scope) {
$scope.items = [{
name: 'A',
checked: false
}, {
name: 'B',
checked: false
}, {
name: 'C',
checked: false
}, {
name: 'D',
checked: false
}];
}
And created a view for the model:
<ul>
<li ng-repeat="item in items">
<label>
<input type="checkbox" ng-model="item.checked">
{{item.name}}
</label>
</li>
</ul>
<button ng-click="save()">save</button>
Next you have to define save function:
$scope.save = function() {
//angular.toJson converts array to string, something like
// '[{"name":"A","checked":false},{"name":"B","checked":true},...]'
var json = angular.toJson($scope.items);
//Service is angular service for your model that makes http requests to your backend
Service.save(json).then(function(){
//here you can notify user that data is persisted
}, function() {
//here you can notify user that there was a problem with request
});
}
And a simple model service:
.service('Service', function($http) {
return new function() {
this.save = function(data) {
return $http.post('url/to/backend', data);
}
}
});

AngularJS default value for ng-model

Is it possible to make ng-models get default values, like ''?
I have a form on which I have used jQuery's serialize function, and whenever a a value is not present, it will still include it in the serialized data, E.g. {name: '', age: ''}.
However, when I use try using posting it by using Angular's $http and getting the model from $scope, it appears as undefined when it is empty.
You may also try:
<div ng-init="foo={}">
<input type="text" ng-model="foo.name=''"/>
</div>
or:
<input type="text" ng-init="foo.name=''"/>
it will present:
foo = { name: '', .... }
You can simply define the properties on the model in the scope in advance of using them in your view.
If you show your controller code I'll show you what you need to update to add them to the scope.
It should look something like:
In your js file that defined the app
angular.module("MyModule", []).controller('MyCtrl', ['$scope', function ($scope) {
$scope.myModel = {name:""};
}]);
In your HTML
<input type="text" ng-model="myModel.name"/>
Note I prefer not having global variables/functions so I'm using a different syntax provided by Angular to avoid this and to allow for minification.
You shouldn't need to use jQuery serialize.
Your form should be bound to the scope like this:
<form ng-controller="MyCtrl" ng-submit="submit()">
<input type="text" name="name" ng-model="formData.name">
<input type="text" name="age" ng-model="formData.age">
<input type="submit" value="Submit Form">
</form>
function MyCtrl($scope) {
$scope.formData = {};
$scope.submit = function() {
$http.post('/someUrl', $scope.formData)
};
}
So that in $http you can simply pass $scope.formData.
Is there a more effective way to serialize a form with angularjs?
Sometimes, you don't know if the value is set or not. That's what defaults are for.
I use this when I need to make sure a variable has some value. You can set it in your controller
$scope.possiblyEmptyVariable = $scope.possiblyEmptyVariable || "default value";
Works great without Angular as well
// some object that may or may not have a property 'x' set
var data = {};
// Set default value of "default"
// carefull, values like 'null', false, 0 will still fall to defaults
data.x = data.x || "default";
// Set default value of "default"
// this will not fall to defaults on values like 'null', false, 0
data.x = !"x" in data || "default";
If you need to set a bunch of values, use angular.extend or jQuery.extend
data.z = "value already set";
var defaults = { x: "default", y: 1, z: "default" };
var newData = angular.extend({}, defaults, data);
// { x: "default, y: 1, z: "value already set" }
Hope that helps

Resources