I have a todo list app that I wrote in angular and I wanted to fade in each todo, when it is created and fade them out before they are deleted. I was only able to get the fade in effect to work, if I apply the effect in the todo-item component, however the fade out effect wouldn't work. I've tried adding the animation to the parent todos component however, that doesn't work for either the fade in or fade out.
todos.component.ts (parent container of todo-items)
animations: [
trigger('fade', [
transition('void => *', [
style({opacity: 0}),
animate(1000, style({opacity: 1}))
]),
transition('* => void', [
animate(1000, style({opacity: 0}))
])
])
]
})
export class TodosComponent implements OnInit {
todos:Todo[];
constructor(private todoService:TodoService) {
}
ngOnInit() {
this.todoService.getTodos().subscribe(todos=> { this.todos = todos});
}
deleteTodo(todo:Todo){
this.todos.splice(this.todos.indexOf(todo), 1);
this.todoService.deleteTodo(todo).subscribe();
}
addTodo(todo:Todo){
this.todoService.addTodo(todo).subscribe(todo=>{
this.todos.push(todo);
})
}
}
todos.component.html (parent container of todo-items)
<app-add-todo (addTodo)="addTodo($event)"></app-add-todo>
<app-todo-item
@fade
*ngFor="let todo of todos"
[todo] = "todo"
(deleteTodo)="deleteTodo($event)"
>
</app-todo-item>
todo-item.component.ts
export class TodoItemComponent implements OnInit {
@Input() todo: Todo;
@Output() deleteTodo: EventEmitter<Todo> = new EventEmitter();
setClasses(){
let classes = {
todo: true,
'is-complete': this.todo.completed
}
return classes
}
onToggle(todo) {
todo.completed = !todo.completed;
this.todoService.toggleCompleted(todo).subscribe( todo => console.log(todo));
}
onDelete(todo){
this.deleteTodo.emit(todo);
}
constructor(private todoService:TodoService) { }
ngOnInit() {
}
}
todo-item.component.html
<div [ngClass] = "setClasses()">
<p>
<input (change)="onToggle(todo)" type="checkbox"/>
{{todo.title}}
<button (click)="onDelete(todo)" class="del">x</button>
</p>
</div>
In android, Fade In and Fade Out animations are used to change the appearance and behavior of the objects over a particular interval of time. The Fade In and Fade Out animations will provide a better look and feel for our applications.
The Fade In/Fade Out behavior lets you dissolve into and out of any object by ramping the opacity of the object from 0 percent to 100 percent at the start, and then back to 0 percent at the end. You can eliminate the fade-in or fade-out effect by setting the duration of the Fade In Time or Fade Out Time to 0 frames.
Definition and Usage The fadeOut() method gradually changes the opacity, for selected elements, from visible to hidden (fading effect). Note: Hidden elements will not be displayed at all (no longer affects the layout of the page). Tip: This method is often used together with the fadeIn() method.
In the CSS, use the @keyframes rule paired with fadeIn. At 0%, set the opacity to 0. At 100%, set the opacity to 1. This creates the fade-in effect.
For Animations I often use https://animista.net/ they offer simple animations in css.
To use them, you then only need to add the class to fade int, when clicking delete, you need to set the class for fading out - after the animation finished you really delete the object with a timer.
When deleting you need to dynamically set it to another class something like that can work:
<div [className]="someValue"></div>
(from: https://malcoded.com/posts/angular-ngclass/)
When deleting you also need to create a timer, such that the element is only deleted after the animation finished. Example for a simple timer:
// repeat with the interval of 2 seconds
let timerId = setInterval(() => alert('tick'), 2000);
// after 5 seconds stop
setTimeout(() => { clearInterval(timerId); alert('stop'); }, 5000);
Hope it helps!
I have added one more field to ToDo
class, status
of perticular todo-item
.
Using this status
, we can transition the animation state by binding the status
property to @fade
Demo
Here, I am deleting any random item added in list.
todo-parent.component.ts
@Component({
selector: 'app-todo-parent',
templateUrl: './todo-parent.component.html',
styleUrls: ['./todo-parent.component.css'],
animations: [
trigger('fade', [
transition('void => active', [ // using status here for transition
style({ opacity: 0 }),
animate(1000, style({ opacity: 1 }))
]),
transition('* => void', [
animate(1000, style({ opacity: 0 }))
])
])
]
})
export class TodoParentComponent {
todoList: {str: string, status: string}[] = [];
addItem() {
this.todoList.push({str: 'added :' + this.todoList.length, status: 'active'});
}
deleteRandom() {
const num = Math.ceil(Math.random() * this.todoList.length);
this.todoList.splice(num, 1);
}
}
todo-parent.component.html
<div style="width: 250px">
<div *ngFor="let todo of todoList" [@fade]="todo.status"> <!-- using status here for transition -->
<app-todo-item [todoValue]="todo.str"></app-todo-item>
</div>
</div>
There is no need to do anything in your todo-item
component.
So I figured out the answer to my problem. The fade effect won't apply to component tags. So in my todos.component.html (parent todo-item container) I created a div to wrap my todo-item tag in; and I applied the trigger name to it.
my modified todos.component.html
<app-add-todo (addTodo)="addTodo($event)"></app-add-todo>
<div @fade *ngFor="let todo of todos">
<app-todo-item [todo] = "todo" (deleteTodo)="deleteTodo($event)">
</app-todo-item>
</div>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With