How to apply conditional style to unchecked checkbox - vuejs2

We are running Vue 2.x with vuetify and trying to figure out how to set some conditional, custom styling for unchecked checkboxes on a table for viewing/creating/updating user permissions. The roles are defined something like this:
Role A View and Role B Edit are being added. The gray boxes are permissions that have not changed. This is working as desired.
The issue is that I can't figure out how to assign color/style/class to the unchecked boxes so that we can mark revoked permissions with an empty red checkbox so that if manage were unchecked the last row would look like:
We are using but have also tried css overrides on . We have tried using css classes, :color, :fill, :style but nothing is working to get the box outline red.
This is what we currently have and is working for the checked boxes:
<template v-slot:item.view.id="{ item }">
<v-simple-checkbox
v-if="item.view.id"
v-model="item.view.active"
:disabled="!edit"
:color="getCheckboxColorForRole(item.view)"
#click="updateRolesRow(item, 'view')"
>
</v-simple-checkbox>
</template>
where getCheckboxColorForRole compares the initial vs current state and returns the appropriate color to display.
What am I missing here?

can you please provide some code? basically this is style binding

per #Anatoly I looked into the scoped css again and was able to get it to work. But then made it a global css rule so that I can use the scss var for the color and apply this on other pages. This is what I ended up with:
<template v-slot:item.view.id="{ item }">
<v-checkbox
v-if="item.view.id"
v-model="item.view.active"
:disabled="!edit"
:color="getCheckboxColorForRole(item.view)"
:class="[{'group-role-checkbox-original-checked': item.view.originalActive}]"
:ripple="false"
#click="updateRolesRow(item, 'view')"
>
</v-checkbox>
Had to switch it to <v-checkbox> since the simple checkbox wasn't allowing me to add classes. Then I checked/unchecked a few times and noticed that the only change is that the gray--text class is removed when unchecked. So then I added this css rule:
.group-role-checkbox-original-checked i:not(.gray--text) {
color: $anchor-color !important;
}
If anyone knows of a better way to do this I would love to know.

Related

Prevent list display filter from resetting v-list selection

Version info: Vuetify 2.6.3, Vue 2.6.14, Nuxt 2.15.8
I'm making a custom component that is supposed to be somewhat similar to v-autocomplete, except that it's rendered as bottom sheet. If user enters a display filter into v-text-field, the option list (v-list) is supposed to display only those options that match the filter.
In overall it works fine except one use case: let say the list has 5 items (aa, bb, cc, dd, ee) and user selected bb and cc from the list. Now, v-list-item-group's model selectedItems contains the 2 selected items bb and cc, perfect! However, when user enters b into display filter, the already selected item cc will be auto deleted from selectedItems. I can't tell if selectedItems change is caused by filter or by user selection. Is there a way to maintain the selection in model?
I'm considering a hack - if an item is selected, keep it in filteredChoices even if it does not match the filter. This behaviour is bearable but UX wise not as intuitive as the filter of v-autocomplete.
The simplified structure looks like the below:
<template>
<v-bottom-sheet scrollable>
<v-card>
<v-card-text>
<v-list>
<v-list-item-group
v-model="selectedItems"
:mandatory="!optional"
:multiple="multiple"
>
<v-list-item
v-for="item in filteredChoices"
:key="item.value"
:value="item"
>
</v-list-item>
</v-list-item-group>
</v-list>
</v-card-text>
<v-text-field
v-model="filterInput"
placeholder="filter choices..."
hide-details
></v-text-field>
</v-card>
</v-bottom-sheet>
</template>
<script>
...
filteredChoices() {
if (this.filterInput == null) {
return this.allItems
}
return this.allItems.filter((item) => {
return item.label
.toLocaleLowerCase()
.includes(String(this.filterInput).toLocaleLowerCase())
})
},
...
</script>
How I reach the solution:
I was quite new to front-end stuff. Previously, when I was learning how to implement v-model support for custom component, all web resources I came across say the same thing - bind inner component's value props to custom component's value props. However I just discovered that this is merely one of the ways rather than a must. With that new learning, more possibilities pop up in my mind and one of them lead me to below solution.
Solution:
Decouple the custom component value from bottomsheet's list
Bind the model of inner v-autocomplete to an array data, say internalValue. (this inner component is not included in question's template for simplification)
Bind the model of inner v-list-item-group (in bottomsheet) to a separate data, say bottomSheetSelections.
Update the custom component value based on user actions in bottomsheet
Add a watcher to bottomSheetSelections array:
if the array grows, it means the user has selected more item. We should push the additional item to internalValue.
if the array shrinks:
if the missing item is still there in filteredChoices, the removal is triggered by user de-selection. We should remove this item from internalValue.
else, we consider the removal is triggered by list filter. No action is needed.
Restore user selection in bottomsheet on clearing filter
Add a watcher for filteredChoices. Whenever the array grows, if the additional choice exist in internalValue, we should push it to bottomSheetSelections.
Summary
Strictly speaking, this doesn't solve the ask of question's title - the list selection in bottomsheet (bound to v-list-item-group) is still getting reset. However, at least we're able to restore it in bottomsheet on clearing filter.
More importantly, this solution achieved the objective mentioned in question details - retain the user selection value. We kept it in a separate data internalValue.
I haven't test this solution with long list of data. My guts feeling is that there could be more efficient solution. Please share it if you have a better solution.

Ionic 4 - Select not showing selected value set in controller

Problem:
I have an ion-select and in the controller when the user does something, I populate the ion-select with 1 value and make that value the selected value. The ion-select does not show that the value has been selected, but the [(ngModel)] has the correct value. When I open the ion-select it shows the value in the list and it is selected, when selecting the value in the list again it goes over the ion-select label.
How can I populate the ion-select with a value and make the populated value the selected value so that it shows on the ion-select as a selected item?
Screenshots:
The Make has value of CHEVROLET but it does not show as selected by ion-select:
When tapping on ion-select, it shows the CHEVROLET as selected and CHEVROLET goes over the Make label:
HTML:
<ion-item>
<ion-label position="floating">
<span class="required">* </span>Make
</ion-label>
<ion-select [interfaceOptions]="global.compactAlertOptions" id="make" [(ngModel)]="global.valuation.vehicle.make" name="make" #makeRef="ngModel" required>
<ion-select-option *ngFor="let make of makes">{{make}}</ion-select-option>
</ion-select>
</ion-item>
<ion-label *ngIf="makeRef.touched && makeRef.invalid && makeRef.errors.required" class="error">Make is required</ion-label>
Controller:
Modal Controller (the Make gets set in a popup modal):
this.global.valuation.vehicle.make = this.vehicleDetails.VehicleMake;
Populate the ion-select options in parent controller:
this.makes = [this.global.valuation.vehicle.make];
This generally happens when the value in ngModel is set before <ion-select-option> options are loaded on the DOM.
You will have to explicitly delay setting the value to ngModel until the <ion-select> and options are loaded on the DOM.
You can achieve it by adding a setTimeout in your component file and assign the ngModel value in the callback of setTimeout.
It seems to me that this has to do with some custom css that you are using on the template. Since when you use floating for a select is exactly the same as when you use stacked, Since the select is going to expand on the ion-item anyway. This floating works best with ion-input.
In your case, if the option was not selected, the select should be empty and the label above it. but it is on the item furthermore on the baseline of the select. When you select the option it will show in the baseline on the select left aligned.
like this:
If you remove the floating you will see what I mean.
it should show like this:
It will be easier to understand the issue if you just provide the CSS bits that are messing with the alignment of the elements.
My guess is that you have some styles that only reduce the ion-item and don't deal with alignment and positioning of the inner elements.

Adding ripple to mat-card without the card expanding on click/touch

Im trying to add a ripple effect to a card using angular material. The ripple effect works the way it supposed except that it expands the hight of the card when the effect is active.
How can I stop the card from expanding?
<mat-card mat-ripple>
<mat-card-content>This is content</mat-card-content>
</mat-card>
Stackblitz that demonstrates the behaviour
Add a class (i.e. last-child) to the last child of your mat-card (in your case mat-card-content) and define the following style:
.mat-card .last-child {
margin-bottom: 0;
}
The problem is that matRipple adds an zero-height element to the mat-card while Angular Material only removes the margin-bottom from the last child.
If you add the footer element (with or without content) you won't need additional CSS and this will lock the height when activating the ripple effect.
<mat-card mat-ripple>
<mat-card-content>This is content</mat-card-content>
<mat-card-footer></mat-card-footer>
</mat-card>
should be as easy as adding matRipple to the mat-card
<mat-card class="action-card" matRipple>
<mat-card-title>
{{content}}
</mat-card-title>
<mat-card-content>
desc
</mat-card-content>
</mat-card>
make sure you inject the MatRippleModule into your module.ts though, that threw me off for a while
Use a div -Tag inside of mat-card -Tag. This Fix my issue.

selenium can't test text color

Hello I am trying to check if the color of an input is red.(Selenium IDE 1.9 Firefox Plugin)
If i select it with
<td>verifyAttribute</td>
<td>id=focus_me</td>
<td>*color=red*</td>
the "Find" button works, but there is no attribute selected to check.
if i change it to
<td>verifyAttribute</td>
<td>id=focus_me#color</td>
<td>*color=red*</td>
the element is not found, so how do i use it ?
Assuming we are talking about color as a style, your HTML probably looks something like:
<span id="custom1" style="color:red;">Custom Attribute 1</span>
As you can see 'color' is not an attribute. It is part of the value of the 'style' attribute.
So what you want do is verify that the 'style' attribute contains the 'color:red':
<td>verifyAttribute</td>
<td>id=focus_me#style</td>
<td>*color:*red*</td>
Note that the asterisk (*) are wildcards. They have been added in case there is another style property before or after the one of interest. One was also added between the color and red since sometimes people puts spaces and sometimes not.

dijit.form.Select won't set value programmatically

I have a dynamic dojo form in which I have a dijit.form.Select whose selected value I have tried to set dynamically through various ways. I get the select widget to load and show the data, but it always ignores my every attempt. I am using dojo 1.7.
var bcntryval = <?= $this->billingContact->countryId;?>;
var countryStore;
function onBillingShow() {
if (countryStore) countryStore.close();
countryStore = new dojo.data.ItemFileReadStore({url: 'CartUtilities.php?action=getcountries'});
dijit.byId("bcntry").setStore(countryStore, bcntryval); // does not set value! but does set the store
dijit.byId("bcntry").attr('value', String(bcntryval)); // doesn't set the value either
dijit.byId("bcntry").set('value', bcntryval)); // nor does this!
}
My markup for the bcntry widget is as follows:
<td><input data-dojo-type="dijit.form.Select" style="width: 10em;" data-dojo-props="sortByLabel:false, maxHeight:'-1'" data-dojo-id="bcntry" id="bcntry" name="bcntry" />
I've invested a fair amount of time on learning dojo. When it works its nice, but the docs leave a lot to be desired!
I am also seeing a similar problem with the dijit.form.FilteringSelect. That also ignores setting the value via javaScript.
I've also tried completely programmatic versions of this code. I have come to the conclusion that setting the value just doesn't work when you're selecting from a store.
This DID work, but its not dynamic.
<div name="scntry" data-dojo-type="dijit.form.Select" data-dojo-props="maxHeight:'-1',sortByLabel:false" value="<?= $this->shippingContact->countryId;?>" >
<?php foreach($this->countryList as $c):?>
<span value="<?= $c->id;?>"><?= $c->name;?></span>
<?php endforeach;?>
</div>
The reason most likely is, that youre trying to set the value of the 'searchAttr'. Instead you would want to set value to the 'identifier'.
Answer is here, check the timeout function on bottom shelf: http://jsfiddle.net/TTkQV/4/
The trick is to set the value as you would set option.value (not option.innerHTML).
normalSelect.set("value", "CA");
filteringSelect.set("value", "AK");
Take a look here, I believe this does what you want in the Dojo way:
Setting the value (selected option) of a dijit.form.Select widget
If not, you can always just use the actual dom selection object and use straight Javascript:
How do I programatically set the value of a select box element using javascript?