Im trying to pass variable with [ngStyle] and read it on ::before class but unfortunately cannnot do it,
could someone point me on a right direction?
CSS:
.handle-slider__control {
height: 7px;
z-index:1;
background: $colour-alto;
position: relative;
margin:50px auto;
margin-bottom: 16px;
&.handle-slider__control--markers {
margin-bottom: 0;
}
}
.handle-slider__control::before {
position: absolute;
z-index:-1;
content:"";
left: var(--left);
right: var(--right);
background: $colour-red;
height:100%;
}
HTML:
<div [ngStyle]="getRangeColours()" class="handle-slider__control"></div>
And JS method:
getRangeColours()
{
return {"--left": "10%","--right": "10%"};
}
There is no information about wrongly passed data or anything. Im trying to change css parameters left, right based on data that are in component. If there is any other way to do it I would also consider it. THANKS!
Tested in Angular 9.1.11
test.component.ts
import { Component, OnInit, HostBinding } from '#angular/core';
#Component({
selector: 'app-test',
templateUrl: './test.component.html',
styleUrls: ['./test.component.scss']
})
export class TestComponent implements OnInit {
#HostBinding('style.--left.%') left: number = 20; // Change it to any Number at any point
#HostBinding('style.--right.%') right: number;
constructor() {}
ngOnInit(): void {
this.right = 10; // Change it to any Number at any point
}
}
test.component.html
<h2 class="handle-slider__control">CSS Variables in Angular</h2>
test.component.scss
.handle-slider__control {
height: 7px;
z-index:1;
background: blue;
position: relative;
margin:50px auto;
margin-bottom: 16px;
&.handle-slider__control--markers {
margin-bottom: 0;
}
}
.handle-slider__control::before {
position: absolute;
z-index:-1;
content:"";
left: var(--left);
right: var(--right);
background: red;
height:100%;
}
For Lower versions, try this (couldn't test though):
import { DomSanitizer } from '#angular/platform-browser';
public value: string;
#HostBinding("attr.style")
public get leftStyle(): any {
return this.sanitizer.bypassSecurityTrustStyle(`--left: value`);
}
constructor(private sanitizer: DomSanitizer) {
this.value = '10%';
}
About css variales thare are differents insteresting links about this, Take a look here or here, e.g.
I don't check it but
document.documentElement.style.setProperty('--left', "10%");
document.documentElement.style.setProperty('--rigth', "20%");
must be work
I just used different class instead of pseudocode with ngStyle on it like that:
.slider-colour-control {
position: absolute;
z-index:-1;
content:"";
background: $colour-red;
height:100%;
}
Related
I'm new on angular,
And I'm trying to make a gallery with a lighbox that shows up when an image is clicked.
I already try the examples with bootstrap and also tried to do it by myself, but when I click on the img-link, the links throws me up to the home page maybe there is a config that I didn't know how to use it or is missing.
I don't know if its a problem about routes or if I need to do other commponent for that.
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script>
import { Component, OnInit } from '#angular/core';
import { CuadrosService, Cuadro } from '../cuadros.service';
#Component({
selector: 'app-galeria',
templateUrl: './galeria.component.html',
styleUrls: ['./galeria.component.css']
})
export class GaleriaComponent implements OnInit {
Cuadro:any [] = [];
constructor(private _cuadosService:CuadrosService ) {
console.log("constructor")
}
ngOnInit(): void {
this.Cuadro = this._cuadosService.getCuadros();
console.log(this.Cuadro);
}
}
.container-galeria {
display: flex;
flex-wrap: wrap;
grid-template-columns: repeat(4, 1fr);
grid-auto-rows: 400px;
background-color: rgba(0, 0, 0, .80);
justify-content: space-around;
}
.img-galeria {
width: 100%;
height: 100%;
object-fit: cover;
padding: 10px;
}
.img-galeria:hover {
transform: scale(1.05);
box-shadow: 0 8px 15px rgba(0, 0, 0, 0.3);
}
.item-galeria:nth-child(1) {
grid-column-start: span 2;
}
.item-galeria:nth-child(2) {
grid-row-start: span 2;
}
.lightbox {}
.lightbox:active {
display: block;
position: fixed;
flex-wrap: wrap;
height: fit-content;
width: fit-content;
max-width: 1200px;
max-height: 800px;
background-color: rgba(0, 0, 0, 0.3);
z-index: 2000;
justify-content: center;
}
<hr>
<div class="container-galeria container">
<div class=" lighbox item-galeria col-4" *ngFor="let cuadro of Cuadro">
<img class="img-galeria" [src]="cuadro.foto" alt="">
</div>
</div>
<app-footer></app-footer>
Any idea? or somthing wrong in my code?
Thanks for the help.
So the way I am seeing it your lightbox is missing a t in the class name.
Secondly I would set a onclick listener for each image to remove and set an active class instead of using the :active css selector. The css selector :active will be removed as soon as the person stops clicking.
You will have to Pass your Element in to the function to determine what image will be active.
Also you might want to add a function to exit the active mode
<div class="lightbox item-galeria col-4" *ngFor="let cuadro of Cuadro" (click)="toggleActive($event, item)">
<img class="img-galeria" [src]="cuadro.foto" alt="">
</div>
The function:
import { Component, OnInit } from '#angular/core';
import { CuadrosService, Cuadro } from '../cuadros.service';
#Component({
selector: 'app-galeria',
templateUrl: './galeria.component.html',
styleUrls: ['./galeria.component.css']
})
export class GaleriaComponent implements OnInit {
Cuadro:any [] = [];
constructor(private _cuadosService:CuadrosService ) {
console.log("constructor")
}
ngOnInit(): void {
this.Cuadro = this._cuadosService.getCuadros();
console.log(this.Cuadro);
}
toggle(event, item): void {
if(item.classList.contains("active")){
item.classList.remove("active"));
}else{
item.classList.add("active"));
}
}
I might add that I didn't test the code and some parts of code may need a little tweak.
I hope I could help.
I am new to angular 7 directives. I created a custom tooltip directive using angular 7. Now, I am unable to specify line breaks when i pass the tooltip text from my html. I want a line break after the Tootltip Title text I pass from html. Any idea how to achieve this?
Tried to pass
and
code for line break in my input string to the tooltip directive. Didn't work either.
Here is what I tried so far.
My directive : tooltip.directive.ts:
import { Directive, Input, ElementRef, HostListener, Renderer2 } from '#angular/core';
#Directive({
selector: '[tooltip]'
})
export class TooltipDirective {
#Input('tooltip') tooltipTitle: string;
#Input() placement: string;
#Input() delay: number;
tooltip: HTMLElement;
offset = 10;
constructor(private el: ElementRef, private renderer: Renderer2) { }
#HostListener('mouseenter') onMouseEnter() {
if (!this.tooltip) { this.show(); }
}
#HostListener('mouseleave') onMouseLeave() {
if (this.tooltip) { this.hide(); }
}
show() {
this.create();
this.setPosition();
this.renderer.addClass(this.tooltip, 'ng-tooltip-show');
}
hide() {
this.renderer.removeClass(this.tooltip, 'ng-tooltip-show');
window.setTimeout(() => {
this.renderer.removeChild(document.body, this.tooltip);
this.tooltip = null;
}, 0);
}
create() {
this.tooltip = this.renderer.createElement('span');
this.renderer.appendChild(
this.tooltip,
this.renderer.createText(this.tooltipTitle) // textNode
);
this.renderer.appendChild(document.body, this.tooltip);
this.renderer.addClass(this.tooltip, 'ng-tooltip');
this.renderer.addClass(this.tooltip, `ng-tooltip-${this.placement}`);
}
setPosition() {
const hostPos = this.el.nativeElement.getBoundingClientRect();
const tooltipPos = this.tooltip.getBoundingClientRect();
let top, left;
if (this.placement === 'top') {
top = hostPos.top - tooltipPos.height - this.offset;
left = hostPos.left + (hostPos.width - tooltipPos.width) / 2;
}
/* other positions to be added */
this.renderer.setStyle(this.tooltip, 'top', `${top}px`);
this.renderer.setStyle(this.tooltip, 'left', `${left}px`);
}
}
CSS :
/* Styles for tooltip */
.ng-tooltip {
position: absolute;
max-width: 150px;
font-size: 14px;
text-align: center;
color: #f8f8f2;
padding: 3px 8px;
border-radius: 2px;
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.5);
background-color: #38393b;
z-index: 1000;
opacity: 0;
}
.ng-tooltip:after {
content: "";
position: absolute;
border-style: solid;
}
.ng-tooltip-top:after {
top: 100%;
left: 50%;
margin-left: -5px;
border-width: 5px;
border-color: #38393b transparent transparent transparent;
}
.ng-tooltip-show {
opacity: 1;
}
From the html file, I invoke the tooltip directive by passing the text like this:
<div tooltip="Title: ( want a line break here)
{{someVariable}}" placement="top" class="remark">Hover Here</div>
This can be resolved by taking any of the approach,
Either create two different input such as #Input('Title'): string and #Input('Body'): string and pass into two different parameters.
OR
if you want to pass it in a single parameter make a use of interface such as
export interface IToolTip {
title?: string;
body: string;
footer?: string;
}
Assign this interface to your tooltip variable #Input('tooltip') tooltipTitle: ITooltip; Rest of the things can taken care under create() funciton.
Thanks.
I am using React-typescript in my app. For styling I am using Style-components. I am really new Style-components. Lots of syntax are new to me. I normally use css. I have decided I will convert my css into Style-component. So I can use it different components. I have created one Wrapper components where I put my Label with style components. I also created two components one is Input and another one is Textarea. I want to use Wrapper components both Input and Textarea components. I followed one youtube tutorial. Where I converted html and css into react-css. which works fine as expected. But I am struggling to convert react css into style-components. specially the focus and valid option. I really don't know how to use them. Also I am facing difficulties when label size vary. It takes sometimes too left or sometimes too right. Here is the Image:
.
I really don't know how to fix those issues.
This is my Youtube tutorial based on React component
import React from 'react'
import './new.css'
const Test = () => {
return (
<div className="main">
<div className="input-group">
<input type="text" id="firstname" className="inputField" autoComplete="off" required />
<label htmlFor="name" className="labels">First name</label>
</div>
</div>
)
}
export default Test;
This is the css
.main{
position: relative;
}
.inputField{
outline: none;
padding: 16px 22px;
border: 1px solid #dadce0;
font-size:18px;
border-radius:5px;
}
.inputField:focus{
border: 2px solid royalblue;
}
.labels{
color: #8d8d8d;
position: absolute;
top: 27px;
left: 55px;
background: #ffffff;
transition: 300ms;
transform: translate(-50%, -50%);
}
.inputField:valid + .labels{ // I don't know how to use this `Valid` in style-component
top: -1px;
padding: 0 3px;
font-size:14px;
color: #8d8d8d;
}
.inputField:focus + .labels { // I don't know how to use this `focus` in style-component
top: -1px;
padding: 0 3px;
font-size:14px;
color: royalblue;
transition: 300ms;
}
This is the wrapper component where I used Label styling with style-components and others requirements.
import React from 'react';
import styled from 'styled-components';
const Container = styled.div`
position: relative;
`
const Label = styled.label`
display: block;
color: #8d8d8d;
background: #ffffff;
position: absolute;
left: 50px;
top: 29px;
pointer-events: none;
transition: 300ms;
transform: translate(-50%, -50%);
`
const Error = styled.p`
color: red;
`
const Description = styled.p`
color: blue;
`
export interface IInputWrapperProps {
label?: string;
required?: boolean;
description?: string;
error?: string;
wrapperStyle?: React.CSSProperties;
children?: JSX.Element;
}
export default ({
label, error, description, children, required, wrapperStyle
}: IInputWrapperProps) => {
return (
<ErrorBoundary id="InputWrapperErrorBoundary">
<div style={wrapperStyle}>
<Container>
<Label>
{label} {required && <span style={{ color: 'red' }}> *</span>}
</Label>
{children}
</Container>
{description && <Description>{description}</Description>}
{error && <Error>{error}</Error>}
</div>
</ErrorBoundary>
);
}
This is my Input component styling with style-componenents
import React, { useState, memo } from "react";
import styled from "styled-components";
import InputWrapper, { IInputWrapperProps } from "../wrapper";
import { Label } from "../wrapper"
const Input = styled.input.attrs(() => ({
className: 'text-input'
}))`
border: 1px solid #dadce0;
background: #fdfdfd;
font-size:18px;
border-radius: 5px;
box-shadow: none;
padding: 16px 30px;
outline: none;
&:focus {
border: 2px solid royalblue;
}
${Label}:focus & {
top: -12px;
padding: 0 3px;
font-size:14px;
color: royalblue;
transition: 300ms;
}
`
export interface ITextInputProps extends IInputWrapperProps {
value: string | undefined;
onChange: (i: string) => void;
}
export default memo(({
value, onChange, ...wrapperProps
}: ITextInputProps) => {
return (
<InputWrapper
{...wrapperProps}
>
<div>
<Input
value={value}
onChange={e => onChange(e.target.value)}
/>
</div>
</InputWrapper>
)
});
This is the parent component where I am rendering those two input fields
<InputTesting
label="Frist Name"
value={undefined}
onChange={(i) => console.log(i)}
/>
<br></br>
<br></br>
<InputTesting
label="Hello"
value={undefined}
onChange={(i) => console.log(i)}
/>
Before I answer the question, I need to say two things: first, I couldn't understand so much about your styled-components code, so I'll just transform your react/CSS code to react-typescript/styled-component. Second, I didn't get what you mean by "difficulties when label size varies", so I'm not focusing on this in the answer. That been said, let's go to the code.
Input.tsx
import React from 'react';
import styled from 'styled-components';
interface InputProps extends React.InputHTMLAttributes<HTMLInputElement>{
id: string;
label: string;
}
const InputGroup = styled.div`
position: relative;
`;
const InputLabel = styled.label`
color: #8d8d8d;
position: absolute;
top: 27px;
left: 55px;
background: #ffffff;
transition: 300ms;
transform: translate(-50%, -50%);
`;
const InputField = styled.input`
outline: none;
padding: 16px 22px;
border: 1px solid #dadce0;
font-size: 18px;
border-radius: 5px;
&:focus
{
border: 2px solid royalblue;
}
&:valid + ${InputLabel}
{
top: -1px;
padding: 0 3px;
font-size:14px;
color: #8d8d8d;
}
&:focus + ${InputLabel}
{
top: -1px;
padding: 0 3px;
font-size:14px;
color: royalblue;
transition: 300ms;
}
`;
const Input: React.FC<InputProps> = ({ id, label, ...rest }) => {
return (
<InputGroup>
<InputField id={id} {...rest} />
<InputLabel htmlFor={id} >{label}</InputLabel>
</InputGroup>
);
}
export default Input;
The idea here is to create an input component that already has a label inside it. Initially, I create an interface called InputProps which extends all attributes from a common InputElement and forces the parent component to put an id and a label attribute.
Them I used styled-components to copy all styles from the youtube guy. To put pseudo-classes on styled-components you have to use a sass' feature called parent selector. Using the ampersand, you can refer to the parent selector. Another thing you have to use is styled-components reference. This feature will allow you to refer to the styled-label in the code.
Now that you've created the Input component, let's use it on the App.
App.tsx
import React from 'react';
import Input from './Input';
function App() {
return (
<>
<Input required type="text" label="First Name" id="first-name" />
<Input required type="text" label="Hello" id="hello" />
</>
);
}
export default App;
This is the final result.
I have a problem with Angular and Material for Angular, I have an application with many modals, they all lock background scrolling when they're open, but I have a notification modal, this notification modal isn't intended to block background scrolling.
I don't have any .noScroll class in this modal, but the background page in relation to the modal still won't scroll, I want to the user to be able to scroll the page even with the notification modal open.
The notification modal is a DialogRef from Material for Angular.
I tried using overflow: visible and auto, also tried to modify the backdrop to enable scroll, but no success :(
How do I make the backdrop of this particular modal to enable scrolling and possible override other configurations of the code?
Edit: Here is part of the code >
ModalService:
{
constructor(private matDialog: MatDialog) {
}
openNotificationsModal(topOffset, rightOffset): MatDialogRef<NotificationsModalComponent> {
return this.notificationsModal(topOffset, rightOffset);
}
private notificationsModal(topOffset, rightOffset, clazz?: string): MatDialogRef<NotificationsModalComponent> {
const config = {
panelClass: clazz ? clazz : 'notifications-modal',
backdropClass: 'cdk-overlay-transparent-backdrop',
data: {
topOffset,
rightOffset,
}
};
return this.matDialog.open(NotificationsModalComponent, config);
}
}
this is my modal component:
import { Component } from '#angular/core';
import { MatDialogRef } from '#angular/material';
#Component({
selector: 'aa-notifications-modal',
templateUrl: './notifications-modal.component.html',
styles: []
})
export class NotificationsModalComponent {
constructor(private dialogRef: MatDialogRef<NotificationsModalComponent>) {}
async ngOnInit() {
this.dialogRef.updatePosition({
top: '2.5rem'
});
}
output() {
this.dialogRef.close();
}
}
this is the scss of this modal:
aa-notifications-modal {
width: 100%;
}
.notifications-modal {
width: 100%;
max-width: 100% !important;
pointer-events: none !important;
.mat-dialog-container {
display: flex;
justify-content: flex-end;
background: transparent;
width: 100%;
box-shadow: none;
}
.align-triangle {
display: flex;
justify-content: flex-end;
padding: 0;
.triangle {
margin-right: 4rem;
width: 0;
height: 0;
border-left: 25px solid transparent;
border-right: 25px solid transparent;
border-bottom: 25px solid #fff;
}
}
.space {
padding: 0;
}
.content-modal {
display: flex;
justify-content: flex-end;
margin-right: 8rem;
aa-notifications-list {
width: 427px;
pointer-events: auto;
border-radius: 5px;
}
}
}
As I can understand you need to find out where overflow: hidden; likely it will be on body tag, a simple solution you can try to set overflow: auto !important;
But more elegant will be to provide Scroll strategy into your Dialog
I wanted to make two stretchable rectangles which can be resized horizontally(both left and right).But the problem with my current code is that once i resize my first rectangle(in red),the second rectangle(in blue) automatically jumps to the initial position of the first rectangle.Please help me to fix this.
I am attaching my code along with the output images.
html file:
<div class="rectangle" [ngStyle]="style" mwlResizable [validateResize]="validate"
[enableGhostResize]="true"
[resizeSnapGrid]="{ left: 1, right: 1 }" (resizeEnd)="onResizeEnd($event)">
<div class="resize-handle-left" mwlResizeHandle [resizeEdges]="{ left: true }"></div>
<div class="resize-handle-right" mwlResizeHandle [resizeEdges]="{ right: true }"></div>
</div>
<div class="rectangle1" [ngStyle]="style1" mwlResizable [validateResize]="validate1"
[enableGhostResize]="true"
[resizeSnapGrid]="{ left: 1, right: 1 }" (resizeEnd)="onResizeEnd1($event)">
<div class="resize-handle-left1" mwlResizeHandle [resizeEdges]="{ left: true }"></div>
<div class="resize-handle-right1" mwlResizeHandle [resizeEdges]="{ right: true }"></div>
</div>
css file:
.rectangle {
position: relative;
width: 50px;
height: 50px;
border-radius: 10px;
background-color: red;
}
.rectangle1 {
position: relative;
width: 50px;
height: 50px;
border-radius: 10px;
background-color: blue;
}
.resize-handle-left,
.resize-handle-right {
position: absolute;
height: 50px;
cursor: col-resize;
width: 5px;
}
.resize-handle-left {
left: 0;
}
.resize-handle-right {
right: 0;
}
.resize-handle-left1,
.resize-handle-right1 {
position: absolute;
height: 50px;
cursor: col-resize;
width: 5px;
}
.resize-handle-left1 {
left: 0;
}
.resize-handle-right1 {
right: 0;
}
.ts file:
import { Component } from '#angular/core';
import { ResizeEvent } from 'angular-resizable-element';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
constructor() { }
public style: object = {};
public style1: object = {};
validate(event: ResizeEvent): boolean {
const MIN_DIMENSIONS_PX: number = 50;
if (
event.rectangle.width &&
event.rectangle.height &&
(event.rectangle.width < MIN_DIMENSIONS_PX ||
event.rectangle.height < MIN_DIMENSIONS_PX)
) {
return false;
}
return true;
}
validate1(event: ResizeEvent): boolean {
const MIN_DIMENSIONS_PX: number = 50;
if (
event.rectangle.width &&
event.rectangle.height &&
(event.rectangle.width < MIN_DIMENSIONS_PX ||
event.rectangle.height < MIN_DIMENSIONS_PX)
) {
return false;
}
return true;
}
onResizeEnd(event: ResizeEvent): void {
this.style = {
position: 'fixed',
left: `${event.rectangle.left}px`,
top: `${event.rectangle.top}px`,
width: `${event.rectangle.width}px`,
height: `${event.rectangle.height}px`
};
}
onResizeEnd1(event: ResizeEvent): void {
this.style1 = {
position: 'fixed',
left: `${event.rectangle.left}px`,
top: `${event.rectangle.top}px`,
width: `${event.rectangle.width}px`,
height: `${event.rectangle.height}px`
};
}
}
Links to the output:
On refreshing my page
problem with resizing
Remove css property top and position
import { Component } from '#angular/core';
import { ResizeEvent } from 'angular-resizable-element';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
name = 'Angular';
public style: object = {};
public style1: object = {};
validate(event: ResizeEvent): boolean {
const MIN_DIMENSIONS_PX: number = 50;
if (
event.rectangle.width &&
event.rectangle.height &&
(event.rectangle.width < MIN_DIMENSIONS_PX ||
event.rectangle.height < MIN_DIMENSIONS_PX)
) {
return false;
}
return true;
}
validate1(event: ResizeEvent): boolean {
const MIN_DIMENSIONS_PX: number = 50;
if (
event.rectangle.width &&
event.rectangle.height &&
(event.rectangle.width < MIN_DIMENSIONS_PX ||
event.rectangle.height < MIN_DIMENSIONS_PX)
) {
return false;
}
return true;
}
onResizeEnd(event: ResizeEvent): void {
this.style = {
left: `${event.rectangle.left-8}px`,
width: `${event.rectangle.width}px`,
height: `${event.rectangle.height}px`
};
}
onResizeEnd1(event: ResizeEvent): void {
this.style1 = {
left: `${event.rectangle.left-8}px`,
width: `${event.rectangle.width}px`,
height: `${event.rectangle.height}px`
};
}
}
resizeEnd is the same event for both the rectangles. So when it fires function attached to this event will be called. In your code
functions:- onResizeEnd and onResizeEnd1 must be called togather
when resizeEnd event occurs and the values of another rectangle
got reset.
try to create separate events for both the rectangles.
let me know if this is helpful.