Selecting "Select All" also emits onDeSelectAll event in angular2-multiselect-dropdown - javascript

I am using angular2-multiselect-dropdown. Whenever I click "SelectAll" in the dropdown, it doesnt select all because it is also emiting deSelectAll event and so it also calls onDeSelectAll() function. And so its not implementing the default functionality of selecting all the items in the dropdown. Select All checkbox is also not checked. Please tell me how can I make this work, as I have a deadline soon.
ts:
ngOnInit() {
this.dropdownList = [
{ id: 1, itemName: "Pacemaker1", value: "Pacemaker1" },
{ id: 2, itemName: "Pacemaker2", value: "Pacemaker2" },
{ id: 4, itemName: "Pacemaker2", value: "Pacemaker2" },
];
this.selectedItems = [];
this.dropdownSettings = {
singleSelection: false,
text: "Select devices",
selectAllText: "Select All",
unSelectAllText: "UnSelect All",
enableSearchFilter: true,
badgeShowLimit: 3,
};
this.getStudies();
}
onItemSelect(item: any) {
this.selectedItems.push(item);
}
OnItemDeSelect(item: any) {
this.selectedItems = this.selectedItems.filter((el) => el.id !== item.id);
}
onSelectAll(items: any) {
console.log("select", items);
this.selectedItems = [];
this.selectedItems.push(items);
}
onDeSelectAll(items: any) {
console.log("deselect", items);
this.selectedItems = [];
}
html:
<div class="form-group">
<label class="form-col-form-label">
Associated Devices
</label>
<angular2-multiselect
class="form-control"
[data]="dropdownList"
[settings]="dropdownSettings"
(onSelect)="onItemSelect($event)"
(onDeSelect)="OnItemDeSelect($event)"
(onSelectAll)="onSelectAll($event)"
(onDeSelectAll)="onDeSelectAll($event)"
formControlName="associatedDevices">
</angular2-multiselect>
</div>
Please check the replicated functionality here
https://stackblitz.com/edit/angular-ivy-esame2?file=src%2Fapp%2Fapp.component.html

I solved this issue by installing #4.6.3 version and its working fine. Apparently its an open issue in the package itself.

I faced the same issue you can solve it by CSS like this
label[for=selectAll] {
pointer-events:none;
}

Related

Advanced Javascript - List Json data in HTML using loop and triggering an element change event, using Revealing Pattern

I wrote a working example of a real problem that I'm trying to solve
I created an object simulating the json return I have from the database
I need:
list contracts and contract batchs
when entering the function, mark the last batch of the contract as selected in the drop-down list
when entering the function, display the invoices for the last batch only of the contract selected in the ul-invoices element.
load and display the respective invoices when changing the batch
Problems:
I cannot list invoices for the last batch of the selected contract
Although there is a function for onchange="getInvoices", I always getInvoices is not defined
Note:
When entering the page, I already have the information of the selected contract, in the case of the example, I left the contract with ID 1.
In the example I am using the in-attendance class to define the selected contract
I am using Revealing Pattern and I want to keep this pattern
<html>
<label id="contracts"></label>
<ul id="ul-invoices"></ul>
<script>
let lblContract = document.querySelector('#contracts');
let UlInvoices = document.querySelector('#ul-invoices');
let contractInAttendance = 1;
const objectContract = {
id: 1,
nome: 'wagner',
contracts: [{
id: 1,
contract: '123456',
batches: [ {
id: 1,
contract_id: 1,
batch: '1',
invoices: [ {
value: 10,
batch_id: 1,
}]
},
{
id: 2,
contract_id: 1,
batch: '2',
invoices: [{
value: 10,
batch_id: 2,
}]
}]
},
{
id: 2,
contract: '246789',
batches: [ {
id: 3,
contract_id: 2,
batch: '1',
invoices: [ {
value: 20,
batch_id: 3,
}]
}]
}]
}
const revelling = (function() {
function privateInit() {
const contracts = objectContract.contracts;
let contractFilteredById = contracts.filter(contract => contract.id === contractInAttendance);
for (const contract of contracts) {
const selectedContract = contract.id === contractFilteredById[0].id ? 'in-attendance' : '';
//let batchFilteredById = contract.batches.filter(batch => batch.id === batchInAttendance);
let htmlForBatchsOptions = contract.batches.map(batch => `<option value=${batch.id}>${batch.batch}</option>`).join('');
lblContract.innerHTML +=
`<div class="contract-${selectedContract}" style="display: flex;">
<div id="contract-${contract.contract}" data-contract="${contract.id}" class="loren">
<span>${contract.contract}</span>
</div>
<div class="ipsulum" style="margin-left: 5px;">
<select class="sel-batch" onchange="getInvoices(this)">
${htmlForBatchsOptions}
</select>
</div>
</div>`;
const batchOption = document.querySelector('select.sel-batch');
batchOption.value = 2;
/!* create method for load invoices */
}
}
/!* Method fix for load invoices onchange sel-batch */
function getInvoices(selectObject) {
console.log('populate invoices element #ul-invoices');
}
return {
init: privateInit()
}
})();
revelling.init;
</script>
</html>
The IIFE function in this pattern makes that method getInvoices private, so you can't add a handler this way, because it is trying to find a global method that doesn't exist.
You need to assign the event handler this way:
lblContract.innerHTML +=
`<div class="contract-${selectedContract}" style="display: flex;">
<div id="contract-${contract.contract}" data-contract="${contract.id}" class="loren">
<span>${contract.contract}</span>
</div>
<div class="ipsulum" style="margin-left: 5px;">
<select class="sel-batch">
${htmlForBatchsOptions}
</select>
</div>
</div>`;
const batchOption = lblContract.querySelector('select.sel-batch');
// The event listener holds a reference to the inner function
batchOption.addEventListener("change", getInvoices);

Vue allow only one element in array be true

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/

Check all the checkboxes on basis of Id angular 4

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;
}

I'm trying to implement VeeValidate to check if at least one checkbox is checked

I found a jsfiddle example that I forked and then edited. I don't understand what's going on or how to fix it. In my example I'm using checkboxes with values but when I click a checkbox the value is changed to true or false depending on if the checkbox is clicked.
const Checkboxes = {
template: '#checkboxTmpl',
data() {
return {
text: '',
options: [
{
name: 'Web',
slug: 'web'
},
{
name: 'iOS',
slug: 'ios'
},
{
name: 'Android',
slug: 'android'
}
]
};
},
created() {
this.$validator.extend('oneChecked', {
getMessage: field => 'At least one ' + field + ' needs to be checked.',
validate: (value, [testProp]) => {
const options = this.options;
// console.log('questions', value, testProp, options.some((option) => option[testProp]));
return value || options.some((option) => option[testProp]);
}
});
},
methods: {
validateBeforeSubmit(e) {
this.$validator.validateAll(); // why is oneChecked not validated here? --> manually trigger validate below
this.options.forEach((option) => {
this.$validator.validate('platforms', option.slug, ['checked'])
});
console.log('validator', this.errors);
if (!this.errors.any()) {
alert('succesfully submitted!');
}
}
}
};
Vue.use(VeeValidate);
const app = new Vue({
el: '#app',
render: (h) => h(Checkboxes)
})
<script src="https://cdn.jsdelivr.net/vee-validate/2.0.0-beta.18/vee-validate.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.8/vue.js"></script>
<div id="app">
</div>
<script id="checkboxTmpl" type="text/template">
<form #submit.prevent="validateBeforeSubmit">
<label v-for="(option, index) in options">
<input type="checkbox"
v-model="option.slug"
name="platform"
v-validate.initial="option.slug"
data-vv-rules="oneChecked:checked"
data-vv-as="platform"/> {{option.name}}
</label>
<p v-show="errors.has('platform')">{{ errors.first('platform') }}</p>
<pre>{{options}}</pre>
<button type="submit">Submit</button>
</form>
</script>
I don't understand why all of the checkboxes are checked and unchecking one of them returns a validation error even though two are still checked. I like that errors are shown before the form is submitted but unchecking all and then submitting doesn't trigger the validation error.
I'm using VeeValidate because that is what the example uses but any other solution would be fine. I don't want to use jQuery in my vue.js application.
I would really like to understand what is going on.
There was two main problems going on :
Using v-model on the wrong key. In fact, each time the checkbox was checked or unchecked, it will emit an input event that will modify the original slug of the option (in your data). Instead, you need to add a checked field in your option. Then in your template add the :checked attribute and modify your v-model to be :option.checked.
As the docs of VeeValidate say, you can just use the required rule to make sure a checkbox has to be checked to submit your form. Here is the link towards the docs. Therefore, you don't need your created block.
Additionally, the validateAll function returns a promise containing the result of the validation. So no need to use this.errors.any() too.
Also, I upgraded the VeeValidate library to the latest as you used a beta.
Here is the working code :
const Checkboxes = {
template: '#checkboxTmpl',
data() {
return {
text: '',
options: [{
name: 'Web',
slug: 'web',
checked: false
},
{
name: 'iOS',
slug: 'ios',
checked: true
},
{
name: 'Android',
slug: 'android',
checked: true
}
]
};
},
methods: {
validateBeforeSubmit(e) {
this.$validator.validateAll().then(value => {
if (value) {
alert('successfully submitted')
}
})
}
}
};
Vue.use(VeeValidate);
const app = new Vue({
el: '#app',
render: (h) => h(Checkboxes)
})
<div id="app"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.8/vue.js"></script>
<script src="https://unpkg.com/vee-validate#latest"></script>
<script id="checkboxTmpl" type="text/template">
<form #submit.prevent="validateBeforeSubmit">
<label v-for="(option, index) in options">
<input type="checkbox"
:checked="option.checked"
v-model="option.checked"
name="platform"
v-validate="'required'"/> {{option.name}}
</label>
<p v-show="errors.has('platform')">{{ errors.first('platform') }}</p>
<pre>{{options}}</pre>
<button type="submit">Submit</button>
</form>
</script>
Hope that helps!

Angular 5 Select Option Frozen after Updating Array

I have a select dropdown:
<select class="form-control" id="teamSelect" [disabled]="!isSubmitButtonDisabled()" [(ngModel)]="selectedTeam" (ngModelChange)="onTeamChange($event)" style="width: 50%;">
<option *ngFor="let team of teams" [ngValue]="team">{{ team.text }}</option>
</select>
I populate it in ngOnit like this:
ngOnInit() {
this._microService.getTeams()
.subscribe(team => {
this.teams = team.map(m => { return { text: m.name, value: m.name } as Select; });
this.teams.unshift( { text: '', value: ''} as Select)
}
);
}
No problems!
Later I have button click that should add a new item to the dropdown...
onCreateTeam(team: string = ''): void {
if(team != '') {
let t = { text: team, value: team } as Select;
this.teams.push(t);
this.selectedTeam = t;
}
}
The dropdown gets populated but then I can't select anything. Is there a way to update the array in let team of teams from my component so the DOM gets the new option, and still allows a selection?
No errors are thrown in the Console.

Categories

Resources