Have a each() with if statement not working - javascript

Problem
I only want the commands in the if logic to happen if the 3rd default button is visible, but it throws an error saying its parent has the css class of visibility: hidden. When you need to remove that state the 3rd default button becomes visible so I'm not sure why it isn't passing.
Desired Behaviour
I want it so for each state that is underlined to click on them to unselect them. Then the if statement is to take care of those who need to be actually removed, because they have info filled out for them, and so if the 3rd default button is visible, which is the remove button, then to execute the code inside the if statement which is to make sure the other default buttons are hidden and click the remove button.
Code
it('deletes all selected states', () => {
cy.get('span[class*="css-ddft8r-StateText"]').each($el => {
cy.wrap($el)
.filter(':has(span[class*="css-1qkbmzm-Underline css-1x6iasc4"])')
.click({ multiple: true });
if (cy.get('[data-cy=default-buttons]').eq(3).should('be.visible')) {
cy.get('[data-cy=default-buttons]')
.eq(0)
.should('be.hidden');
cy.get('[data-cy=default-buttons]')
.eq(2)
.should('be.visible');
cy.get('[data-cy=default-buttons]')
.eq(3)
.click();
}
});
});

Cypress commands return Chainer object - it is inner Cypress entity which can't be used with conditionals as object is always recognized as true within if statement.
So please give a chance for jquery:
if(Cypress.$('[data-cy=default-buttons]:contains("remove")').is(':visible')){
// do assertions
cy.get('[data-cy=default-buttons]:contains("remove")').click({force: true})
// as parent is hidden, we can ommit click visibility check by passing force: true
}
*= is checking that attribute contains part of passed string, so your selector could be simplified to:
[class*="StateText"]
Whole test seems as overengineered and not working properly with these each cycle and conditional inside. Maybe you dont even need to check buttons for each element and move assertions out of loop. Example repository would be helpful.

So the solution I ended up using was actually just using .each() instead of the if statement within it. We figured out we could utilize a ternary inside of a data-cy due to those css classes being unstable/unreliable and this took care of not having to write an if statement.
We did roughly this:
cy.get('[data-cy=example_data_cy]').each($el => {
//click on the state if it was selected to unselect it

Related

Item is moving on mouse click in bootstrap-duallistbox

I have taken the customized plugin which gives the feature for optgroup which is given over here Add scroll position return on select1. Add optgroup capability
Customized bootstrap-duallistbox (with optgroup feature)
I have created a sample example in plunker which shows a running example. The option group is working fine but the issue is that even through when I put move-on-select="false" still Item is moving on mouse click.
Can anyone please tell me why this is behaving like that
Working Plunker
<select ng-model="modal.selectedItems"
ng-options="item.name group by item.app for item in modal.allItems"
multiple
bs-duallistbox
move-on-select=false
></select>
Honestly, the easiest solution is just to change the implementation of selectGroup. I think it should be this:
function selectGroup(e) {
if(e.data.dlb.settings.moveOnSelect) {
move(e.data.dlb);
}
e.preventDefault();
}
You'll probably want to make a similar change to unselectGroup. The current implementation has strange behavior, where it moves things that aren't selected since it never unselects anything properly.
Edit:
The way that selections are made is faulty. I have no idea of the author's intent, but I suspect this implementation is closer to what a user would expect:
function selectGroup(e) {
if (e.target.tagName != 'OPTGROUP') return;
$(this).find('option').each(function (index, item) {
var $item = $(item);
if (!$item.data('filtered1')) {
if (!$item.prop('selected')) {
$item.prop('selected', true);
} else {
$item.removeAttr('selected');
}
}
});
if(e.data.dlb.settings.moveOnSelect) {
move(e.data.dlb);
}
e.preventDefault();
}
Again, make a similar change to unselectGroup. In the original code, the problem was that when you click on an individual option, the click would bubble up to the optgroup, hence the if guard. Also, the selection state should not be changed directly. That is already handled in the move function. It's much nicer to change the selected attribute, which the the move function later digests. In this way, it's also visually clear what is actually being selected. Thus, when you click an optgroup, it should toggle selected on each the item properties. You may want to modify how the removal of selected attribute is done.
Go with
http://www.virtuosoft.eu/code/bootstrap-duallistbox/
as #prakash Said in Commments.

Agularjs ng-class:remove class if other condition becomes true

The question might not be clear but I can't figure out a better question to elaborate. I am trying to highlight a table row using ng-class and using conditions. Below is my code:
<tr ng-class="{selectSuccess: selectedRows.indexOf(rowData.entity_id) > -1,
danger: rowData.total_received < rowData.total_sold,
info: rowData.total_received > rowData.total_sold}">
In my code as you can see there are three conditions and three classes. danger and info classes are added on page load as they become true but selectSuccess which becomes true when I select a row so I need to know if there is any possibility to add important to this selectSuccess. I have tried adding important via css but that did not work. Or I need to know if I can make the other condition to false when I click on a row.
Note: If you want I can add the whole code but only need to know if I can toggle the class and that is why provided only the main code.
You could add && selectedRows.indexOf(rowData.entity_id) == -1 to the danger and info conditions.

jQuery 'change' method (for HTML attribute modify) working only once

I have this pair of functions affecting two inputs, and one select. These are exclusive so when inputs are filled, select must be modified to have option 3 selected, and when any option except 3 is selected, both inputs must be empty:
$('#ar_filter').on('change', '#ar_fromDate, #ar_toDate', function() {
if ($('#ar_fromDate, #ar_toDate').val!=""){
$('.lastDays').attr('readonly','readonly').find('option[value=3]').attr('selected', true);
}
});
$('#ar_filter').on('change', '#lastDays', 'select', function() {
if ($('.lastDays').val()!=3){
$('#ar_fromDate, #ar_toDate').val("");
}
});
This works, but only the first time. When I write some value on the inputs, it resets correctly select to value 3, but when I change manually selected options, after it resets and leaves inputs empty, it does not reset anymore the select, even when writing on any of those inputs.
JSFIDDLE EXAMPLE (try making 2 select resets by filling the inputs: it will only make the first one)
Based on your JSFiddle, I believe your second implementation of .on() is incorrect. The third optional argument can be passed as data to the handler function as denoted in the reference documentation.
Try changing:
$('#ar_filter').on('change', '#lastDays', 'select', function() {
to this:
$('#ar_filter').on('change', '#lastDays', function() {
Based on your comment above, I believe your selector is wrong. #lastDays is the id of the <select> element, which is where you want the change event bound. The extra select is not needed.
Updated Fiddle
Note:
The updated fiddle includes the .val() fix described by #tymeJV in his answer.
EDIT:
In addition to the .on() selector fix described above, you'll need to break out the two selectors in your .val() statement. This is because only the first input will be validated each time the change event occurs. This comes directly from the jQuery documentation for .val():
Get the current value of the first element in the set of matched elements.
The second value will not be fetched or validated.
Change this:
$('#ar_fromDate, #ar_toDate').val() != ""
to this:
$('#ar_fromDate').val() != "" || $('#ar_toDate').val() != ""
This should fix the problem. I've included an updated fiddle below. I've left the original fiddle in tact to show the progression of steps in solving this problem for the benefit of future visitors.
Complete Fiddle

jQuery: toggling attribute within a toggleClass function

I'm trying to add an attribute to a searchfield only when it is visible, so I have the following code to a) hide the search form initially, b) toggle the visibility and c) add or remove the attribute "autofocus" to the form's input when the form is given the class "focus" (e.g being visible). The code for a) and b) works as it should, c) is my imagined take on how the addAttr() thing should be, but I don't really know Javascript so obviously it's not working. The question is: How do I make it work?
$("#searchwdgt").hide();
$(function() {
$('#show_search').click(function() {
$('#show_search').toggleClass('active');
$('#searchwdgt').toggleClass('focus').slideToggle(400);
if($('#searchwdgt.focus')) {
$('#searchwdgt input').addAttr('autofocus');
} else {
$('#searchwdgt input').removeAttr('autofocus');
}
return false;
});
});
The basic construct is simple. #show_search is an anchor that the user clicks to get the search form (#searchwdgt). To minimize the number of user clicks it would be nice if the attribute "autofocus" could be added to the input (has class "searchfield", is type "search", just for clarification) when the form becomes visible, but for UX purposes it can't be in place always (this messes with tab browsing since the form is hidden initially). So, any constructive pointers that can help solve the issue are most welcome. Thanks.
the function should be
.attr('autofocus','autofocus')
instead of
.addAttr('autofocus');
The reason it isn't working is that each attribute needs to have a value, even if it's null

Smarty / Dojo checkbox onCheck uncheck other checkbox

I am using Dojo labels and checkboxes in one of my app inside smarty file. I want to add a certain behavior to uncheck a checkbox, if any other checkbox is checked. I also check if that checkbox is originally checked, it will uncheck the same. (I do not want to use radio button)
Here is my code for one CheckBox:
<input id="form.cs"
data-dojo-type='dijit.form.CheckBox'
type="checkbox"
data-dojo-props="value:'true', type:'checkbox', name:'cs', style:'vertical-align: top'"
onChange="if(dijit.byId('form.cs"').checked)
dijit.byId('form.cs"').set('checked', false);
else
dijit.byId(' form.nl"').set('checked', false);"
/>
The problem with code is when i add curly braces, this is not rendered by smarty engine and throws error.
For example :
onChange="if(dijit.byId('form.cs"').checked) {
dijit.byId('form.cs"').set('checked', false); }
else {
dijit.byId(' form.nl"').set('checked', false);"}
The above code snippet will create a breakdown in the smarty.
I recommend writing your event handler in JavaScript. If you're going to write all your event handlers as attributes you're going to have a lot of problems like code validation, ... .
You could write a loop that actually loops over all checkboxes, setting the value to the opposite of the changed value (so if one checkbox becomes true, the other ones must become false).
To do this you could write a simple function like this:
var toggleCheckboxes = function(myNode, value) {
query("input[type=checkbox]").forEach(function(node) {
if (node !== myNode) {
registry.getEnclosingWidget(node).set("value", !value, false);
}
});
};
The dojo/query module allows you to get a list of all nodes matching the given selector. With the dijit/registry module you can retrieve the actual widget behind the DOM node and then you just set the value using:
registry.getEnclosingWidget(node).set("value", !value, false);
The third parameter (set to false) is actually very important. This parameter will prevent further event invocations. If you don't put that parameter there it will actually trigger another onChange, causing an infinite loop.
Now the only thing you need to do is bind an onChange event handler to each checkbox that calls this function, you can also to that with the dojo/query and dijit/registry module, for example:
query("input[type=checkbox]").forEach(function(node) {
registry.getEnclosingWidget(node).on("change", function(value) {
toggleCheckboxes(node, value);
});
});
A complete example can be found on JSFiddle.
But I still recommend using a radiobutton. I think you can actually say this is a bad UI design, a checkbox and a radiobutton have different goals, use them for what they're meant to.

Categories

Resources