Not able to get value of radio select setting dynmically in AngularJS - javascript

Following is my code in which I am not getting selected radio option for each corresponding rows, let me know what I am doing wrong here.
My Plnkr Code - http://plnkr.co/edit/MNLOxKqrlN5ccaUs5gpT?p=preview
Though I am getting names for classes object but not getting the selection.
HTML code -
<body ng-controller="myCtrl">
<div class="container-fluid">
<form name="formValidate" ng-submit="submitForm()" novalidate="" class="form-validate form-horizontal">
<div class="form-group">
<label class="col-sm-2 control-label">Name</label>
<div class="col-sm-6">
<input type="text" name="name" required="" ng-model="classes.name" class="form-control" />
</div>
</div>
<div class="form-group">
<table id="datatable1" class="table table-striped table-hover">
<tr class="gradeA" ng-repeat="cls in reqgrps">
<td ng-bind="cls.name"></td>
<td><input type="radio" name="groupName[{{$index}}]" ng-model="classes.satisfies"> Choice 1</td>
<td><input type="radio" name="groupName[{{$index}}]" ng-model="classes.satisfies"> Choice 2</td>
<td><input type="radio" name="groupName[{{$index}}]" ng-model="classes.satisfies"> Choice 3</td>
</tr>
</table>
</div>
<div class="panel-footer text-center">
<button type="submit" class="btn btn-info">Submit</button>
</div>
</form>
</div>
<div class="result">{{classes}}</div>
</body>
Script File -
var myApp = angular.module('myApp', []);
myApp.controller('myCtrl', function($scope){
$scope.reqgrps = [{name: 'Sub1', roll: 121},{name: 'Sub2', roll: 122}, {name: 'Sub3', roll: 123}];
$scope.classes = {};
$scope.result = {};
$scope.submitForm = function() {
$scope.result = $scope.classes;
};
});
------------- EDIT -------------
Expected Output -
classes obj -
{
name: "Test Class",
satisfies: [
"Sub1": "Choice 1",
"Sub2": "Choice 3",
"Sub3": "Choice 2",
.................
..................
..................
..................
"Subn": "Choice 2",
]
}

You'll need to differentiate between each row that is generated by ng-repeat.
You can do this by adding [$index] to each ng-model like this:
<td><input type="radio" ng-model="classes.satisfies[$index]" value="Choice 1"> Choice 1</td>
<td><input type="radio" ng-model="classes.satisfies[$index]" value="Choice 2"> Choice 2</td>
<td><input type="radio" ng-model="classes.satisfies[$index]" value="Choice 3"> Choice 3</td>
As others have mentioned, you can make the result dynamic as needed by using ng-value to set the value that is passed into the model.
The resulting object is something like this:
{"name":"Bill","satisfies":{"0":"Choice 2","1":"Choice 1","2":"Choice 3"}}
See plunker here

You should specify a different ng-model property for each row. (Not sure why you'd want to specify the same model on 3 identical rows). In theory you don't HAVE to do this, but as I said, I don't see why you would.
Also you should add a value attribute on your radio buttons:
http://plnkr.co/edit/JN4JuQJH2OvRxoawfDbv?p=preview
From the angular docs:
value string
The value to which the expression should be set when selected.
https://docs.angularjs.org/api/ng/input/input%5Bradio%5D
I would also recommend removing the initialization of empty objects in your controller (if ng-model doesn't find the property on the scope it will just create it for you), and I've noticed you've used ng-bind, in case you didn't know that's just a shortcut for the double brackets: {{}}
EDIT:
In case your value needs to be a dynamic value you can use ng-value and specify a property on the scope which you can then set in your controller

You need to set ng-value for each radio button, so than Angular will be able to pick those values. You have 3 identical rows so I added some dummy values for them to show the right output.
http://plnkr.co/edit/AxUx83xdotniYru6amGU?p=preview
Also, you can find an explicit example of using Angular radio buttons in official docs here:
https://docs.angularjs.org/api/ng/input/input%5Bradio%5D
UPDATE:
Check edited plnkr, hope it helps!

Related

Angular 2 - Add Value of Checked Radio Button to Array

I am trying to get the checked radio button and add the value to an Array. Currently, i cannot remove the previously checked radio buttons, so basically it keeps adding to the array every time i select a radio button.
item.component.ts
displaySelectedConditions(event) {
if(event.target.checked) {
this.selectedConditionsArr.push(event.target.value);
}
}
item.component.html
<ul class="dropdown-menu">
<li *ngFor="let item of filteredItems | funder "> //generates 4 items
<a><input type="radio" (change) = "displaySelectedConditions($event);"
name="funder" id="{{item}}" value="{{item}}">
<label for="{{item}}" >{{item}}</label></a>
</li>
</ul><!-- Dropdown Menu -->
I would suggest if you want to have the values neatly stored somewhere, then make use of a form. Simple template driven form works well here, then you would have all your values stored in an object, here's a sample:
<form #radioGroup="ngForm">
<div *ngFor="let str of strings">
<input type="radio" [value]="str" name="str" ngModel />{{str}}
</div>
<hr>
<div *ngFor="let num of numbers">
<input type="radio" [value]="num" name="num" ngModel />{{num}}
</div>
</form>
This would create an object like:
{
str: "value here",
num: "value here"
}
And if you declare the form like the following, you can easily access the object values:
#ViewChild('radioGroup') radioGroup: NgForm;
Somewhere in component:
console.log(this.radioGroup.value);
Plunker

Using the angular datepicker with ng-repeat

I'm trying to write something that lets me edit records with dates in them, I have this inside my table:
<tr ng-repeat="event in eventFixtures track by $index">
<td>{{event.date | date: 'dd/MM/yyyy'}}</td>
<td>
<div class="row">
<div class="col-md-6">
<p class="input-group">
<input type="text"
class="form-control"
ng-model="event.date"
is-open="fixture{{$index}}popup"
ng-click="openFixturePopup($index)"/>
</p>
</div>
</div>
</td>
</tr>
However when I go to click on one of the input boxes the datepicker doesn't show up.
The open function is here:
$scope.openFixturePopup = function(fixture) {
$scope["fixture"+fixture+"popup"] = true;
};
The variables are delcared like so:
for(var i = 0; i < data.length; i++) {
$scope["fixture"+i+"popup"] = false;
}
From having the values of the variables be printed out above the table, they are being changed and if I create an input that is linked to a specific fixture popup e.g. like this:
<div class="row">
<div class="col-md-6">
<p class="input-group">
<input type="text"
class="form-control"
uib-datepicker-popup="{{format}}"
ng-model="testDate"
is-open="fixture0popup"
ng-click="openFixturePopup(0)"/>
</p>
</div>
</div>
It works fine.
Does anyone know what might be causing this?
I have a hunch that trying to use interpolation for a variable name is what is throwing this off. I tried numerous things like $scope[dynamicVarName], $scope.$eval([dynamicVarName]), and others to no avail. I can't say for certain that is your issue, but I think I found a solution that you can try.
Set an isOpen flag on your event and look at that, rather than creating a bunch of scope variables for state. This is also advantageous because if the index changes, the open state moves with the array element, so there is less chance that you get invalid states.
Here's what the code could look like:
var app = angular.module("myApp", [])
.controller("myCtrl", function ($scope) {
$scope.eventFixtures = [
{name: "1", date: "1-1-01"},
{name: "2", date: "2-2-02"},
{name: "3", date: "3-3-03"},
{name: "4", date: "4-4-04"},
{name: "5", date: "5-5-05"}
];
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="myCtrl">
<table>
<tr ng-repeat="event in eventFixtures track by $index">
<td>{{event.date | date: 'dd/MM/yyyy'}}</td>
<td>
<div class="row">
<div class="col-md-6">
<p class="input-group">
<input type="text"
class="form-control"
ng-model="event.date"
is-open="{{event.isOpen}}"
ng-blur="event.isOpen = false;"
ng-focus="event.isOpen = true;"/>
isOpen? {{event.isOpen || false}}
</p>
</div>
</div>
</td>
</tr>
</table>
</div>

input controls disabled in tfoot under ng-repeat

JSON returns more than 3 types of student details and for each student succeeded creating a table but among the three for one student of type partner should have some input controls like a checkboxes and buttons available. the problem am facing is that the checkboxes are showing up but the controls are disabled
this is what i have tried
{{i.memberType | fcap}} Member - {{i.name.first}} {{i.name.last}}
<tfoot ng-show="i.memberType == 'PARTNER'">
<tr>
<td>
<input type="checkbox" id="iautho" ng-model="iautho" ng-checked="ctrl.isAuthorized">
<label for="iautho">I authorize this member to view and update student information.</label>
<input type="checkbox" id="ihave" ng-model="ihave" ng-checked="ctrl.isAuthorized">
<label for="ihave" ng-show="iautho">I have read, understand and voluntarily agree to all the terms and conditions of the
Partner Access Authorization agreement.</label>
<button id="studentdetails" type="submit" class="btn btn-primary" ng-disabled="!ihave">Update
</button>
</td></tr>
<hr class="m-y-1">
</tfoot>
May I know what am I doing wrong ?
the problem am facing is that the checkboxes are showing up but the controls are disabled
Your have both ng-model and ng-checked. You should not use ng-checked as ng-model is enough.
Quick example : http://jsfiddle.net/Lvc0u55v/736/
var myApp = angular.module('myApp',[]);
function MyCtrl($scope) {
$scope.foo = true;
}
<div ng-controller="MyCtrl">
<input type="checkbox" ng-model="foo"/>
</div>

Displaying different <tr> depending on radio button (in Knockout)

OK, here goes.
Problem 1:
I want to, based on the radio button checked, display a tr-element or not. Threre will be 3 buttons, displaying 'unlocked achievements', 'locked', and 'all' (both locked + unlocked).
The code below shows how it looks when I try to call three different functions, each setting the tr:s visibility to true/false depending on radio button checked. (D.R.Y, I know, but right now I'm just looking for the functionality).
Problem 2:
Making the for-loop run. itemsListForFilter is declared globally, outside the filter function. itemsListForFilter is a copy of an object arrayMap which is initiallized and filled elsewhere in the code. The array contains items with - amongst other things - the boolean "radioCheck", with the default value "true", which I want to check.
When I access itemsListForFilter in the function where the copying takes place it's filled with items but...
When I try to access itemsListForFilter in the filter function it displays as having the value of null. So the copy is "lost" somewhere :)
View / HTML:
<div class="widget-header-container">
<h3 class="widget-header">Achievements</h3>
<div class="wrapper">
<input type="radio" name="appliedFilter" value="all" data-bind="checked: filterAll"/><label for="all">Show all</label>
<input type="radio" name="appliedFilter" value="unlocked" data-bind="checked: filterUnlocked"/><label for="unlocked">Unlocked</label>
<input type="radio" name="appliedFilter" value="locked" data-bind="checked: filterLocked"/><label for="locked">Locked</label>
</div>
<div><div class="widget-header-line-game1"></div><div class="widget-header-line-game2"></div><div class="widget-header-line-shadow"></div></div>
</div>
<div>
<div class="rounded-box" style="padding:15px;padding-top: 0;background-color:#fff;overflow:hidden;">
<table id="game-achievements" class="table table-condensed" style="margin-top:10px;">
<tbody data-bind="foreach: viewGame.achievements()">
<tr data-bind="visible: radioCheck" style="display: none">
Viewmodel / JS:
filterUnlocked: function(){
return filter('unlocked');
},
filterLocked: function(){
return filter('locked');
},
filterAll: function(){
return filter('all');
},
filter: function(x){
for (var item in itemsListForFilter){
if (x === 'locked'){
item.radioCheck = '!achieved';
}
if (x === 'unlocked') {
item.radioCheck = 'achieved';
}
else {item.radioCheck = true;}
}
Observe that the viewmodel is an object and not a function:
var gamesViewModel = {
self: this,
settings: null,
gameId: null,
authorized: false,
(...)
Right now the functions named filterUnlocked, etc (except filter) displays as "unused properties" in the JS file. What should i do to call them from the HTML? Or is there a better way to accomplish what I'm looking for?
Thank you.
You can get the effect you want with less complexity.
First, the radio group. The checked binding in Knockout kind of replaces (or acts like) the name attribute for a radio group: all the radio buttons should share one. The bound variable will be updated to the value of the selected radio button, which will cause others bound to the same variable to de-select. Now you have one variable to look at instead of three.
Instead of doing filtering by hiding rows, it is more usual to have a computed filter the data, and the table just displays it. The computed can get the data from "outside"; it doesn't have to be an observable or part of the viewmodel (although if it's not an observable, you'll need to tell the computed when to update, if the source changes).
Here's a little working example:
var achievements = [{
name: 'The locked one',
locked: true
}, {
name: 'The unlocked one',
locked: false
}];
var vm = {
appliedFilter: ko.observable('all'),
viewGame: {}
};
vm.viewGame.achievements = ko.computed(function() {
var filter = vm.appliedFilter();
if (filter === 'all') {
return achievements;
}
return ko.utils.arrayFilter(achievements, function(item) {
return item.locked === (filter === 'locked');
});
});
ko.applyBindings(vm);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<div class="widget-header-container">
<h3 class="widget-header">Achievements</h3>
<div class="wrapper">
<input type="radio" value="all" data-bind="checked: appliedFilter" />
<label for="all">Show all</label>
<input type="radio" value="unlocked" data-bind="checked: appliedFilter" />
<label for="unlocked">Unlocked</label>
<input type="radio" value="locked" data-bind="checked: appliedFilter" />
<label for="locked">Locked</label>
</div>
</div>
<div>
<div class="rounded-box" style="padding:15px;padding-top: 0;background-color:#fff;overflow:hidden;">
<table id="game-achievements" class="table table-condensed" style="margin-top:10px;">
<tbody data-bind="foreach: viewGame.achievements()">
<tr><td data-bind="text: name"></td></tr>
</tbody>
</table>
</div>
</div>

How to dynamically create multiple form input fields with incremented ng-models?

After reading this article, I understand how to dynamically add a form field using ng-repeat.
I am wondering how can multiple form elements be dynamically created with incrementing ng-model values.
For example, the following would be created from a button click.
<input ng-model="vm.foo.bar1.first">
<input ng-model="vm.foo.bar1.second">
<input ng-model="vm.foo.bar1.third">
<input ng-model="vm.foo.bar1.fourth">
<input ng-model="vm.foo.bar2.first">
<input ng-model="vm.foo.bar2.second">
<input ng-model="vm.foo.bar2.third">
<input ng-model="vm.foo.bar2.fourth">
<input ng-model="vm.foo.bar3.first">
<input ng-model="vm.foo.bar3.second">
<input ng-model="vm.foo.bar3.third">
<input ng-model="vm.foo.bar3.fourth">
How can this be done?
I would suggest to restructure your ViewModel to make vm.foo.bar an array. Then this would be trivial:
<div ng-repeat="item in barItems">
<input ng-model="vm.foo.bar[$index].first">
<input ng-model="vm.foo.bar[$index].second">
<input ng-model="vm.foo.bar[$index].third">
<input ng-model="vm.foo.bar[$index].fourth">
</div>
Or, if you insist, then also
<div ng-repeat="item in barItems" ng-init="outerIdx = $index">
<input ng-repeat='p in ["first", "second", "third", "fourth"]'
ng-model="vm.foo.bar[outerIdx][p]">
</div>
(I'm assuming here, that unlike with first, second, etc..., the number of bars is not known - hence an array is a better option)
EDIT:
If you really want, you could also make vm.foo an object that holds properties bar1, bar2, etc...:
<div ng-repeat="item in [1, 2, 3, 4]">
<input ng-model="vm.foo['bar' + item].first">
<input ng-model="vm.foo['bar' + item].second">
<input ng-model="vm.foo['bar' + item].third">
<input ng-model="vm.foo['bar' + item].fourth">
</div>
but don't forget to first create vm.foo object in the controller:
this.foo = {};
When I have to do this I use the $index to control the names of things. Although I've never tried this exact code, this should work.
<input ng-model='vm.foo.bar3[$index]'></input>
$index comes along whenever you do ng-repeat and is just the index of the list item. So that should end up making ng-models that are vm.foo.bar3.0 to whatever.
To my point of view, you should create arrays of models in your controller.
$scope.vm.foo = [{
bar1: [{
first: '',
second: '',
...
},
bar2: ...
],
}]
And then in your view iterate on your tab :
<div ng-repeat="elem in foo">
<div ng-repeat="input in elem">
<input ng-model="input">
</div>
</div>
Hope it will help you !

Categories

Resources