Using Angular, I wanted to make an animated display list. The problem is that I am getting this error:
Objects are in the array and show up on the screen, but are not animated.
This is what the HTML code looks like, where I iterate through the table and display the elements that I want to be slowly displayed (animation):
<section [#listAnimation]="articles.length">
<div *ngFor="let article of articles">
<div class="card border-0">
<div class="row no-gutters">
<div class="col-md-4 mt-3">
<div class="container-text-image">
<img [src]="article.mainImageSrc" onerror="this.onerror=null; this.src='..\..\..\assets\notFound.png';" class="card-img" [alt]="article.mainImageFullName">
<div class="label bottom-left">
<h3 class="label-text">
{{article.category}}
</h3>
</div>
</div>
</div>
<div class="col-md-8">
<div class="card-body">
<h5 class="card-title mt-0">{{article.title}}</h5>
<p *ngIf="article.description != null" class="card-text description-text">{{article.description}}</p>
</div>
</div>
</div>
</div>
</div>
</section>
This is what the animation code looks like in a component:
const listAnimation = trigger('listAnimation', [
transition('* <=> *', [
query(':enter',
[style({ opacity: 0 }), stagger('60ms', animate('600ms ease-out', style({ opacity: 1 })))],
),
query(':leave',
animate('200ms', style({ opacity: 0 })),
)
])
]);
#Component({
selector: 'app-articles',
templateUrl: './articles.component.html',
styleUrls: ['./articles.component.css'],
animations: [listAnimation]
})
Here's a snippet of code where I get my backend data into an array:
private fetchArticles = (): void => {
this.loaderService.show();
this.articlesService
.getPortalArticles(this.getArticlesParams())
.pipe(
finalize(() => {
this.setArticleMainImg();
this.loaderService.hide();
})
)
.subscribe(
(result) => {
this.articlesCount = result.totalItemsCount;
this.articles = result.items;
},
(error) => { }
);
}
Any ideas what might be causing the error? I realize that I can add {optional: true} to the animation code, but this will only get rid of the error and the animation will still not work.
Related
I have a problem loading a component inside another component. It just doesn't show , but in browser the route changes , but my component doesn't update...
So i have:
--homepage
--coins--
--coinspreview <-- i cannot access this component;
--services
app-component.html
<app-homepage>
</app-homepage>
app-homepage.html
<section id="home">
<div class="bg">
<img class="my-bg" src="/assets/images/bg.jpg">
</div>
<div class="container middle">
<div class="row">
<div class="col-lg-12 col-sm-12 col-12">
<div class="hero">
<h4 class="hero-title">
Top 100 Cryptocurrency
</h4>
</div>
</div>
</div>
</div>
</section>
<section id="coins">
<app-coins></app-coins>
//here it shows my another component
</section>
app-coins.html
<div class="container">
<div class="row justify-content-center align-items-center">
<div class="col-lg-3 col-md-4 col-sm-6 col-6" *ngFor="let coin of coins$ | async">
<div class="main" [routerLink]="['./coins/coins-preview']">
<img class="mini" src="{{coin.image}}" alt="{{coin.name}}" />
<div class="name">{{coin.name}}</div>
<div class="prices">
<p class="coin-price">
Pret actual: {{coin.current_price}}
</p>
<p class="coin-market-cap">
Capitalizare: {{coin.market_cap}}
</p>
</div>
</div>
</div>
</div>
</div>
And this are all my routes inside app-routing-module.
const routes: Routes = [
{
path: '',
redirectTo: 'homepage',
pathMatch: 'full'
},
{
path: 'homepage',
component: HomepageComponent
},
{
path: "coins",
component: CoinsComponent,
children: [
{
path: "coins/coins-preview",
component: CoinsPreviewComponent
}
]
}
];
I don't know what to do else.. Im so stuck but I cannot understand why It doesnt load ????
When defining the child route dont repeat the parent route name. That should make it working
What i am trying to do is add a row div after every 3 colum divs
Example Output need:
<div class="row">
<div class="col-md-6"></div>
<div class="col-md-6"></div>
<div class="col-md-6"></div>
</div>
I have an array of products i am iltrating like this
<div class="row" *ngFor="let p of relatedProperties;let i = index">
<div class="col-md-6" *ngIf="relatedProperties[i].title !== undefined">{{ relatedProperties[i].title }}</div>
<div class="col-md-6" *ngIf="relatedProperties[i].title !== undefined">{{ relatedProperties[i].title }}</div>
<div class="col-md-6" *ngIf="relatedProperties[i].title !== undefined">{{ relatedProperties[i].title }}</div>
</div>
But the problem is that my every row prints same title on one iltration and second on next iltration
Current output
<div class="row">
<div class="col-md-6">Title1</div>
<div class="col-md-6">Title1</div>
<div class="col-md-6">Title1</div>
</div>
<div class="row">
<div class="col-md-6">Title2</div>
<div class="col-md-6">Title2</div>
<div class="col-md-6">Title2</div>
</div>
<div class="row">
<div class="col-md-6">Title3</div>
<div class="col-md-6">Title3</div>
<div class="col-md-6">Title3</div>
</div>
Desired Output
<div class="row">
<div class="col-md-6">Title1</div>
<div class="col-md-6">Title2</div>
<div class="col-md-6">Title3</div>
</div>
<div class="row">
<div class="col-md-6">Title4</div>
<div class="col-md-6">Title5</div>
<div class="col-md-6">Title6</div>
</div>
<div class="row">
<div class="col-md-6">Title7</div>
<div class="col-md-6">Title8</div>
<div class="col-md-6">Title9</div>
</div>
If you split your Array into subarrays with always 3 titel's then you can easy loop through this Array in your template.
https://ng-run.com/edit/zZsztdvTOTpzbUC5Buuj?open=app%2Fapp.component.ts
component html
<div class="row" *ngFor="let row of newTitleArr; let i = index">
<div class="col" *ngFor="let col of newTitleArr[i]">{{ col.title }}</div>
</div>
component ts
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
titleArr = [
{ title: 'title1' },
{ title: 'title2' },
{ title: 'title3' },
{ title: 'title4' },
{ title: 'title5' },
{ title: 'title6' },
{ title: 'title7' },
{ title: 'title8' },
{ title: 'title9' },
{ title: 'title10' },
{ title: 'title11' },
{ title: 'title12' },
{ title: 'title13' },
];
newTitleArr:any[];
ngOnInit() {
this.newTitleArr = this.splitArr(this.titleArr, 3)
}
splitArr(arr, size) {
let newArr = [];
for(let i = 0; i< arr.length; i += size) {
newArr.push(arr.slice(i, i+size));
}
return newArr;
}
}
Maybe this works, but Im unsure
<ng-container *ngFor="let p of relatedProperties; let i = index">
<div class="row" *ngIf="(i + 1) / 3 === 1">
<div class="col-md-6" *ngIf="relatedProperties[i - 2].title != null">{{ relatedProperties[i].title }}</div>
<div class="col-md-6" *ngIf="relatedProperties[i - 1].title != null">{{ relatedProperties[i].title }}</div>
<div class="col-md-6" *ngIf="relatedProperties[i].title != null">{{ relatedProperties[i].title }}</div>
</div>
</ng-container>
Also, I gotta say this feels pretty hacky, but if this is what you request, this should work
edit:
Note that strict null (a == null) is better than checking for undefined (a === undefined), as it will check for both undefined or null. In your case title != null.
Also, you could build an iterable that holds the structure you want in a cleaner way.
instead of having [title1, title2, title3, title4, title5, title6...] you should try to have [[title1, title2, title3], [title4, title5, title6], ...] which is way cleaner and allows you to simply have two *ngFors inside your template
<element1 *ngFor="let innerArray of myArray; let i = index">
<element2 *ngFor="let title of innerAray; let j = index">
</element2>
</element1>
And finally, I suggest you avoid calling a variable 'p', that's bad practice.
You can use this to add a row after every 3 columns.
<ng-container *ngFor="let p of relatedProperties; let i = index">
<div class="row" *ngIf="(i%3)==0">
<div class="col-md-6" *ngFor="let p of relatedProperties.slice(i, i+3)>
<span *ngIf="relatedProperties[i].title !== undefined"> {{ relatedProperties[i].title }} </span>
</div>
</div>
</ng-container>
I am new to the Angular 8 framework. I am trying to implement animation using angular animations
Here is what the code looks like:
This component is in <div class="col-md-5"></div> as a parent div.
component.ts:
#Component({
selector: 'app-agent-bot',
templateUrl: './agent-bot.component.html',
styleUrls: ['./agent-bot.component.css'],
animations: [
trigger('bot_res_slide', [
transition('* => *', [
animate('2s', keyframes([
style({ transform: 'translate3d(-100%, 0, 0)', visibility: 'visible' }),
style({ transform: 'translate3d(0, 0, 0)' })
]))
])
])
]
})
component.html
<main>
<div class="bot shadow-sm" [ngStyle]="{height: botHeight}">
<div class="bot_header p-2 rounded-top">
<div class="row">
<div class="col-md-12">
<div class="color_blue">
<i class="fa fa-bandcamp" aria-hidden="true"></i>
<span class="ml-3">AGENT BOT</span>
</div>
</div>
</div>
</div>
<div class="bot_body rounded-bottom d-flex flex-column">
<div class="p-2">
<div class="bot_response" #bot_res_slide>
<div class="bot_response_msg">
Hello Agent! How may I help?
</div>
<div class="bot_response_msg_time">03:00pm</div>
</div>
<div class="user_response">
<div class="user_response_msg">
Hi..!
</div>
<div class="user_response_msg_time">03:01pm</div>
</div>
</div>
<div class="mt-auto d-flex border-top input_section">
<div class="canned_msg">
<img src="./../../../assets/icons/canned_icon.png" class="w-100 h-100">
</div>
<div class="h-100 w-100 border-left">
<input type="text" class="user_input" placeholder="Type here" />
</div>
<div class="send_msg_btn d-flex justify-content-center align-items-center px-3">
<i class="fa fa-paper-plane my-auto" aria-hidden="true"></i>
</div>
</div>
</div>
</div>
</main>
Here is what the output looks like:
The expected output is the animation should only work in the bot component and should not be displayed outside.
Where am I going wrong or where should I improve my code?
Add overflow: hidden to the message list container (.bot_body).
This will clip the child elements rendering outside the container
I do believe that your issue is in the way you've done a simple translateX job with the translate3d property. Your element is showing up from the far left because the syntax of transform3d(x, y, z) values and you've made it travel the whole page (100%). For a slide, I'd recommend changing to a transform: translateX(value) to use the best function for the job. As well as define the transform-origin to be aligned to the edge of your message/ bot container. #vishalbiswas also has a possible solution by using overflow: hidden on the containing element.
...
style({ transform: 'translateX(-100%)', visibility: 'visible' }),
style({ transform: 'translateX(0)' })
...
In CSS:
.bot-response {
overflow: hidden;
}
I want to animate from bottom when I click on link. Below is the image what I want to achieve. On click of Link whole "Red" section should be animated and come from the bottom side. To achieve that What I did is:
What I tried is:
#Component({
selector: 'mypage',
templateUrl: './mypage.component.html',
styleUrls: ['./mypage.component.scss'],
animations: [
trigger('slideInOut', [
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%)'
}))
])
])
],
});
animationState = "flyIn";
dataRefresh(id) {
this.animationState = 'flyIn';
}
<div [#slideInOut]="animationState">
<!-- Here is other page content, which I need to animate from bottom -->
<div class="col-lg-10 col-md-10 col-10" (click)="dataRefresh(id)">
<div class="row">
<div class="col-lg-12 col-md-12 col-12">
<div class="branch_row_padding">
<div class="">Name</div>
<div class="">Description</div>
</div>
</div>
</div>
</div>
</div>
By trying above, what happens only link div is animating from left side, I want to animate whole page.
What can be the possible solution for this?
Why not do it with just CSS?
relevant css:
.myAnimateClass{
border:1px solid red;display:block; animation: example 3s ease-in-out;
}
#keyframes example {
from {margin-left:-100%;}
to {margin-left:0;}
}
relevant TS:
import { Component } from '#angular/core';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
name = 'Angular 6';
show: boolean = true;
myAnimateClass: string = '';
resetClass() {
console.log("check");
setTimeout(() => {
this.myAnimateClass = 'myAnimateClass';
},100);
}
animatePage() {
if(this.myAnimateClass == 'myAnimateClass') {
this.myAnimateClass = 'something';
this.resetClass();
} else{
this.myAnimateClass = 'myAnimateClass';
}
}
}
relevant HTML:
<div [ngClass]='myAnimateClass'>
<hello name="{{ name }}"></hello>
<p>
Start editing to see some magic happen :)
</p>
<button type="button" (click)='animatePage()'>Animation page</button>
<div >
<!-- Here is other page content, which I need to animate from bottom -->
<div class="col-lg-10 col-md-10 col-10" (click)="dataRefresh(id)">
<div class="row">
<div class="col-lg-12 col-md-12 col-12">
<div class="branch_row_padding">
<div class="">Name</div>
<div class="">Description</div>
</div>
</div>
</div>
</div>
</div>
</div>
check working stackblitz here
Im getting the above error message but dont understand why as everything is defined as far as i can see.
Heres my html:
Apparently, the error occurs on line 1
<div *ngIf="pager.index < quiz.questions.length">
<h5 class="flow-text"><span [innerHTML]="quiz.questions[pager.index].text"></span></h5>
<br>
<div class="row text-left">
<div class="col s12 m12" *ngFor="let answer of quiz.questions[pager.index].answers">
<div class="answer">
<input type="checkbox" [checked]="answer.selected" (change)="onSelect(answer);"/><label class="black-text flow-text"> {{answer.text}} </label>
</div>
</div>
</div>
<footer class="row">
<div class="col s6 m6"></div>
<div class="col s6 m6">
<div *ngIf="pager.index < quiz.questions.length - 1">
<button id="nextButton" class="btn-flat black-text right flow-text" (click)="goTo(pager.index + 1);">Next</button>
</div>
<div *ngIf="pager.index == quiz.questions.length - 1">
<button id="nextButton" class="btn-flat black-text right flow-text" (click)="goTo(pager.index + 1);">Finish</button>
</div>
</div>
</footer>
</div>
<div *ngIf="pager.index == quiz.questions.length">
{{ selections }}
</div>
here is the component.ts
import { Component, OnInit, EventEmitter } from '#angular/core';
import { QuizService } from '../services/quiz.service';
import { Answer, Question, Quiz } from '../models/index';
import {MaterializeAction} from "angular2-materialize";
#Component({
selector: 'app-quiz',
templateUrl: './quiz.component.html',
styleUrls: ['./quiz.component.sass'],
providers: [QuizService]
})
export class QuizComponent implements OnInit {
quiz: Quiz;
pager = {
index: 0,
size: 1,
count: 1
};
selections: [string]
constructor(private quizService: QuizService) { }
ngOnInit() {
this.loadQuiz()
}
loadQuiz() {
this.quizService.get().subscribe(res => {
this.quiz = new Quiz(res);
this.pager.count = this.quiz.questions.length;
});
}
goTo(index: number) {
if (index >= 0 ) {
this.pager.index = index;
}
}
onSelect(answer: Answer) {
if (answer.selected = true) {
this.selections.splice(this.selections.indexOf(answer.text), 1);
} else {
this.selections.push(answer.text);
}
answer.selected = !answer.selected
}
}
i dont understand why its happening as despite the error compiling the code works and runs as it should, apart from the check boxes which i have asked in another question.
You should be using safe navigation operator in this case
*ngIf="pager.index < quiz?.questions?.length"
And
*ngIf="pager.index == quiz?.questions?.length"
It seems quiz variable is undefined, define it like this quiz: Quiz={}