Trigger animation after page load in angular 8, ExpressionChangedAfterItHasBeenCheckedError - css

As the question suggests, I am trying to figure out a way to get an element animated after the page has been loaded. I have looked all over the place but there seem to be too many and no way to do this at the same time, I am hoping for some guidance. After the page is loaded in mobile the the logo should slowly animate towards the top-right and also scale down in size, if that makes sense.
I am looking for the Angular equivalent of $(document).ready(function() {}
As per suggestions, I have used ngAfterViewInit() but I still cannot get anything to work.
Below the index-section.component.html
<section class="index-section">
<div [#logoMoveResize]="load_completed ? 'initial' : 'end'" class="index-logo-wrapper" [class.hideOnLoad]="isTrue">
<figure>
<img src="assets/icons/logo_mobile.svg" alt="urbanwheels logo">
</figure>
</div>
<div class="index-media-wrapper">
<div class="media-container">
<iframe src="https://player.vimeo.com/video/128014070?autoplay=1&color=ffffff&title=0&byline=0&portrait=0" frameborder="0" allow="autoplay; fullscreen" allowfullscreen></iframe>
</div>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Itaque contra est, ac dicitis; Duo Reges: constructio interrete. Videsne quam sit magna dissensio?
</p>
</div>
</section>
And the index-section.component.ts
import { Component, OnInit, Inject, ViewChild } from '#angular/core';
import { trigger, state, animate, style, group, query, transition } from '#angular/animations';
#Component({
selector: 'app-index-section',
templateUrl: './index-section.component.html',
styleUrls: ['./index-section.component.scss'],
animations: [
trigger('logoMoveResize', [
state('initial', style({
transform: 'translateX(0%) translateY(0%) scale(1)',
})),
state('end', style({
transform: 'translateX(25%) translateY(-25%) scale(.3)',
})),
transition('initial <=> end', [animate('1s')]),
])
]
})
export class IndexSectionComponent implements OnInit {
load_completed = true;
innerWidth: any;
ngOnInit() {
this.innerWidth = window.innerWidth;
}
ngAfterViewInit() {
if ( this.innerWidth < 1000 ) {
this.load_completed = false;
}
}
}
This the error I am getting:

set a variable in component.ts
#Component({
selector: 'app-some',
templateUrl: './some.component.html',
styleUrls: ['./some.component.scss'],
animations: [
trigger('fadeInOut', [
state('void', style({
opacity: 0
})),
transition('void <=> *', animate(1000)),
]),
trigger('EnterLeave', [
state('flyIn', style({ transform: 'translateX(0)' })),
transition(':enter', [
style({ transform: 'translateX(-100%)' }),
animate('0.5s 300ms ease-in')
]),
transition(':leave', [
animate('0.3s ease-out', style({ transform: 'translateX(100%)' }))
])
])
]
})
export class SomeComponent implements OnInit {
load_completed = false;
ngOnInit(){
}
ngAfterViewInit(){
load_completed = true;
}
}
And in you component.html
<div [#fadeInOut]="load_completed"> some random element you want to animate </div>
As above example you can just animate when you need based on the condtion

This answer has provided me with info I need in regards to the question. As #Kevin LeStarge suggested my work around was:
setTimeout(()=> {
this.load_completed = true;
}, 0);
Or as #Lijo suggests using the AfterContentChecked life cycle hook:
import { ChangeDetectorRef, AfterContentChecked} from '#angular/core';
constructor(
private cdref: ChangeDetectorRef) { }
ngAfterContentChecked() {
this.cdref.detectChanges();
this.load_completed = true;
}

use ngAfterViewInit hook of angular to apply animation to the element.

I am looking for the Angular equivalent of $(document).ready(function() {}
the equivalent is
constructor(private zone: NgZone) {
this.zone.onStable.pipe(
// don't keep the stream open
first()
).subscribe(() => /* zone is stable, do something */)
}

You can use Angular Resolve - Interface that classes can implement to be a data provider. A data provider class can be used with the router to resolve data during navigation. The interface defines a resolve() method that will be invoked when the navigation starts. The router will then wait for the data to be resolved before the route is finally activated.
For more details -
https://angular.io/api/router/Resolve

Related

How do I implement paging (JwPaginationModule) in my Ionic app?

I have a list with cars. Now I want to integrate paging because of the many records.
This is my ListViewPageModule in which I imported JwPagingationModule:
import { NgModule } from '#angular/core';
import { CommonModule } from '#angular/common';
import { FormsModule } from '#angular/forms';
import { JwPaginationModule } from 'jw-angular-pagination';
import { IonicModule } from '#ionic/angular';
import { ListViewPageRoutingModule } from './list-view-routing.module';
import { ListViewPage } from './list-view.page';
import { ComponentsModule } from '../components.module';
#NgModule({
imports: [
CommonModule,
FormsModule,
IonicModule,
ComponentsModule,
ListViewPageRoutingModule,
JwPaginationModule
],
declarations: [ListViewPage]
})
export class ListViewPageModule {}
My Component:
#Component({
selector: 'app-list-view',
templateUrl: './list-view.page.html',
styleUrls: ['./list-view.page.scss'],
})
export class ListViewPage implements OnInit {
structureGroups: StructureGroup[] = [];
lablesHeadlines = lablesHeadlines;
headlines = lablesHeadlines;
pageOfItems: Array<any>;
constructor(private listClientService: ListClientServiceService, private router: Router) { }
ngOnInit() {
this.listClientService.getAllCarGroupNamesWithId().subscribe(
(response) => {
this.carGroups = response;
return response;
});
}
openCarGroup(id: number) {
this.router.navigate(['/detail-view', { carGroupId: id }]);
}
onChangePage(pageOfItems: Array<any>) {
// update current page of items
this.pageOfItems = pageOfItems;
}
}
My HTML:
1 <ion-content>
2 <ion-list id="list">
3 <ion-item id="list-item" button *ngFor="let carGroup of carGroups"
4 (click)="openCarGroup(carGroup.id)">
5 <ion-label>{{carGroup.carGroupName}}</ion-label>
6 </ion-item>
7 </ion-list>
8 <div class="card-footer pb-0 pt-3">
9 <jw-pagination [carGroups]="carGroups" (changePage)="onChangePage($event)"></jw-pagination>
10 </div>
</ion-content>
My CSS
.card-footer{
width: 100%;
height: 10%;
position: absolute;
bottom: 10px;
}
I am unfortunately still very inexperienced when it comes to working with ionic and Angular. Currently I get the error:
NG0303: Can't bind to 'carGroups' since it isn't a known property of 'jw-pagination'.
This error comes from my HTML file line 9.
Question 1: How can I fix the error?
Question 2: How do I include Pagination correctly in my component? In my ngOnInit() I will have to integrate Pagination as well or?
Question 3: Currently I get "<jw-pagination [carGroups]="carGroups" (changePage)="onChangePage($event)">"
is not displayed. The div has the desired area at the end of the page but I don't see the PageController there. How can I make it visible?
According to the documentation, you should provide your data as items attribute like so:
<jw-pagination [items]="carGroups" (changePage)="onChangePage($event)"></jw-pagination>
This guide might be helpful.
https://edupala.com/how-to-implement-ionic-table-with-pagination/

AnimeJs implementation with react doesn't work

I've implemented a simple Anime Js text animation into my react app; I have other other Anime Js projects which perform perfectly but I just don't see the issue with this one, and why it doesn't work.
TextColourChangeLoader.js
import React from 'react';
import './styles/TextColourChangeLoader.css';
import anime from 'animejs';
export default class TextColourChangeLoader extends React.Component {
constructor(props) {
super(props);
this.state = {
text: "",
play: false
}
}
componentDidMount() {
this.setState({
text: this.props.textToRender,
play: true
})
}
componentWillUnmount() {
this.setState({
text: '',
play: false
})
}
playAnimeColourChange = () => {
if(this.state.play) {
anime({
targets: '.loader-letter',
delay: anime.stagger(100),
duration: 1000,
scale: anime.stagger(2, {easing: "easeInElastic"}),
color: '#7DE2FC',
direction: 'alternate',
easing: 'easeInOutElastic(1,.8)',
loop: true,
loopComplete: function() {
console.log('done')
}
});
}
}
render() {
this.playAnimeColourChange();
return (
<div id="loader-text-holder">
{this.state.text.split('').map((letter, i) => {
return <span id={letter === " " ? "loader-letter-space" : "loader-letter"+i} key={i} className="loader-letter text">{letter}</span>
})}
{this.playAnimeColourChange()}
</div>
)
}
}
Example.js
import React from 'react';
import './styles/ViewLoaderWithText.css';
import anime from 'animejs';
import TextColourChangeLoader from './TextColourChangeLoader';
export default class ViewLoaderWithText extends React.Component {
constructor(props) {
super(props);
this.state = {
play: false
}
}
componentDidMount() {
this.setState({
play: true
})
}
playAnime = () => {
if(this.state.play) {
let loaderAnime = anime({
targets: '.view-loader-shape',
delay: anime.stagger(100, {start: -100}),
translateY: [{value: -25, easing: 'easeInCubic'}, {value: 0, easing: 'easeOutCirc'}],
background: '#7DE2FC',
direction: 'alternate',
easing: 'easeInOutElastic(1,.8)',
duration: 1000,
loop: true,
autoplay: true
});
}
}
render() {
return (
<div id="view-loader-wrapper">
<div id="loader-shape-holder">
<span className="view-loader-shape" id="view-loader-shape1"></span>
<span className="view-loader-shape" id="view-loader-shape2"></span>
<span className="view-loader-shape" id="view-loader-shape3"></span>
<span className="view-loader-shape" id="view-loader-shape4"></span>
<span className="view-loader-shape" id="view-loader-shape5"></span>
</div>
<TextColourChangeLoader textToRender="Verifying email"/>
{this.playAnime()}
</div>
)
}
}
The anime js instance in the Example.js file works as it should; however the TextColourChangeLoader.js animation doesn't run. I've tried logging to the console each time a loop completes with the loopComplete callback option, and it shows that the loop is running however, the animation doesn't. I've also tried only running the TextColourChangeLoader.js animation, but that still doesn't work. What could be a possible explanation for this? Anything helps.
I think that doesn't work because you are trying to animate a component that had not loaded first. Remember the lifecycle flow in React, I prefer use React Hooks to solve the problem and this is the way: with the useEffect hook you pass in the animate function, in order to first render the component and then execute the function, not in the reverse order. I guess that the equivalent in class components is componentDidMount() so try to refactorize your code in order to connect the anime() with the componentDidMount. Conclusion, the main concept is first render the component and then execute the anime(). Sorry for my english level.

css-in-javascript use in a React component

According to this reference https://github.com/airbnb/javascript/tree/master/css-in-javascript, a styled JS component should be written like this:
function MyComponent({ styles }) {
return (
<div {...css(styles.container)}>
Never doubt that a small group of thoughtful, committed citizens can
change the world. Indeed, it’s the only thing that ever has.
</div>
);
}
export default withStyles(() => ({
container: {
display: 'inline-block',
},
}))(MyComponent);
I'm trying to write a simple React component like following, without success (I'm receiving a withStyles is not defined error):
import React from 'react';
const MyComponent = ({styles}) => {
return (
<div {...css(styles.container)}>Hello World</div>
)
}
export default withStyles(() => ({
container: {
color: 'red'
},
}))(MyComponent);
What am I doing wrong? Is it possible to use this convention for a React component?
You can do it like this
const divStyle = {
color: 'blue',
fontSize:10px
};
function HelloWorldComponent() {
return <div style={divStyle}>Hello World!</div>;
}
However you can try other better approaches.Please refer to the link below:
https://medium.com/#aghh1504/4-four-ways-to-style-react-components-ac6f323da822

Manage state of animation trigger in angular2 routing

I am faceing an issue with angular2 animation. App has a guide system where User navigate from step 1 to step 2 and so on. Now i have animation on routing where my first component slide to left and second come from right side and this is same for every step, this flow works very well but i want to reverse it when user go back to previous step then i want that current component should slide to right and previous component should slide in from left side.
animation.ts
import {trigger, state, animate, style, transition} from '#angular/animations';
export const routeAnimation =
trigger('routeAnimation', [
state('void', style({position: 'absolute', width: '100%', top: '150px', left: '20px'})),
state('*', style({position: 'absolute', width: '100%', top: '150px', left: '20px'})),
transition(':enter', [
style({transform: 'translateX(100%)'}),
animate('0.5s ease-in-out', style({transform: 'translateX(0%)'}))
]),
transition(':leave', [
style({transform: 'translateX(0%)'}),
animate('0.5s ease-out', style({transform: 'translateX(-100%)'}))
])
]);
Components to animate while route
import {Component, HostBinding} from '#angular/core';
import {routeAnimation} from './animation';
import {state} from '#angular/animations';
#Component({
template: `<h1>first</h1>`,
animations: [routeAnimation]
})
export class FirstComponent {
#HostBinding('#routeAnimation') routerTransition = true;
}
#Component({
template: `<h1>second</h1>`,
animations: [routeAnimation]
})
export class SecondComponent {
#HostBinding('#routeAnimation') routerTransition = true;
}
#Component({
template: `<h1>third</h1>`,
animations: [routeAnimation]
})
export class ThirdComponent {
#HostBinding('#routeAnimation') routerTransition = true;
}
#Component({
template: `<h1>fourth</h1>`,
animations: [routeAnimation]
})
export class FourthComponent {
#HostBinding('#routeAnimation') routerTransition = true;
}
Thanks in advance.

Angular 2 two-way component binding doesn't call parent ngOnChange

I have created a plunker here:
http://plnkr.co/edit/8bwqkYQ6tqrpGwHT588y?p=preview
that shows the issue.
Basically, I have 2 components. The first component has a 2-way binding of a property to the child component.
My parent component is:
import { Component, Input, Output, EventEmitter } from '#angular/core'
import { ChildComponent } from "./childComponent"
#Component({
selector: 'parentComponent',
template: `
<div>
Reset<br>
<div>Parent SelectedId: {{selectedId}}</div>
<childComponent [(selectedId)]="selectedId"></childComponent>
</div>
`,
directives: [ChildComponent]
})
export class ParentComponent {
#Input() selectedId: number;
ngOnChanges(changes) {
console.log("Parent changes called!");
}
}
and my child component:
import { Component, Input, Output, EventEmitter } from '#angular/core'
#Component({
selector: 'childComponent',
template: `
<div>
<div>Child SelectedId: {{selectedId}}</div>
</div>
`,
directives: []
})
export class ChildComponent {
#Input() selectedId: number;
#Output() selectedIdChange: EventEmitter<number> = new EventEmitter<number>();
constructor() {
setTimeout(() => {
this.selectedId = 100;
this.selectedIdChange.emit(this.selectedId);
}, 2000);
}
ngOnChanges(changes) {
console.log("Child changes called!");
}
}
In the child, I set a timeout to change the value of selectedId programmatically after 2 seconds, then emit the value back to the parent.
This all works great, except for one thing... the ngOnChange of the parent is only being called once.
I would think that the parent would very much like to know if the child has changed the value, or else what is the point of 2 way binding??
What am I missing here?
The ngOnChange of the parent will only be called if App's selectedId changes, since that's what ParentComponent's input property is bound to.
If you want the parent to be notified of changes made in the child, bind to the xChange event (where x is the name of the input property) – i.e., break up the property and event bindings:
<childComponent [selectedId]="selectedId" (selectedIdChange)="changed($event)"></childComponent>
changed(newValue) {
console.log('newValue', newValue);
this.selectedId = newValue;
}
Plunker

Resources