Angular repeating radio button group in a list - javascript

I have 'recommendations', an array of recommendation like:
{Id: 1, Label: "option 1"},
{Id: 2, Label: "option 2"}
And 'items', an array of item like:
{Id: 1, Name: "Name 1", Recommend: recommendations[0]},
{Id: 2, Name: "Name 2", Recommend: recommendations[1]}
Now I like to show a list of items, for each item, show item name and radio button group to let user select one of possible 'Recommend' options.
My html looks like:
<div ng-repeat="i in viewModel.items">
<div>
{{i.Name}}
</div>
<div class="form-group">
<label class="control-label col-md-3">Recommend this?</label>
<div class="col-md-9">
<div class="radio" ng-repeat="r in viewModel.recommendations">
<label>
<input type="radio" ng-model="i.Recommend" ng-value="r"/>
{{r.Label}}
</label>
</div>
</div>
{{i.Name}}, {{i.Recommend.Label}}
</div>
</div>
{{viewModel.items | json}}
When I click one of options for each item, I see corresponding Recommend.Label is changing properly so it seems to be bound to model ok.
My problem is that, on initial page load, radio button group of each item is not showing the current option even though 'items' seems to have one of possible Recommend object. (All radio buttons are not checked).
What am I missing?

You should set the item's "Recommend" value to bound to $scope.recommendations at the beginning.
angular.module('test', []).controller('testCtrl', function($scope) {
$scope.viewModel = {};
$scope.viewModel.recommendations = [{Id: 1, Label: "option 1"}, {Id: 2, Label: "option 2"}];
$scope.viewModel.items = [{Id: 1, Name: "Name 1", Recommend: $scope.viewModel.recommendations[0]}, {Id: 2, Name: "Name 2", Recommend: $scope.viewModel.recommendations[1]}]; });
jsFiddle: http://jsfiddle.net/rkgetptj/

Related

angular 2 - radio button two way binding, get values in a hidden element

Plunker link
I am loading form from JSON.
I need help on below issue.
Issue : On click of save button i need to get the radio button values either true or false
but now i am getting both radio button values as 'true in console'
Users can click both the buttons, since it is a radio group, i need one value as true and another one as false vice versa
{name: "rado 1", type: "radio", id: "rOne", checked: true}
{name: "radio 2", type: "radio", id: "rTwo", checked: true}
My component HTML code
<div class="col-md-12 pb-2 pt-4">
<form class="form-horizontal">
<div *ngFor="let record of records">
<div *ngFor="let radioButton of record.wrapper">
<label>
//hidden element
<input type="hidden" name="{{radioButton.id}}" [(ngModel)]="radioButton.checked">
<input
name="radiogroup"
type="radio"
id="{{radioButton.id}}"
[checked]="radioButton.checked"
(change)="radioButton.checked = $event.target.checked"
[value]="radioButton.checked"
>
{{radioButton.name}}
</label>
</div>
</div>
<button class=" btn btn-primary " href="# " (click)="save() ">Save</button>
</form>
</div>`
Expected: I need radio button values true or false vice versa, it can not be both true or false.
values should be sent to hidden variables.
Two way binding
My Json (i have very complex json but here making it simple one)
[
{
"wrapper": [
{
"name": "rado 1",
"type": "radio",
"id": "rOne",
"checked": false
},
{
"name": "radio 2",
"type": "radio",
"id": "rTwo",
"checked": false
}
]
}
]
Edited
<label>
<input
name="radiogroup"
type="radio"
id="{{radioButton.id}}"
[value] = "radioButton.id"
[(ngModel)]="selectedRadioId" >
{{radioButton.name}}
</label>
ts :
// On click of save button show console log with values
save(): void {
this.records[0].wrapper.forEach((wrapper)=>{
wrapper.checked = wrapper.id == this.selectedRadioId;
})
console.log(this.records[0].wrapper[0]);
console.log(this.records[0].wrapper[1]);
}
Plunker

trying to set data and selected option to select in angular js

In my application i have select that i bind with options and the user selected saved data on page load.
Fiddle Link for issue
<div ng-app ng-controller="QuestionController">
<ul ng-repeat="question in Questions">
<li>
<div>{{question.Text}}</div>
<select ng-model="Answers['{{question.Name}}']" ng-options="option for option in question.Options">
</select>
<select ng-model="OptSelected" ng-options="option for option in question.Options">
</li>
</ul>
</div>
And in my angular controller
function QuestionController($scope) {
$scope.Answers = {};
$scope.Questions = [{ "Text": "Gender?", "Name": "GenderQuestion",
"Options": [{1,"Male"}, {2,"Female"}],
"OptSelected": [{1,"Male"}]},{ "Text": "Favorite color?","Name": "ColorQuestion",
"Options": [{1,"Red"}, {2, "Blue"}, { 3,"Green"}],"OptSelected": [{ 2, "Blue"}] }];
angular.forEach($scope.Questions, function(q) {
var propModel = "Answers['" + q.Name + "']";
$scope[propModel] = q.OptSelected;
})
In my application I am successful at binding data to select but i canot set the user saved value to select.
I have tried to recreate the issue with fiddle without much success but I think it will provide you all better understanding of what I am trying to do
I would recommend binding to just the Questions array and avoid the complexity of trying to bind to the corresponding question in an Answers array. You can always extract what you need from the Questions array either after a selection has been made or all together through some controller level action.
That said, part of your problem is that you don't have a well formed array of objects.
Here's a simplified, working version:
var app = angular.module('myApp', []);
app.controller('QuestionController', function($scope) {
$scope.Questions = [{
Text: "Gender?",
Name: "GenderQuestion",
Options: [{
id: 1,
desc: "Male"
}, {
id: 2,
desc: "Female"
}],
OptSelected: {
id: 1,
desc: "Male"
}
}, {
Text: "Favorite color?",
Name: "ColorQuestion",
Options: [{
id: 1,
desc: "Red"
}, {
id: 2,
desc: "Blue"
}, {
id: 3,
desc: "Green"
}],
OptSelected: {
id: 2,
desc: "Blue"
}
}];
});
<html ng-app="myApp">
<head>
<meta charset="utf-8" />
<script>
document.write('<base href="' + document.location + '" />');
</script>
<script data-require="angular.js#1.5.x" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.11/angular.min.js" data-semver="1.5.11"></script>
</head>
<div ng-controller="QuestionController">
<ul ng-repeat="question in Questions">
<li>
<div>{{question.Text}}</div>
<select ng-model="question.OptSelected" ng-options="option as option.desc for option in question.Options track by option.id">
</select>
</li>
</ul>
</div>
</html>

how to separate ng-repeat by date

I'm getting crazy to create a list separated by year and month name...
I would like to have something like:
Events in 2015
January
- event 1
- event 2
- event 3
February
- event 1
- event 2
...ecc...
Events in 2016
...ecc...
I don't think I have to create a repeater for each Year and Month, right? I think there is a filter or a rule to achieve this.
<div ng-app ng-controller="Main">
<div ng-repeat="event in events | what here?">
// how to create separators here?
{{event.title}}
</div>
</div>
$scope.events = [
{id: 1, title: "Title 1", date: 283764873126},
{id: 2, title: "Title 2", date: 283764873126},
{id: 3, title: "Title 3", date: 283764873126},
{id: 4, title: "Title 4", date: 283764873126}
];

Dynamically Creating Menu Structure using Knockout

I have a requirement to display menus and submenus but I have to populate the structure using a service response.
Below is the sample response I am getting from the service.
{name: "Item A",
url: "url of Item A",
title: "sometitle",
children: [{
name: "Child1 of A",
url: "url of Child1 of A",
title: "sometitle",
children: [{
name: "Grandchild of A",
url: "url of Grandchild of A",
title: "sometitle",
children: [{
name: "Grand Grand child of A",
url: "url of Grand Grand child of A",
title: "sometitle",
children: []
}]
}]
}]
},
{name: "Item B",
url: "url of Item B",
title: "sometitle",
children: []
},
{
name: "Item C",
url: "url of Item C",
title: "sometitle",
children: []
}
All the parent nodes Item A, Item B, Item c are displayed as menu buttons,with children as submenus. I have no information on the depth of the children.
Service can have any number of parents and any level of children nodes.
So,at runtime I have to create the menu structure.
Can i achieve the same using pure javascript ui/li tags? I want to create ui, li tags dynamically ,using a recursive function, which gives me a similar tree structure as shown in the response, Any pointer?
Thanks
Tani
I've faced this requirement myself, I'll present my solution:
I defined a Knockout template to render one item. This will be used to render the first 'tier' of items in your tree-like datastructure. The 'magic' is that the template will render the item's children, using the template itself. So the idea is basically a 'recursive template'. (Sorry if my explanation is a bit vague, the code below should make it clear.)
The template could look like this (suppose you store the service response in an array called items):
<script type="text/html" id="treeItem">
<li class="item">
<ul data-bind="template: { name: 'treeItem', foreach: children }"></ul> // Magic is in this line
</li>
</script>
Consume the template for the first tier of items:
<ul data-bind="template: { name: 'treeItem', foreach: items }"></ul>
Here is a Fiddle demonstrating the solution: http://jsfiddle.net/xsjxc8jd/
Edit: And it didn't even require observables :)

Use checkbox to select item Angular JS

I want to be able to have a list of items and to select one using a checkbox:
<div data-ng-repeat="device in devices">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label>
<input type="checkbox"> {{ device.name }}
</label>
</div>
</div>
</div>
If this can be done using a custom directive that would also be cool!
So the idea, that when a checkbox is checked the device would go into an ng-model and all the other checkboxes would be disabled.
I have a feeling there needs to be a custom model created, something like:
devices = [{
name: "LED",
checked: false,
id: "98"
},{
name: "LED 2",
checked: false,
id: "8"
},{
name: "LED 3",
checked: false,
id: "78"
}]
Just need some function to fire each time one checkbox is checked.
I expect that it can be done with a ng-click on the checkbox? And a two way data binding on the model for canBeChecked
devices = [{
name: "LED",
checked: false,
id: "98",
canBeChecked: true
},{
name: "LED 2",
checked: false,
id: "8",
canBeChecked: true
},{
name: "LED 3",
checked: false,
id: "78",
canBeChecked: true
}]
Iterate over your collection and display a checkbox for each:
<div ng-repeat="device in devices">
<label>
{{ device.name }}
<input type="checkbox" ng-model="device.checked" ng-click="change(device)">
</label>
</div>
Note that the checkbox also has the ng-click directive. This is what you want to trigger each time a checkbox is clicked. The triggered function clears all checkboxes and only checks the clicked one. The checkboxes should now behave like radio buttons.
Your controller might look like this:
app.controller("MyCtrl", ["$scope", function($scope) {
$scope.devices = [{
name: "LED",
checked: false
}, {
name: "LED 2",
checked: false
}, {
name: "LED 3",
checked: false
}];
$scope.change = function(device) {
angular.forEach($scope.devices, function(item) {
item.checked = false;
});
device.checked = true;
};
}]);
It is not necessary to create the canBeChecked property you mention.
Here's the full working example: http://jsfiddle.net/zxdr8/
If you must use checkboxes, here is how you would do it.
Markup:
<div data-ng-repeat="device in devices">
<div class="col-sm-offset-2 col-sm-10">
<div class="checkbox">
<label>
<input type="checkbox" ng-model="device.checked" ng-change="checkDevice(device)"> {{ device.name }}
</label>
</div>
</div>
</div>
Controller:
$scope.devices = [{
name: "LED",
checked: false,
id: "98"
},{
name: "LED 2",
checked: false,
id: "8"
},{
name: "LED 3",
checked: false,
id: "78"
}];
$scope.checkDevice = function (device) {
for (var i = 0, len = $scope.devices.length; i < len; ++i) {
if ($scope.devices[i] !== device)
$scope.devices[i].checked = false;
}
});
Your checked and canBeChecked properties seems like merely an UI thing. In my opinion, you should not be creating a custom data models and duplicating unnecessary properties just to do that. Believe me, I did things like that too when started using Angular, but there are much better ways.
Consider storing selected data in other location (model, service, controller, whatever). And maybe if you can store just an ID (primitive property), you can do your "checkbox-radio-like-element" like this:
<div ng-repeat="device in devices">
<label>
<input type="checkbox" ng-true-value="{{device.id}}" ng-false-value="" ng-model="some.storage">
{{device.name}}
</label>
</div>
And thats all you need, no background code needed. When Angular team implements interpolation support for ngTrueValue and ngFalseValue directives, you will be able to store the whole objects and reset model to e.g. null.

Categories

Resources