Dynamic selection of 2nd item from a static dropdown using cypress - javascript

to automate CRUD functionality I need to select the 2nd item from a static drop down and the html is like
<select name="segment[segment_contact_id]" id="segment_segment_contact_id">
<option value="73082">Rita Basu</option>
<option value="73349">researcher user</option>
</select>
So by using cypress I am using the hardcoded value and my code is like
const segmentUser2 = 'researcher user'
const userValue2 = 73349
cy.get('select#segment_segment_contact_id')
.select(segmentUser2)
.should('have.value', userValue2)
I need suggestion because I don't like to use the hardcoded value instead I would like to use always the 2nd item from the drop down dynamically.

You could do something like this
Cypress.Commands.add(
'selectNth',
{ prevSubject: 'element' },
(subject, pos) => {
cy.wrap(subject)
.children('option')
.eq(pos)
.then(e => {
cy.wrap(subject).select(e.val())
})
}
)
Usage
cy.get('[name=assignedTo]').selectNth(2)

Here is #ItsNotAndy's way without the custom command.
cy.get('select#segment_segment_contact_id')
.children('option').eq(1)
.then($option => {
cy.wrap($option).parent().select($option.val())
})
As a function
function selectNth(selector, pos) {
cy.get(selector)
.children('option').eq(pos)
.then($option => {
cy.wrap($option).parent().select($option.val())
})
}
selectNth('select#segment_segment_contact_id', 1)
Verifying from text displayed
cy.get('select#segment_segment_contact_id')
.find(':selected')
.contains('researcher user')
Verifying by selectedIndex
cy.get('select#segment_segment_contact_id')
.its('0.selectedIndex')
.should('eq', 1)

You can use this as well. Here first we are getting value of the second item in the list using the eq() command. Then once we have got the value, we are just simply passing that to select().
cy.get('select#segment_segment_contact_id option').eq(1).invoke('val')
.then((val) => {
cy.get('select#segment_segment_contact_id').select(val)
})
And if you want to just validate the value or text you can do:
cy.get('select#segment_segment_contact_id option')
.eq(1).should('have.value', 73349)
cy.get('select#segment_segment_contact_id option')
.eq(1).should('have.text', 'researcher user')

Related

Programmatically select next/previous option in select 2, with sorter applied

I have a select2 that uses the sorter option to sort options alphabetically, and a button that should select the next option after the currently selected option. All of this works as desired except the button does not select the next (alphabetical) choice in the select2, which is what I would like; instead it selects the next <option> element in the underlying <select> that drives the select2. These <option>'s are not sorted alphabetically. Obviously I could manipulate the DOM to sort them alphabetically, but that sort of defeats the purpose of leveraging the sorter option. Is there any way to identify the option that comes after the currently selected one, in the sorted list?
HTML
<select id="employeeSelect">
<option value="abc">Diane Smith</option>
<option value="xyz">Tim Carter</option>
<option value="dmv">Keith Appleton</option>
<option value="r2d2">Carla Peters</option>
</select>
<button id="nextEmployee">Next</button>
JS
$('#employeeSelect').select2({
placeholder: '-- select an employee --',
sorter: data => data.sort((a, b) => a.text.localeCompare(b.text)),
})
$('#nextEmployee').on('click', function(){
$("#employeeSelect > option:selected")
.prop("selected", false)
.next()
.prop("selected", true);
$('#employeeSelect').trigger('change');
})
I didn't find any documentation on this, but from inspecting the select2 element's data properties, it appears that the sorted list is not held in the select2's internal data in any way (I think it is generated on the fly when the dropdown is clicked); therefore, this is probably not possible other than by sorting the <option> tags.
So my current solution looks like this:
$('#nextEmployee').on('click', function(){
const isBefore = function (a, b)
{
return $(a).text().toUpperCase().localeCompare($(b).text().toUpperCase()) < 0
}
const selectedOption = $("#employeeSelect > option:selected")
const nextOption = $('#employeeSelect').find('option').toArray()
.reduce(function (acc, thisOption)
{
if (isBefore(selectedOption, thisOption)
&& (!acc || isBefore(thisOption, acc)))
{
return thisOption
} else
{
return acc
}
}, null)
if (nextOption)
{
selectedOption.prop("selected", false)
$(nextOption).prop("selected", true);
$('#employeeSelect').trigger('change');
}
}

How to disable 2 options in multiselect dropdown and grayout that option

Hi i have used Angular8 and bootstrap 4. I have used bootstrap multi-select dropdown, i need to get the PL Marketing and CL Marketing as disabled and grayed out. i have tried in all ways but not able to disable and gray out that option.
TS:
ngOnInit() {
this.initEoForm();
setTimeout(() => {
$("#multiselectUser")
.multiselect({
buttonWidth: "400px"
})
.on("change", e => {
let selectedFilename = $("#multiselectUser").val();
selectedFilename = selectedFilename.filter(function(
item,
index,
inputArray
) {
return inputArray.indexOf(item) == index;
});
let selectedName = selectedFilename
? selectedFilename.toString()
: "";
this.getSelectedRoles(selectedName);
});
}, 100);
setTimeout(() => {
$('#assignedRoles option[value="124"]').prop("disabled", true);
$('#assignedRoles option[value="123"]').prop("disabled", true);
});
}
HTML:
<select name="user" id="multiselectUser" multiple="multiple" (change)="selecteduser($event)" [(ngModel)]="selectedUsers" >
<option *ngFor="let field of user" [value]="field.id" >
{{field.label}}</option>
</select>
DEMO
I would recommend instead of editing the UI with jQuery to modify the user[] that is visualized in the *ngFor and add a field called disabled. Then in your template you can do the following
<select name="user" id="multiselectUser" multiple="multiple" (change)="selecteduser($event)" [(ngModel)]="selectedUsers" >
<option *ngFor="let field of user" [disabled]="field.disabled" [value]="field.id" >
{{field.label}}</option>
</select>
And your typescript should be changed like so
// From
setTimeout(() => {
$('#assignedRoles option[value="124"]').prop("disabled", true);
$('#assignedRoles option[value="123"]').prop("disabled", true);
});
// To
setTimeout(() => {
this.user = this.user.map(x => {
return {
...x,
disabled: [123, 124].includes(x.id)
};
});
Here is also a demo on stackBlitz (im using your example as base)
// Answer for the comments
You can add a custom class like so and apply whatever styles you need
<option *ngFor="let field of user" [ngClass]="{'disabled-option': field.disabled}" [disabled]="field.disabled" [value]="field.id" >
{{field.label}}</option>
And in order to enable the options, you just have to iterate over the fields again and change the disabled state
** Important
Because you are using third party linrary for the select you must add you styles in the root .css files for them to take effect.
Also because of the library you are using you should re-initialized the select component in order for it to re-render the options with their new state.
Look again at the stackblitz i had provided

Retrieve selected values from multi-select box in vue js

I am having a hard time retrieving values from a multi-select box in Vue. After the user has selected any number of values, I want to retrieve the values and submit to a data source. No luck so far. Here's an excerpt of my code below.
<div id="app">
<select multiple v-bind:data-id="program.id" :disabled="!program.editable" v-model="program.dropDowns">
<option>Microsoft</option>
<option>IBM</option>
<option>Google</option>
<option>Apple</option>
</select>
</div>
getPrograms: function() {
axios.get("https://my-json-server.typicode.com/isogunro/jsondb/Programs").then((response) => {
this.programs = response.data.map(row => ({
...row,
dateFormatted: toDDMMYY(row.Date),
editable: false,
dropDowns: ["Apple","Google"]
}));
console.log(this.programs)
})
.catch(function(error) {
console.log(error);
});
}
Any help would be much appreciated. Here's the actual pen
The problem is that you are not passing anything to the saveItem function, so no program was being sent.
You just have to replace saveItem for saveItem(program) and that should do the trick.
Just you have assigned drop down data wrongly , Need to change like below:
Little change in template:
<button v-else #click="saveItem(program)">save</button>
and saveItem() method like below:
saveItem (program) {
program.isReadOnly = true
program.editable = false
console.log(program)
alert(program.dropDowns)
}

event.target.value - how to get the key value?

There was a need to add a drop-down list with a choice of accounts. The chosen value is processed through "event.target.value". This handler takes the value visible to the user, but I only need the 'key' value of the selected record where the stored "account.Id". I've tried get access to key, but it doesn't seem to work.
First experience with JS, so apologize in advance if the question is incorrect or elementary.
Page:
<select class="slds-select" name = "accountSelect" onchange={changeHandler2} >
<template for:each={allAccounts.data} for:item="account">
<option key={account.Id} value={account.Id}>{account.Name}</option>
</template>
</select>
Handler:
changeHandler(event) {
if (field === 'accountSelect') {
this.accountId = event.target.options[event.target.selectedIndex].getAttribute('key');
}
}
Did you tried to use the data to get it :
changeHandler(event) {
if (field === 'accountSelect') {
this.accountId = allAccounts.data.find(item => item.Id === event.target.value);
}
}

Get last clicked element in multiple select Angular

Im trying to get the last clicked option in a multiple select, no matters if the option is selected or unselected.
The problem is that the select is not via template, is mounted dinamically via TS.
I've tried adding vanilla JS event listeners at the creation of the options but doesn't works. Actually i can get all the selected elements, but i lost the unselected option and i can't get exactly the new selected one.
My HTML
<tr *ngFor="let communityLine of communityLines">
<td>{{communityLine.name}}</td>
<td>{{communityLine.instrument.name}}</td>
<td>{{communityLine.param.name}}</td>
<td>{{communityLine.contextSource.name}}</td>
<td>{{communityLine.sampleType.name}}</td>
<td>{{communityLine.value}}</td>
<td>
<select multiple [id] ="communityLine.apiKey" (change)="eventGetChange(communityLine, $event)" [(ngModel)]="nodeKey">
</select>
</td>
</tr>
My TS function
private eventGetChange(commLineKey, event) {
console.log(this.nodeKey);
console.log(commLineKey);
console.log(event.target.value)
My TS method to mount the select, is a bit complicated because i need to show all nodes (stored in this.allNodes var) but select the nodes that are in other array (nodesInRelation var).
private mountSelect(nodesInRelation: Node[], lineApiKey: String): void {
let select = <HTMLSelectElement>document.getElementById(lineApiKey);
let copy = this.allNodes;
for (let node of nodesInRelation) {
copy.forEach((item, index) => {
if (item.name === node.name) copy.splice(index, 1);
});
}
for (let node of nodesInRelation) {
let newoption = new Option(node.name, node.apiKey, null, true);
select.add(newoption);
}
for (let node of copy) {
let newoption = new Option(node.name, node.apiKey, null, false);
select.add(newoption);
}
M.updateTextFields();
M.AutoInit();
}
In eventGetChange function first console.log i get all the current selected values, in the second i get the key and is okey and in the third i get only the first selected element in the box.
I just want the last clicked, selected or unselected.
Thanks you.
You seem to be ditching Angular and opting for direct DOM manipulation for no apparent reason. Angular is perfectly capable of populating options list programmatically. It could look something like
<td>
<select multiple [id] ="communityLine.apiKey" [(ngModel)]="nodeKey">
<option *ngFor="let option of optionList; let i = index"
[value]="option" (click)="eventGetChange(option)">{{ option }}
</option>
</select>
</td>
optionList: any[];
private mountSelect(nodesInRelation: Node[], lineApiKey: String): void {
// populate optionList here
}
private eventGetChange(commLineKey) {
// the clicked option is available here
}
If this.nodeKey as you say stores an array with all the current selected values you can simply do this:
this.nodeKey[this.nodeKey.length - 1]
It will give you the las value in the nodeKey array

Categories