ngClass one conditional and other from variable - css

I have the following data structure:
this.filters = [
{
key: 'filter1',
active: true,
class: 'filter1Class'
},
{
key: 'filter2',
active: false,
class: 'filter2Class'
},
{
key: 'filter3',
active: true,
class: 'filter3Class'
}
];
And with this I want to create some icons in my html, every icon will have each own css class and it can be enabled or not depending on the active flag in the model.
My classes are quite simples, every filterNClass is just a color and the one I applied to set it enabled or nor is an opacity value:
.disabled {
opacity: 0.2;
}
.filter1Class {
color: #1993a0;
}
.filter2Class {
color: #720053;
}
.filter3Class {
color: #000055;
}
this is my html:
<div *ngFor="let filter of filters">
<mat-icon [ngClass]="filter.class"
[ngClass]="{disabled: !filter.active}">alarm_on
</mat-icon>
</div>
in this way, the second ngClass is not working, it does if I remove the first one, but I'm not able to manage both at the same time.
How can it be done?

I finally solved it by including a div:
<div *ngFor="let filter of filters">
<div [ngClass]="filter.class">
<mat-icon
[ngClass]="{disabled: !filter.active}">alarm_on
</mat-icon>
</div>
</div>

you can write so:
<div *ngFor="let filter of filters">
<mat-icon [ngClass]="{disabled: !filter.active,filter.class }">alarm_on
</mat-icon>
</div>

You will need to use object array syntax and include all checks under the same ngclass attribute as follows:
<div *ngFor="let filter of filters">
<mat-icon [ngClass]="{filter.class : true, 'disabled' : !filter.active }">alarm_on
</mat-icon>
</div>

Related

creating overlapping user icons

I'm trying to create a a component that overlaps over the user icons just as shown in the photo. I've seen this being used on google. If I have a list of user icons, how do I overlap them over each other?
I want something like this .
<template>
<div >
<ul>
<li v-for="user in userList" :key="user.key">
<user-icon-component :name="user.name" :image="user.picture"></user-icon-component>
</li>
</ul>
</div>
</template>
<script>
export default {
name: "UserList",
props: {
userList: {
type: Object,
default: null,
},
},
};
</script>
<style>
</style>
The icon component is just an <img> tag with a user prop:
Vue.component('user-icon-component', {
props: ['user'],
template: `
<img :src="user.picture" width="32" height="32" />
`
})
Give the <li>s position: absolute and the <ul> position: relative to pull them out of the normal document flow. Set the left position on each <li> as a calculation from the index of the loop:
<ul class="icon-container">
<li v-for="(user, key, i) in userList" :key="user.key"
class="icon" :style="{ left: `${i * 20}px` }">
<user-icon-component :user="user"></user-icon-component>
</li>
</ul>
Here's a demo:
Vue.component('user-icon-component', {
props: ['user'],
template: `
<img :src="user.picture" width="32" height="32" />
`
})
/***** APP *****/
new Vue({
el: "#app",
data() {
return {
userList: {
'Bob': { name: 'Bob', key: 1, picture: 'https://www.flaticon.com/svg/static/icons/svg/3084/3084430.svg' },
'Mary': { name: 'Mary', key: 2, picture: 'https://www.flaticon.com/svg/static/icons/svg/3084/3084431.svg' },
'Paul': { name: 'Paul', key: 3, picture: 'https://www.flaticon.com/svg/static/icons/svg/3084/3084452.svg' },
}
}
},
});
.icon-container {
position: relative;
}
.icon {
position: absolute;
}
ul {
list-style-type: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<ul class="icon-container">
<li v-for="(user, key, i) in userList" :key="user.key"
class="icon" :style="{ left: `${i * 20}px` }">
<user-icon-component :user="user"></user-icon-component>
</li>
</ul>
</div>
I liked the idea in your question and took it as a challenge for myself and here is the result:
vue overlapping avatars component
basically the approach I took was to use the component's props as style in style binding. there are some scoped style as well but I think they can be set in the style binding as well if needs be (probably the code could be cleaner).
user prop is an array of objects that contains this property: img: 'imageURL' and using a v-for on a div element with:
:style="{ backgroundImage: `url(${user.img})`}"
we can set the images.
as for the overlapping part, divs have position: relative and using the index of v-for, the style binding becomes like this:
:style="{backgroundImage: `url(${user.img})`, left: `-${i*15}px`}"
which shifts every element to the left by 15px except for the first one.
here is the image of the final result:
Thanks for your question, it was fun :)

How to change button colour on click?

I want to change my button colour on click using angular and css as I am very new to it.
.ts
import { Component } from '#angular/core';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
title = 'title';
}
.html
<mat-sidenav color="primary" #sidenav fxLayout="column" mode="over" opened="false" fxHide.gt-sm="true">
<div fxLayout="column">
<button mat-button style="text-align:left" routerLink="butn1" >Attend</button>
<button mat-button style="text-align:left" routerLink="butn2" >Host</button>
<button mat-button style="text-align:left" routerLink="contact" >Contact</button>
<button mat-button style="text-align:left" routerLink="login" >Login</button>
</div>
</mat-sidenav>
You can add this in the html button tag
‘<button [class.mycolorclass]=’hasClicked’ (click)=’hasClicked=true’
The logic in the click directive can be moved into a method in the typescript class if you prefer that
I'm not familiar with angular, but CSS :active should manage to do this:
button {
line-height: 30px;
height: 30px;
font-size: 15px;
color: red;
border: 1px solid black;
background-color: #eee;
color: black;
}
button:active {
color: red;
border-color: red;
}
<button>Click me!</button>
on button click set variable true/false as per your requirement
buttonClicked=false;
onButtonClick(){
this.buttonClicked=true;
}
and give condition in HTML like this
<button mat-button
[ngClass]="buttonClicked? 'myClassHighlighted' : 'none'"
style="text-align:left" routerLink="attend" >Attend</button>
and in css add classes like
.myClassHighlighted{
//your styles here
}
.none{
//your styles here
}
Use ngClass in your buttons to give 'em conditional classes based on a flag which is set true only when you click on that button so I guess you will need ngClick as well, well I don't know about the version of Angular that you are using right now cuz you didn't mention that but now you know you will need ngClass and ngClick for sure and your code might look like sth like this:
<button mat-button style="text-align:left" [ngClass]="{'button--clicked': clicked}" routerLink="attend" (click)="clicked=!clicked" >Attend</button>
.ts
import { Component } from '#angular/core';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
title = 'title';
buttons = [
{ title: 'Attend', link: 'butn1', active: false },
{ title: 'Host', link: 'butn2', active: false },
{ title: 'Contact', link: 'contact', active: false },
{ title: 'Login', link: 'login', active: false },
]
toggleColor(button) {
button.active = !button.active;
}
}
.html
<mat-sidenav color="primary" #sidenav fxLayout="column" mode="over" opened="false" fxHide.gt-sm="true">
<div fxLayout="column">
<button
mat-button
*ngFor="let button of buttons"
[color]="button.active ? 'accent' : 'primary'"
style="text-align:left"
[routerLink]="button.link"
(click)="toggleColor(button)">
{{ button.title }}
</button>
</div>
Need to add css class for button based on click css value change

Change Fontawesome icon in Nativescript Vue

I'm creating a voting system. For both positive and negative votes, i use the same component - VoteButton. How to change the icon ( 'fa-thumbs-o-up' to 'fa-thumbs-up' and 'fa-thumbs-o-down' to 'fa-thumbs-down') when the button is activated? Which is the best option - via CSS (:before), vue.js logic ( IF or something), replace string via JS or something else?
Parent component:
<GridLayout columns="auto,*">
<VoteButton col="0" :buttontext=" 'fa-thumbs-o-up' | fonticon" :votes="upVotes" label="Upvote" :active="upvoted" width="33%" #click="vote(1)" />
<VoteButton col="1" :buttontext=" 'fa-thumbs-o-down' | fonticon" :votes="downVotes" label="Downvote" :active="downvoted" width="33%" #click="vote(-1)" />
</GridLayout>
Parent component CSS:
.upvote.active {
background: orangered;
color: white;
}
.downvote.active {
background: blue;
color: white;
}
VoteButton child component:
<template>
<button #tap="$emit('click')" :class="[buttonClass, { active }]">
<FormattedString>
<Span class="fa" > {{ buttontext }}</Span>
<Span> {{ votes }}</Span>
</FormattedString>
</button>
</template>
<script>
export default {
props: {
active: Boolean,
label: String,
buttontext: String,
votes: Number
},
computed: {
buttonClass() {
return this.label.toLowerCase();
}
}
};
</script>
You could use a counter in javascript to keep track of whether the button should be displaying an upvote or a downvote based on the number of times the button is pressed.
Example:
Html:
<button onclick="myFunction()">Try it</button>
<div id="myDIV">
This is a DIV element.
</div>
CSS:
<style>
.mystyle {
background: orangered;
color: white;
}
.mystyle2 {
background: blue;
color: white;
}
</style>
Javascript:
<script>
var x = 0;
function myFunction() {
var element = document.getElementById("myDIV");
if (x % 2 == 0){
element.classList.add("mystyle");
element.classList.remove("mystyle2");
x++;
}
else {
element.classList.add("mystyle2");
element.classList.remove("mystyle");
x++;
}
}
</script>
Thanks! I did it the following way:
Parent:
<VoteButton col="0" noactivefatext='fa-thumbs-o-up' activefatext='fa-thumbs-up' :votes="upVotes" label="Upvote" :active="upvoted" #click="vote(1)" />
<VoteButton col="1" noactivefatext='fa-thumbs-o-down' activefatext='fa-thumbs-down' :votes="downVotes" label="Downvote" :active="downvoted" #click="vote(-1)" />
VoteButton component:
<template>
<button #tap="$emit('click')" :class="[buttonClass, { active }]">
<FormattedString>
<Span class="fa body" :text="active ? activefatext : noactivefatext | fonticon" ></Span>
<Span> {{ votes }}</Span>
</FormattedString>
</button>
</template>

How to add class(es) to elements generated by ngFor on hover?

Problem: I have some html that uses *ngFor to generate a bunch of divs, all with the same class. I want to be able to add an active class to single elements. I keep running into the issue though of having that class applied to all of my elements instead of just one.
HTML:
<div class="feed" infiniteScroll [infiniteScrollDistance]="2" [infiniteScrollThrottle]="50" (scrolled)="onScroll()" >
<div class="mentions" *ngFor = 'let item of feed; let i = index;'>
<div class="content-wrapper">
<img src={{item.image}}>
<div class="content-text">
<div>{{item.name}}</div><br>
<div>{{item.text}}</div><br>
<div>{{item.followers}}</div><br>
</div>
</div>
<div class="votebtn">
<button mat-button matSuffix mat-icon-button aria-label="UpVote" id = u-{{item.source}} class="UpVote" (click)="vote(i, item, 'keep')">
<mat-icon>thumb_up</mat-icon>
</button>
<button mat-button matSuffix mat-icon-button aria-label="DownVote" id=d-{{item.source}} class=DownVote (click)="vote(i, item, 'ignore')">
<mat-icon>thumb_down</mat-icon>
</button>
</div>
</div>
</div>
Goal: Ultimately, I'd love to be able to do something as simple as adding box-shadow: 1px -1px 12px 0px #c9c9c9 to the a single mentions element on mouseover and then remove it on mouseout. This is my most recent attempt.
<div *ngFor = 'let item of feed; let i = index;' [ngClass] = 'state' (mouseover) = "state = 'mentions hover'" (mouseout) = "state = 'mentions'">
Again, it would add to all elements.
Late reply. I let the object array do most of the work as this pattern is cleaner for me:
CSS
li.selected {
border-bottom: thick solid purple;
}
li.hover {
border-bottom: thick dotted gray;
}
Object
NavigtionMenu = [
{
name: 'Home',
link: 'path/to/link',
hover: false,
selected: false,
},
{
name: 'About Us',
link: 'path/to/link',
hover: false,
selected: false,
}
]
Template
<li
*ngFor="let item of items; let i = index"
(mouseover)="item.hover = true"
(mouseout)="item.hover = false"
(click)="item.selected = true"
[routerLink]="item.link"
[ngClass]="{
'selected' : link.selected === true && link.hover === false,
'hover' : link.hover === true
}"
>
{{ item.name }}
</li>
You could archive this visual effect by defining a small attribute directive:
#Directive({
selector: '[ngHoverClass]'
})
export class NgHoverClassDirective {
#Input(`ngHoverClass`)
set classesToAply(v: string | string[]){
this.classes = Array.isArray(v) ? v: v.split(' ');
}
private classes: string[] = [];
constructor(private renderer: Renderer2, private element: ElementRef){}
#HostListener('mouseover')
onHover(){
this.classes.forEach(c=> this.renderer.addClass(this.element.nativeElement, c));
}
#HostListener('mouseleave')
onLeave(){
this.classes.forEach(c=> this.renderer.removeClass(this.element.nativeElement, c));
}
}
After making it available for consume, you could use it in a component as follows:
<div *ngFor = 'let item of feed; let i = index;' ngHoverClass='hover' class="mentions">
<div *ngFor="let item of feed; let i = index;" [ngClass]="{'hovered': item.isHovered'}" (mouseover)="item.isHovered=true" (mouseout)="item.isHovered=false">

Angular 1.5 component css scoping with nested components

I'm trying to use angular 1.5 components to create a button group.
<button-group size="default">
<my-button>Button 1</my-button>
<my-button>Button 2</my-button>
</button-group>
But, it compiles to something like:
<div class="btn-group" ng-transclude>
<my-button class="ng-scope ng-isolate-scope>
<button class="btn>Button 1</button>
</my-button>
<my-button class="ng-scope ng-isolate-scope>
<button class="btn>Button 1</button>
</my-button>
</div>
So now my CSS scoping is all messed up:
.btn-group > .btn:not(:first-child) {
background: red; //<- doesnt work
}
Basic example:
const buttonGroup = {
bindings: {},
transclude: true,
template: myButtonGroupTemplate
};
You can add classes to your component
Something like that:
html
<button-group size="default">
<my-button class="awesome-class-btn">Button 1</my-button>
<my-button class="awesome-class-btn">Button 2</my-button>
</button-group>
css
.btn-group .awesome-class-btn > .btn:not(:first-child) {
background: red;
}

Resources