I have this array of objects. In each object there is another array.
panels = [{
Id: "26cfdb68-ef69-4df0-b4dc-5b9c6501b0dd",
Name: "Celiac test",
Tests: [{
Id: "e2bb4607-c227-4483-a3e9-55c1bc5a6781",
Name: "test 1 (DGP) IgG"
},
{
Id: "e2bb4607-c227-4483-a3e9-55c1bc5a6781",
Name: "test 2 (DGP) IgG"
},
{
Id: "e2bb4607-c227-4483-a3e9-55c1bc5a6781",
Name: "test 3 (DGP) IgG"
}
]
}, and so on],
I have mapped it to a bootstrap accordion with checkboxes.
First there is a checkbox for the main object, then checkboxes for the array within that object.
What I want is that when I click on the main Panel checkbox it should select the Tests checkboxes and save the panel object in the object variable, say selectedPanel, and when I deselect the main Panel it should deselect all the Tests checkboxes too.
but the main thing is that when I deselect one of the Tests checkboxes it should be removed from selectedPanel.
and the issue is it should be done on basis of Id, not checked/selected coming from backend.
Can anyone help me in this regard?
I have created a stackblitz too:
Stackblitz
Try modifying your checkItem() as below
checkItem(panel: any) {
panel.isChecked = !panel.isChecked;
panel.Tests.forEach(e => {
e.isChecked = true;
});
}
When you are done, your panels object will hold the statues of all checkboxes.
First create array which will hold selected checkboxes. This array will hold id of selected panels/tests.
selectedCheckboxes: [];
To make binding with checkbox "checked" attribute you will need another param to your object, let's call it "checked" for simplicity.
checked: true/false
In your HTML code
<input type="checkbox" class="form-check-input ml-5" id="{{panel.Id}}" name="{{panel.Name}}" (change)="togglePanelCheck(panel)" [checked]="panel.checked">
<input type="checkbox" class="form-check-input ml-5" id="{{test.Id}}" name="{{test.Name}}" [checked]="test.checked" (change)="toggleCheck(test)">
Code for toggle checking:
togglePanelCheck(panel){
if(panel.checked){
this.uncheckPanel(panel);
} else {
this.checkPanel(panel);
}
}
checkPanel(panel){
this.checkItem(panel);
if(this.panelHasTests()){
panel.tests.foreach(test => {
this.checkItem(test);
});
}
}
uncheckPanel(){
this.uncheckItem(panel);
if(this.panelHasTests()){
panel.tests.foreach(test => {
this.uncheckItem(test);
});
}
}
toggleCheck(item){
if(item.checked){
this.uncheckItem(item);
} else {
this.checkItem(item);
}
}
checkItem(item){
this.selectedCheckboxes.push(item.id);
item.checked = true;
}
uncheckItem(item){
const index = this.selectedCheckBoxes.indexOf(item.id);
this.selectedCheckBoxes.splice(index, 1);
item.checked = false;
}
private panelHasTests(panel) : boolean {
return panel.tests && panel.tests.length != 0;
}
Related
I'm creating multiple input fields with checkboxes in vue and I want that only one can be true. So if the user clicks on one the others should be false so that only the last clicked checkbox is true.
My code is like that:
new Vue({
el: "#app",
data: {
selected: null,
options: [
{"id": 1, "title": "One", "value": false},
{"id": 2, "title": "Two", "value": false },
{"id": 3, "title": "Three", "value": false},
]
},
watch: {
selected(selected) {
this.options.forEach((option, index) => {
option.id == selected ? option.value = true : option.value = false;
});
}
}
Unfortunately my watcher isn't working properly. I would be really glad if somebody can show me how to correct it. I want that always the last true element is the only true element and the watches sets all other elements in options to false.
If i understood your requirements correctly you can still do it with radio buttons. You can specify the value to be used inside the selected variable, as described here: https://v2.vuejs.org/v2/guide/forms.html#Radio-1. This means that you can set up a watcher and then mutate the options list accordingly:
selected: function (newVal) {
this.options.forEach(option => {
if (option.id === newVal) option.value = true
else option.value = false
})
console.log(this.options)
}
Here is a sandbox to see it in action:
https://codesandbox.io/s/heuristic-goldberg-lilsw
Update: Just saw that you want to use the </b-switch> from buefy. You can still do something similar by calling a function from the input event which then mutates the options list according to the just changed element. Something like this:
<div v-for="(option,index) in options" :key="index">
<div class="box">
<div class="field">
<b-switch v-model="option.value" #input="(modelValue) => onSwitchChanged(modelValue, option.id)">
{{ option.title }}
</b-switch>
<label :for="index">{{ option.title }}</label>
</div>
</div>
</div>
function onSwitchChanged(modelValue, id) {
if (!modelValue) return
this.options.forEach(option => {
if (option.id === id) option.value = true
else option.value = false
})
}
If you want that Only One will be selected then you have to use radio button. Checkbox has options to select all But One by One.
Without watch you can use methods. Pass index to the method.
<input
type="checkbox"
:id="index"
:value="option.id"
#click="selectAnOption(index)"
>
Method:
methods: {
selectAnOption(index) {
this.options[index].value = true
}
}
Full Code here: https://jsfiddle.net/8ktdp9ew/
I have a child component which consists of 3 checkboxes (generated dynamically using ngFor) and an Apply and Cancel button.
Selector tag for the child is added in the parent's template. Parent component accesses this child component using #ViewChild and calls the present() method exposed by the child component with an object as argument as below which consists of checked state of the checkboxes.
Every time when modal is displayed, present() method is getting called. For the first time, UI/checkboxes is getting updated/checked as the values sent by parent. But, in the subsequent calls to present(), even though options.checked value is getting updated as expected in the ts file, this is not getting reflected in the UI. Every time the modal is displayed, I want checkbox to be checked or unchecked based on the value sent by the parent in present() method. Need help. Thanks in advance
parent.component.ts:
#ViewChild(childModalComponent) childModalComponent: ChildModalComponent;
onBtnClick() {
this.childModalComponent.present({
checkbox1: true,
checkbox2: false,
checkbox3: false
});
}
parent.component.html:
<feature-child-modal></feature-child-modal>
child.component.ts:
#ViewChild('childModal') childModal: ElementRef;
ngOnInit() {
this.options = [
{
label: 'label1',
value: 'value1',
checked: false,
},
{
label: 'label2',
value: 'value2',
checked: false,
},
{
label: 'label3',
value: 'value3',
checked: false,
},
];
}
present(optionsState: CompressTransactionType) {
this.options.forEach(item => {
if(item.value == "value1"){
item.checked = optionsState.checkbox1;
}
if(item.value == "value2"){
item.checked = optionsState.checkbox2;
}
if(item.value == "value3"){
item.checked = optionsState.checkbox3;
}
});
this.childModal.nativeElement.present();
}
dismiss() {
this.childModal.nativeElement.dismiss();
}
child.component.html:
<div *ngFor="let option of options">
<input
type="checkbox"
[value]="option.value"
(change)="onOptionsSelectChanged($event)"
[checked]="option.checked" />
</div>
try passing the array object here option instead of $event. Have a look in this url..
https://stackblitz.com/edit/angular-ivy-wifdeg
<div class="form-group">
<div class="row" style="margin-top: 10px;">
<div class="weekDays-selector checkbox-inline"
ng-repeat="day in vm.days"
ng-if="vm.pen.feeding_frequency.name == 'Custom'">
<input type="checkbox" ng-click="function()"
id="custom_frequency{{$index}}"
name="custom_frequency"
class="weekday" / >
<label for="custom_frequency{{$index}}">{{day.name}}</label>
</div>
This is my HTML part for displaying checkboxes based on my object
Object looks like this:
vm.days = [{
name: i18nFilter('_custom_day_monday_'),
value: 1
}, {
name: i18nFilter('_custom_day_tuesday_'),
value: 2
}, {
name: i18nFilter('_custom_day_wednesday_'),
value: 3
}, {
name: i18nFilter('_custom_day_thursday_'),
value: 4
}, {
name: i18nFilter('_custom_day_friday_'),
value: 5
}, {
name: i18nFilter('_custom_day_saturday_'),
value: 7
}, {
name: i18nFilter('_custom_day_sunday_'),
value: 7
}]
So all I need is just to check if any of these checkboxes created from ng-repeat are checked. Any idea how to do that?
if you modify the checkbox like follow
<input type="checkbox" id="custom_frequency{{$index}}" ng-model="vm.selected[$index]" ng-init="vm.selected[$index]=false" name="custom_frequency" on class="weekday" / >
you will get a scope variable called selected inside your vm object. The Object by default will have 7 false values. If you checked one week day then the corresponding index of object updated with true value.....
then you can filter this array to get number of item checked using following code in ts file
var found = Object.keys($scope.vm.selected).filter(function(key) {
return $scope.vm.selected[key] === true;
});
console.log(found.length)
Get all the checkbox using document.querySelector and use array some to check if any them is checked
[...document.querySelectorAll('.weekday')].some(item => item.checked)
You could use the :checked selector:
document.querySelectorAll(".weekday:checked").length; // 0 if none is checked
I am using angular js select to display the name which is of type json array.using the below code i could display the name when a name is selected it stores a json object which moves to the next page but when i come back to the select page i would like to show the previous selected name but it shows an empty field;
Html:
<select class="formSelect"
ng-model="vm.product.farmer"
ng-change="vm.fillStarted()"
ng-options="farmer as farmer.name for farmer in vm.load.selectedFarmers">
<option value="" selected hidden />
</select>
Ctrl:
vm.load.selectedFarmers = getFarmers();
function getFarmers () {
farmers = [
{ name: 'Nidhin', id: 22 },
{ name: 'Sathish', id: 10 },
{ name: 'Kumar', id: 23 },
{ name: 'Rajkumar', id: 24 }
];
return farmers;
}
when moving from first page to the second page the select has an object like {name: 'Nidhin', id: 22 }
While coming back from the second page to the first page how can i show the selected name?
You can check the position of your selected data based on the position you can change the ng-model value
if (CommonService.isValid(vm.product.farmer)) {
vm.currentPosition = vm.load.selectedFarmers.findIndex(function (item) {
return item.id === vm.product.farmer.id;
});
} else {
vm.currentPosition = -1;
}
vm.product.farmer = vm.load.selectedFarmers[vm.currentPosition];
Try the above code and check whether it solves your problem.
Got a bit of a conundrum with a knockout observable array being shared across multiple view models.
Basically, I have a layout as follows
Transport
... textbox fields, etc
Selected Passengers:
<!-- ko foreach: allPassengers -->
<input type="checkbox" />
<!-- /ko -->
<button>Add Transport</button>
Holiday
... textbox fields, etc
Selected Passengers:
<!-- ko foreach: allPassengers -->
<input type="checkbox" />
<!-- /ko -->
<button>Add Holiday</button>
Now the selected passengers for each section is being generated from ONE observable array, idea being if a passenger is deleted/altered everything should fall into place automagically.
So something like this
function page() {
// in actuality this passengers array is a computed observable obtained from the passengers section which is not shown here.
this.allPassengers = ko.observableArray([
{
Id: 1,
name = ko.observable('name'),
checked = ko.observable(false)
},
{
.
.
]);
}
function transport() {
// pageVM is a page object
this.allPassengers = pageVM.allPassengers;
this.transportItems = ko.observableArray();
this.addTransport = function() {
this.transportItems.push({
.
.
selectedPassengers: [...]
.
.
});
};
}
function holiday() {
// pageVM is a page object
this.allPassengers = pageVM.allPassengers;
this.holidayItems = ko.observableArray();
this.addHoliday = function() {
this.holidayItems.push({
.
.
selectedPassengers: [...]
.
.
});
};
}
However, when add transport/holiday is clicked, I need a way to determine which checkboxs where checked so I can add the selected passengers.
I have tried to add a checked = ko.observable(false) property to the passenger item in parent.allPassengers, but the problem with this approach is if a checkbox is checked in the transport section it will also check it in the holiday section since it is using the same observable array.
Any ideas??
Edit:
example fiddle
The checked binding works with observable arrays too. So you can simply bind to $parent.selectedPassengers and specify the value attribute to be the passenger id, like this:
<input type="checkbox" data-bind="attr: { value: id },
checked: $parent.selectedPassengers" />
In each view model you need to have a selectedPassengers observable array used for binding to the checkbox. And the add function should look like this:
function transport(pageVM) {
....
this.selectedPassengers = ko.observableArray([]);
....
this.addTransport = function() {
this.selectedItems.push({
....
selectedPassengers: this.selectedPassengers()
});
};
};
Working Fiddle
You can use a ko.computed to return the selected passengers (and here's a fiddle):
var ViewModel = function () {
this.allPassengers = ko.observableArray([
{ name: 'John', selected: ko.observable(false) },
{ name: 'Jane', selected: ko.observable(false) },
{ name: 'Mark', selected: ko.observable(false) }
]);
this.selectedPassengers = ko.computed(function () {
return ko.utils.arrayFilter(this.allPassengers(), function (item) {
return item.selected();
});
}, this);
};