In my application, I have two components communicating with each other with BehaviorSubject since they are siblings. I have a form and a card, card can be either "question" or " answer" and its color changes accordingly.
To change it I use CSS variables. But I also want a "tilting" animation whenever the color changes.
I can't use angular animation because the animation is not data-binded related and in my application, the card component is nested inside various components that are animated with "angular animation" and it's not working anyway.
What I try to do is to bind a class with animation to my card main div but it only triggers when the component loads. What is the correct way to make my card tilt whenever its color changes?
Here is a stackblitz that describes my issue.
It can be done easily with Angular animations. Here is your example updated: https://stackblitz.com/edit/angular-ivy-aw3zs3?file=src/app/card/card.component.ts
You just need to provied a state function to handle the transtion trigger.
transition((fromState: string, toState: string) => toState != fromState, [
// animations
])
And you need to link the animation with the target variable
<div class="card" [style]="style" [#cardChange]="card.card">
</div>
Related
I've got a Blazor server app which displays a grid of images. I want to have the images fade when they're displayed. I'm currently using a CSS style/animation:
.gridimage {
animation: fadeIn ease 1s;
}
<img class="gridimage" src="#ImageUrl">
This works fine on initial page load - but when a user changes a filter criteria and the grid of images changes, my #code updates the #ImageUrl and I call StateHasChanged, but the fade doesn't kick in, because the image has already loaded.
I've thought about trying a different approach, where I define a JS method:
function fadeIn(obj) {
obj.style.transition = "opacity 1s";
obj.style.opacity = "1";
}
and then detect DOM changes and trigger that fadeIn() call when the img src attribute changes, but that feels kindof like fighting with the Blazor DOM update model. I've also toyed with using JSInterop when I update ImageUrl but again, it seems messy.
Is there a more elegant way to do it?
Turned out that Brian Parker's answer was correct; adding a unique #key to the item caused the CSS to re-trigger when the page transitions and the image updates - presumably because Blazor sees the <img #key=1234> item as different to <img #key=1235> and so forces it to re-evaluate the CSS.
I am using the Angular Material CDK Drag and Drop Functionality in my application. The drag and drop functionality is working fine, unless I am using it within a dialog (for most components I am using Nebular, in this case the Nebular dialog). The problem I am encountering is, as soon as I drag a draggable element within the dialog, the element disappears behind the dialog. After dropping it, it reappears on the correct position. In the screenshot, I am dragging the "AAAA" element away from the list - it disappears behind the dialog.
Stackblitz: https://stackblitz.com/edit/angular-znqckb
I am using the following implementation:
<div cdkDropList cdkDropListOrientation="horizontal" class="example-list" [cdkDropListData]="techs"
(cdkDropListDropped)="drop($event)">
<button *ngFor="let tech of techs" nbButton cdkDrag>{{tech}}</button>
</div>
Component.ts:
drop(event: CdkDragDrop<string[]>) {
moveItemInArray(this.techs, event.previousIndex, event.currentIndex);
}
I did not modify the style sheet. I assume this issue can be solved somehow by modifying the z-index but I don't know how to apply it to the "dragging" element.
You can change the DragRefConfig injecting the right config (with the desired z-index) in your component. For example:
const DragConfig = {
dragStartThreshold: 0,
pointerDirectionChangeThreshold: 5,
zIndex: 10000
};
providers: [{ provide: CDK_DRAG_CONFIG, useValue: DragConfig }]
The z-index of the preview element will be 10000 ;-)
For more infos: https://material.angular.io/cdk/drag-drop/api#DragRefConfig
I'm struggling with this problem myself and I'm using a crude workaround for now. Forcing the z-index of .cdk-overlay-container to 1000 in your global styles (styles.scss) should get you the result you want. It's not best practice though.
Add this in styles.scss:
.cdk-overlay-container {
z-index: 1000 !important;
}
Stackblitz here
To my knowledge, it's not possible to force a z-index on the drag preview ("dragging" element) because the cdk sets its z-index dynamically as inline style. The Nebular library you are using seems to be setting the z-index of the overlay container to 1040. The Angular Material library sets the drag preview's z-index as 1000, that's why it goes behind the overlay. Vanilla Angular Material sets the z-index of cdk overlay to 1000, so drag & drop will work in that scenario.
For previous angular material versions than 9.
In the html dragable element:
<div ... cdkDrag (cdkDragStarted)="onDragStarted($event)"</div>
In the compoonent ts:
export class ...{
zIndexSerial: number = 1000;
onDragStarted(event: CdkDragEnd): void {
event.source.element.nativeElement.style.zIndex=this.zIndexSerial+"";
this.zIndexSerial = this.zIndexSerial+1;
}
for anyone struggling with the same issue.I found the solution to be z-index only work on positioned elements Refer to this link description here
For Angular version 8, I added the following to styles.scss and got it to work in the modal:
.cdk-drag-preview {
z-index: 9000 !important;
}
See .cdk-drag-preview in https://material.angular.io/cdk/drag-drop/overview#styling
I have a modal that pops up with tab-able elements. Is there something like jQuery's :focusable or pointer-events: none that would allow me use CSS to disallow focusing on items underneath the overlay?
edit: The problem with a JS based approach (and selectors), is that each rerender with React, the query selector would have to be run through again. I don't have control over the component rendering this modal.
You want to do something along the lines of:
const inputs = [...document.getElementsByTagName('input')];
inputs.forEach((input) => input.setAttribute('tabindex', '-1'));
const modalInputs = [...document.querySelectorAll('.my-modal input')];
modalInputs.forEach((input, index) => input.setAttribute('tabindex', index));
Full Example https://codepen.io/bradevans/pen/GGYxrg
Edit: I hadn't seen the reactjs tag until OP commented... I'd utilize the Modals componentDidMount lifecycle method to change the underlying DOM inputs tab indexes and change the modals at the same time or using internal state....
You may also want to store the old tab indexes and reapply them on componentWillUnmount();
I'd like to ask for a little nudge to get my brain out of the box I got it into.
Context
Angular 4 using Angular CLI and AoT.
All methods mentioned in https://angular.io/docs/ts/latest/guide/component-styles.html describe ways to set complex CSS of a component while it is being written by a developer.
After a component is created, Angular allows to adjust individual styles and even assign various CSS class names to tags in the component as you please, all that using [ngClass], <div [class.something]="condition">, various #HostBinding decorators and some other methods.
However, none of the above can change the CSS declaration the component is using. The methods above can either (a) use what is already available in the stylesheet defined by the developer or (b) set individual CSS properties to individual HTML tags in the component's template.
Question
How would I update the CSS for the whole component on runtime so that all elements in that component respond to the new CSS?
Say I introduce a new style for a div.someClass and I want all matching elements div.someClass to reflect the new style.
Plunker
A showcase of my attempts is here: https://plnkr.co/edit/N2C40cSb7hd1AyOxWWdT
The button should be red, based on the value of MyChildComponent.styles
I think I understand why it doesn't work the way I would expect: shortly said, styles are built in the component during compilation, not runtime, including those found inside <style /> tags in the template.
But knowing why it doesn't work doesn't help me to make it work.
Any help highly appreciated.
Solution 1
Inserting a new css class is not possible ( as far as i know ) but you can insert css properties to your component dynamically.
I modified your dynamicStyles() to this
get dynamicStyles(): any{
return {'background': 'red' };
}
that returns an object instead of string because you will pass this object to ngStyle of your button.
In your template, I change the button like this
<button type="button"
[ngStyle]="styles">
Button
</button>
Here's a plunkr
Solution 2
This is something that I would not recommend but in your case it might be useful. You can add this
encapsulation: ViewEncapsulation.None
and the import
import {ViewEncapsulation} from '#angular/core'
to your #Component.You can leak your component's css so that you can use it on your child component. Then in your child component, add a [ngClass] in your button so that you can just pass a variable via #Input() if it should be red.
<button type="button"
[ngClass]="{'redButton': isButtonRed}"
>Button</button>
And in your style.css
.redButton{
background:red;
}
And in your main component.
<div>
<h2>Hello name</h2>
<my-child [isButtonRed]="true"></my-child>
</div>
Here's another plunkr
Hope this helps.
Implemented following scenario
nextClassName={'text-hide'}
nextText={''}
nextIconComponent={
<RaisedButton
label='Next'
/>}
Now this provides me a Next Button with a wrapper div above button, and text-hide class is applied to that div not the button and hence border and background of next button remains as it is.
Please see screenshot http://imgur.com/a/AhBnc
make background and border outside NEXT button transparent, what should i do
The approach I have taken in this implementation is totally wrong.
What should be done is that create a custom pagination component with that component we will create a Next and Previous button and drop down select list for page number, and then include that custom component in the Griddle section
The value passed to customPagerComponent should be a React class, not simply jsx. To take your first example you would probably want to do this:
class MyCustomPagerComponent extends Component {
// boilerplate react stuff
render() {
// jsx for your component
}
}
Then in your Griddle jsx you would want to do:
import MyCustomPagerComponent from 'path/to/component';
<Griddle
...
customPagerComponent={MyCustomPagerComponent}
>
Both next and previous button will come in this new custom pagination component.
More info on this Griddle Issue
https://github.com/GriddleGriddle/Griddle/issues/530