I need to add bootstrap effect fadeInDown to a newly added comment in my comments section.
It works but unfortunately it affects all of the comments when I reload the page and the effect is also added when I edit a comment.
Is it possible to add this specific class only to newly created comment? not affecting the rest of comments nor the other application functionalities?
I will be glad for any advice
This is my comment section:
Comment section
This is the structure of my files: Files structure
These are the components I'm working on:
Comment section HTML
<h6>Comments: ({{commentsCount}})</h6>
<app-new-comment class="d-block mt-3" [requestId]="requestId" (update)="updateComments()">
</app-new-comment>
<app-comment *ngFor="let comment of comments; let i = first"
[ngClass]="{'fadeInDown': i}"
class="d-block mt-3 animated"
[comment]="comment"
(update)="updateComments()"></app-comment>
Comment section TS
export class CommentSectionComponent implements OnInit, OnDestroy {
#Input() requestId: string
comments: CommentDetailsDto[]
commentsCount = 0
private subscription: Subscription
constructor(
private commentsService: CommentsService,
private alert: AlertService
) {
}
ngOnInit(): void {
this.updateComments()
}
ngOnDestroy(): void {
this.unsubscribe()
}
updateComments(): void {
this.unsubscribe()
this.subscription = this.commentsService.getComments(this.requestId)
.subscribe({
next: (comments: CommentDetailsDto[]) => {
this.comments = comments.reverse()
this.commentsCount = this.getCommentsCount(comments)
},
error: (error: HttpErrorResponse) => {
this.alert.handleHttpError(error)
}
})
}
private getCommentsCount(comments: CommentDetailsDto[]): number {
return comments.reduce(
(cnt, comment) => cnt + 1 + (comment.replies ? this.getCommentsCount(comment.replies) : 0),
0
)
}
private unsubscribe(): void {
if (this.subscription instanceof Subscription) {
this.subscription.unsubscribe()
}
}
}
Comment section SCSS
#keyframes fadeInDown {
from {
opacity: 0;
transform: translate3d(0, -100%, 0);
}
to {
opacity: 1;
transform: translate3d(0, 0, 0);
}
}
.fadeInDown {
animation-name: fadeInDown;
}
New comment component HTML
<div class="d-flex">
<app-user-image class="mr-3"></app-user-image>
<textarea #textArea class="d-block" placeholder="Add comment" [(ngModel)]="newComment">
</textarea>
</div>
<div class="text-right mt-3">
<button class="btn btn-primary font-weight-bold px-5" type="button"
[disabled]="!newComment" (click)="submit()">
Post
</button>
</div>
New comment TS
export class NewCommentComponent implements OnInit {
#ViewChild('textArea') textArea: ElementRef<HTMLTextAreaElement>
#Input() requestId?: string
#Input() comment?: CommentDetailsDto
#Output() update = new EventEmitter()
newComment: string
private readonly commentResponseObserver = {
error: (error: HttpErrorResponse) => {
this.alert.handleHttpError(error)
},
complete: () => {
delete this.newComment
this.update.emit()
this.alert.showSuccess('Comment submitted successfully')
}
}
constructor(
private commentsService: CommentsService,
private alert: AlertService,
private route: ActivatedRoute
) {
}
ngOnInit(): void {
if (this.comment) {
this.textArea.nativeElement.focus()
}
}
submit(): void {
if (this.requestId) {
this.addComment()
} else if (this.comment) {
this.addReply()
}
}
addComment(): void {
if (this.newComment) {
this.commentsService.addComment(this.requestId, this.newComment)
.subscribe(this.commentResponseObserver)
}
}
addReply(): void {
if (this.newComment) {
this.commentsService.addReply(this.route.snapshot.queryParamMap.get('requestId'), this.comment, this.newComment)
.subscribe(this.commentResponseObserver)
}
}
}
Comment component HTML
<div class="comment">
<app-user-image></app-user-image>
<div class="position-relative d-inline-block flex-fill">
<div class="d-flex justify-content-between align-items-center">
<div><strong>{{comment.author.name}} / {{comment.author.id}}</strong><span
class="date">{{comment.created | krakenDateTime}}</span></div>
<div class="actions">
<button *ngIf="this.hateoas.supports(comment, 'update') && !edit"
type="button" class="bg-transparent border-0" title="Edit"
(click)="toggleEdit()"><i class="icon-kraken icon-kraken-edit"></i></button>
<button *ngIf="this.hateoas.supports(comment, 'delete')"
type="button" class="bg-transparent border-0" title="Delete"
(click)="displayDeletionConfirmation()"><i class="icon-kraken icon-kraken-trash"></i></button>
</div>
</div>
<textarea *ngIf="edit; else readonlyComment"
#textarea
class="d-block w-100"
style="min-height: 7rem;"
[rows]="rows()"
[(ngModel)]="commentContent"></textarea>
<ng-template #readonlyComment>
<div [innerHTML]="commentContentHtml()"></div>
</ng-template>
<strong *ngIf="showReplyButton"
class="reply-button"
(click)="toggleReplyComponent()">Reply</strong>
</div>
</div>
<div *ngIf="edit" class="animated fadeIn text-right mt-3">
<button class="btn btn-sm discard" (click)="cancelEdit()">Discard</button>
<button class="btn btn-sm ml-2 update" (click)="updateComment()">Update</button>
</div>
<div class="replies">
<app-new-comment *ngIf="showNewReplyWindow"
class="d-block mt-3"
[comment]="comment"
(update)="this.update.emit()"></app-new-comment>
<app-comment *ngIf="firstReply"
class="d-block my-3"
[comment]="firstReply"
(update)="update.emit()"></app-comment>
<div *ngIf="moreReplies.length" class="replies-toggle" (click)="showMoreReplies =
!showMoreReplies">
<div class="horizontal-bar"></div>
<span class="mx-3">{{showMoreReplies ? 'Hide' : 'See'}} {{moreReplies.length}} more
comments</span>
<div class="horizontal-bar"></div>
</div>
<div *ngIf="showMoreReplies">
<app-comment *ngFor="let reply of moreReplies"
class="d-block my-3"
[comment]="reply"
(update)="update.emit()"></app-comment>
</div>
<span id="temporaryLastRow"></span>
Comment TS
export class CommentComponent implements OnInit {
#ViewChild('textarea', {static: true}) textarea: ElementRef<HTMLTextAreaElement>
#Input() comment: CommentDetailsDto
#Output() update = new EventEmitter()
edit = false
showReplyButton = false
showNewReplyWindow = false
showMoreReplies = false
commentContent: string
firstReply: CommentDetailsDto
moreReplies: CommentDetailsDto[]
constructor(
private commentsService: CommentsService,
private modalFactoryService: ModalFactoryService,
public hateoas: HateoasService,
private alert: AlertService
) {
}
ngOnInit(): void {
this.commentContent = this.comment.content
this.showReplyButton = this.hateoas.supports(this.comment, 'reply')
this.moreReplies = this.comment.replies.reverse().slice(1)
this.firstReply = this.comment.replies[0]
}
toggleEdit(): void {
this.edit = !this.edit
}
updateComment(): void {
this.commentsService.updateComment(this.comment, this.commentContent)
.subscribe({
error: (error: HttpErrorResponse) => {
this.alert.handleHttpError(error)
},
complete: () => {
this.alert.showSuccess('Comment updated successfully')
this.update.emit()
}
})
}
cancelEdit(): void {
this.edit = false
this.commentContent = this.comment.content
}
displayDeletionConfirmation(): void {
this.modalFactoryService.openConfirmationModal(
'Delete Comment',
{
message: 'Are you sure you want to delete this comment?',
yesOptionButton: 'Yes',
noOptionButton: 'No'
},
() => {
this.hateoas.execute(this.comment, 'delete')
.subscribe({
error: (error: HttpErrorResponse) => {
this.alert.handleHttpError(error)
},
complete: () => {
this.alert.showSuccess('Comment deleted successfully')
this.update.emit()
}
})
}
)
}
toggleReplyComponent(): void {
this.showNewReplyWindow = !this.showNewReplyWindow
}
commentContentHtml(): string {
return this.commentContent.replace(/\n/g, '<br>')
}
rows(): number {
const newLines = this.commentContent.match(/\n/g) || []
return newLines.length + 1
}
}
export interface Author {
id: string
name: string
}
export interface CommentDetailsDto extends Resource {
content: string
author: Author
replies: CommentDetailsDto[]
created: string
}
Related
I manage to fetch the product data through the URL and when I am on the product details page there is a button that allows me to add the product to a sub-collection of the logged in user.
Below is what I want:
users/{userID}/shopping/{productID}
details-product.component.html displaying information in product details
<div class="uk-container panier" *ngIf="product">
<div id="modal-center" class="uk-flex-top" uk-modal>
<div class="uk-modal-dialog uk-modal-body uk-margin-auto-vertical">
<button class="uk-modal-close-default" type="button" uk-close></button>
<img [src]="(product | async)?.imageURL" class="nav-left">
</div>
</div>
<div class="uk-child-width-1-2#s" uk-grid>
<div>
<a href="#modal-center" uk-toggle>
<img [src]="(product | async)?.imageURL" class="nav-left" alt="">
</a>
</div>
<div>
<div class="uk-dark uk-padding">
<h3> {{ (product | async)?.name }}</h3>
<hr class="uk-divider-icon">
<div class="uk-flex prix">
<p class="uk-text">
<span>{{ (product | async)?.price | currency: 'XOF' }} </span>
</p>
</div>
<hr class="uk-divider-icon">
<button class="uk-button uk-button-default uk-form-width-medium" (click)="showDialog()">
<i class='bx bxs-cart-add'></i>
J'achète le produit
</button>
</div>
</div>
</div>
</div>
shopping-cart.service.ts
import { AngularFirestore, AngularFirestoreCollection } from '#angular/fire/compat/firestore';
import "firebase/auth";
import { User } from 'src/app/models/user.model';
import { Product } from 'src/app/models/product.model';
#Injectable({
providedIn: 'root'
})
export class ShoppingCardService {
userCollection: AngularFirestoreCollection<User>;
productsCollection: AngularFirestoreCollection<Product>;
constructor(private readonly dbstore: AngularFirestore) {
this.userCollection = this.dbstore.collection('users');
this.productsCollection = this.dbstore.collection('products');
}
addToMyCart(product: Product, userID: string, qteProduct: number) {
const userDoc = this.dbstore.firestore.collection('users').doc(userID);
const productDoc = this.dbstore.firestore.collection('products').doc(product.id);
const userShoppingProduct = userDoc.collection('shopping');
return userShoppingProduct.doc(product.id).set(product);
}
}
product.service.ts
import { Injectable } from '#angular/core';
import { AngularFirestore, AngularFirestoreCollection } from '#angular/fire/compat/firestore';
import { Router } from '#angular/router';
import { Observable } from 'rxjs';
import { Product } from 'src/app/models/product.model';
#Injectable({
providedIn: 'root'
})
export class ProductsService {
productCollection: AngularFirestoreCollection<Product>;
constructor(private dbstore: AngularFirestore, private router: Router) {
this.productCollection = this.dbstore.collection('products', (ref) =>
ref.orderBy('category', 'desc')
);
}
getDetailProduct(productId: string): Observable<any> {
return this.productCollection.doc(productId).valueChanges();
}
}
details-product.component.ts
import { ActivatedRoute } from '#angular/router';
import { Observable } from 'rxjs/internal/Observable';
import { User } from 'src/app/models/user.model';
import { Product } from 'src/app/models/product.model';
import { ProductsService } from '../../shared/services/products.service';
import { ShoppingCardService } from 'src/app/shared/services/shopping-card.service';
import { AngularFirestoreCollection } from '#angular/fire/compat/firestore';
import { AddToCartComponent } from './add-to-cart.component'
import { MatDialog } from '#angular/material/dialog';
#Component({
selector: 'app-details-product',
templateUrl: './details-product.component.html',
styleUrls: ['./details-product.component.css']
})
export class DetailsProductComponent implements OnInit {
quantity: number = 0;
productIdRoute: string;
isMyProduct: boolean = false;
product: Observable<Product>;
userCollection!: AngularFirestoreCollection<User>
constructor(
private route: ActivatedRoute,
private productService: ProductsService,
private shoppingCardService: ShoppingCardService,
private titleService: Title,
private dialog: MatDialog,
) {
const routeParams = this.route.snapshot.paramMap;
this.productIdRoute = String(routeParams.get('productId'));
this.product = this.productService.getDetailProduct(this.productIdRoute);
}
showDialog(): void {
const data = this.dialog.open(AddToCartComponent, {
width: '30rem',
data: { productID: this.productIdRoute },
});
console.log(data);
}
add-to-cart.component.ts
component in modal to confirm adding to cart
import { Component, OnInit, Inject } from '#angular/core';
import { MatDialog, MAT_DIALOG_DATA } from '#angular/material/dialog';
import { ShoppingCardService } from '../../shared/services/shopping-card.service';
import { Product } from 'src/app/models/product.model';
#Component({
selector: 'app-add-to-cart',
template: `
<div class="relative p-4 w-full max-w-md h-full md:h-auto">
<div class="p-6 text-center">
<svg aria-hidden="true" class="mx-auto mb-4 w-14 h-14 text-gray-400 dark:text-gray-200" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg>
<h3 class="mb-5 text-lg font-normal text-gray-500 dark:text-gray-400">Do you want to add this product?</h3>
<button (click)="onAddPubpik(data.product, data.userID)" type="button" class="text-white bg-gray-800 hover:bg-gray-800 focus:ring-4 focus:outline-none font-medium rounded-lg text-sm inline-flex items-center px-5 py-2.5 text-center mr-2">
Yes, i add to cart
</button>
</div>
</div>
`,
styleUrls: ['./details-product.component.css']
})
export class AddToCartComponent implements OnInit {
constructor(
#Inject(MAT_DIALOG_DATA) public data: { product: Product, userID: string, qteProduct: number },
private dialog: MatDialog,
private shoppingService: ShoppingCardService
) {}
ngOnInit(): void {
}
async onAddPubpik(product: Product, userID: string): Promise<void> {
this.dialog.closeAll();
const qteProduct = (product.quantity += 1);
product.isMyProduct = true;
await this.shoppingService.addToMyCart(product, userID, qteProduct);
}
}
When i confirm, in console :
On this line const qteProduct = (product.quantity += 1);, product is undefined. You’re not passing product to the matdialog component in your showDialog() method hence the error.
I have in this code a method openItem(anuncio, operacao)" that runs when I click on the object that will perform the action. In this case I don't understand why when running (click) = 'checkFavorite (advert) he also performs the action. Clicking the verifyFavorite action should only run it and not openItem. Could anyone help me? thanks !!!
<div class="ali-container">
<div class="ali-linha">
<div class="ali-capa-livro">
<button *ngIf="operacao !== vis" class="ali-capa-livro-btn" (click)="openItem(anuncio, operacao)">
<img src="{{anuncio.publicacao.imagem}}" width="40%" height="40%" />
</button>
<button *ngIf="operacao === vis" class="ali-capa-livro-btn">
<img src="{{anuncio.publicacao.imagem}}" width="40%" height="40%" />
</button>
</div>
<div class="ali-detalhes-livro">
<div class="ali-titulo-livro">{{anuncio.publicacao.titulo}}</div>
<div class="ali-autores-livro linha-unica-elipissis">{{anuncio.publicacao.autores}}</div>
<span class="ali-preco">{{anuncio.preco | currency:'R$':'code'}}</span>
<span class="ali-conservacao">({{anuncio.tipoConservacao}})</span>
<div class="ali-anunciante linha-unica-elipissis">por {{anuncio.usuario.nome}}</div>
<div class="ali-anunciante linha-unica-elipissis">{{anuncio.statusAnuncio}}</div>
<span>Anúncio: {{anuncio.tipoAnuncio.nome}} {{anuncio.tipoAnuncio.valor | currency:'R$':'code' }}</span>
</div>
<div *ngIf="operacao !== vis">
<button mode="ios" class="botao-excluir-anuncio" (click)="excluir(tipo, anuncio._id, favorito)" ion-button
round text-center item-end>
<ion-icon name="trash" item-end></ion-icon>
</button>
</div>
</div>
</div>
<div *ngIf="operacao === vis">
<div *ngIf="!anuncio.favorito">
<button mode="ios" class="botao-naoefavorito-anuncio" (click)='verificarFavorito(anuncio)' ion-button round
text-center item-end>
<ion-icon name="ios-heart-outline" item-end></ion-icon>
</button>
</div>
<div *ngIf="anuncio.favorito">
<button mode="ios" class="botao-favorito-anuncio" (click)='verificarFavorito(anuncio)' ion-button round
text-center item-end>
<ion-icon name="ios-heart" item-end></ion-icon>
</button>
</div>
<div *ngIf="apenasexcluir === 1">
<button mode="ios" class="botao-excluir-anuncio" (click)="excluir(tipo, anuncio._id, favorito)" ion-button round
text-center item-end>
<ion-icon name="trash" item-end></ion-icon>
</button>
</div>
</div>
import { Component, Input, Output, EventEmitter } from '#angular/core';
import { Anuncio } from '../../models/anuncio';
import { AppBasePage } from '../../pages/app-base-page/app-base-page';
import { AnuncioDetalhePage } from '../../pages/anuncio-detalhe/anuncio-detalhe';
import { NavController, NavParams } from 'ionic-angular';
import { AppGlobal } from '../../app/app.global';
import { AppRestService } from '../../services/app-rest.service';
import { RestNovoFavorito } from '../../services/app-rest.service';
#Component({
selector: 'anuncio-list-item',
templateUrl: 'anuncio-list-item.html'
})
export class AnuncioListItemComponent extends AppBasePage {
#Input('anuncio') anuncio: Anuncio;
#Input('tipo') tipo: any;
#Input('favorito') favorito: any;
#Input('cesta') cesta: any;
#Input('operacao') operacao: any;
#Input('apenasexcluir') apenasexcluir: any;
#Output() onExcluir: EventEmitter<any> = new EventEmitter();
#Output() onDetail: EventEmitter<any> = new EventEmitter();
constructor(private rest: AppRestService, private appGlobal: AppGlobal, public navCtrl: NavController, public navParams: NavParams) {
super();
}
openItem(anuncio, operacao, apenasexcluir) {
// quando origem cesta, chama com o parametro para atualizar a cesta de acordo com o anuncio alterado
if (this.cesta) this.navCtrl.push(AnuncioDetalhePage, { anuncio: anuncio, operacao: operacao, apenasexcluir: apenasexcluir, cesta: this.cesta });
else this.navCtrl.push(AnuncioDetalhePage, { anuncio: anuncio, operacao: operacao, apenasexcluir: apenasexcluir});
}
excluir(tipo, id, favorito) {
if (tipo == 1) {
this.onExcluir.emit(favorito);
} else
this.onExcluir.emit(id);
}
verificarFavorito(id) {
if (id.favorito) {
this.excluirFavorito(id.favorito._id)
} else {
this.incluirFavorito(id._id)
}
}
async excluirFavorito(id) {
await this.rest.excluirAnuncioFavorito(id);
}
async incluirFavorito(id) {
let restNovoFavorito = new RestNovoFavorito();
restNovoFavorito.anuncio = id;
await this.rest.incluirFavorito(restNovoFavorito);
}
}
I'm new to angular and I tried to make an accordion component, and it' didn't work like I wanted it to, here's my html code.
<div class="faq-item-container">
<h1 class="mt-1 mb-5"><strong>Frequently Aksed Questions</strong></h1>
<div class="row" (click)="toggleDetail(); toggleIcon();" *ngFor= "let faq of faqs">
<div class="col my-2">
<h3> {{faq.title}} <a><fa-icon [icon]="faChevronDown" class="float-right"></fa-icon></a></h3>
</div>
<div class="col-12" *ngIf="showDetail">
<div class="faq-detail-container mt-1">
<div class="col-12">
<p><small>
{{faq.content}}
</small></p>
</div>
</div>
</div>
</div>
</div>
and here's the ts code
import { Component, OnInit } from '#angular/core';
import {faChevronUp, faChevronDown, IconDefinition, faSquare} from '#fortawesome/free-solid-svg-icons';
#Component({
selector: 'app-jobs-faq',
templateUrl: './jobs-faq.component.html',
styleUrls: ['./jobs-faq.component.scss']
})
export class JobsFaqComponent implements OnInit {
faChevronUp: IconDefinition = faChevronUp;
faChevronDown: IconDefinition = faChevronDown;
showDetail: boolean;
faqs = [
{
id: 1,
title: 'faq1',
content: 'content1'
},
{
id: 2,
title: 'faq2',
content: 'content2'
},
{
id: 3,
title: 'faq3',
content: 'content3'
}
];
constructor() {
this.showDetail = false;
}
toggleDetail(): void {
this.showDetail = !this.showDetail;
}
toggleIcon() {
if (this.faChevronDown === faChevronDown) {
this.faChevronDown = faChevronUp;
} else {
this.faChevronDown = faChevronDown;
}
}
ngOnInit() {
}
}
The problem is when I click faq1, the others also collpasing, yes I know it's because I called the same function, and that is what I want to ask about, how to call the function separately to make this accordion working like it's supposed to be? thanks.
It depends on whether you want to close all other sections when you click one or not, but a solution could look somewhat like this:
<div class="faq-item-container">
<h1 class="mt-1 mb-5"><strong>Frequently Aksed Questions</strong></h1>
<div class="row" (click)="toggleDetail(faq.id); toggleIcon();" *ngFor= "let faq of faqs">
<div class="col my-2">
<h3> {{faq.title}} <a><fa-icon [icon]="faChevronDown" class="float-right"></fa-icon></a></h3>
</div>
<div class="col-12" *ngIf="faq.showDetail">
<div class="faq-detail-container mt-1">
<div class="col-12">
<p><small>
{{faq.content}}
</small></p>
</div>
</div>
</div>
</div>
</div>
import { Component, OnInit } from '#angular/core';
import {faChevronUp, faChevronDown, IconDefinition, faSquare} from '#fortawesome/free-solid-svg-icons';
#Component({
selector: 'app-jobs-faq',
templateUrl: './jobs-faq.component.html',
styleUrls: ['./jobs-faq.component.scss']
})
export class JobsFaqComponent implements OnInit {
faChevronUp: IconDefinition = faChevronUp;
faChevronDown: IconDefinition = faChevronDown;
faqs = [
{
id: 1,
title: 'faq1',
content: 'content1',
showDetail: false
},
{
id: 2,
title: 'faq2',
content: 'content2',
showDetail: false
},
{
id: 3,
title: 'faq3',
content: 'content3',
showDetail: false
}
];
toggleDetail(faqId: number): void {
this.faqs = this.faqs.map(faq => {
faq.showDetail = (faq.id == faqId) ? !faq.showDetail : false;
return faq;
});
}
toggleIcon() {
if (this.faChevronDown === faChevronDown) {
this.faChevronDown = faChevronUp;
} else {
this.faChevronDown = faChevronDown;
}
}
ngOnInit() {
}
}
Note that your [icon]="faChevronDown" should be based on the faq in the thes scope of your *ngFor. I'll leave it to you as practice to find a solution for that. (Hint: you could use a ternary operation based on faq.showDetail)
I need to show the data I'm fetching, but none is showing, I tried ngIf and ngFor
I'm using angular 6, and trying to display data from movies in the Html, but data seems to be empty, I tried a lot of solutions but none seems to work.
<app-logo></app-logo>
<app-options></app-options>
<div style="display:none;" id="root"></div>
<div class="col s6">
<button routerLink="/halfhour" (click)=searchData() class="options" id="menos-30-min" value="25 min">Menos de 30 min</button>
</div>
<div *ngIf="data?.data">
<ng-container *ngFor="let data of data">
<div class="row">
<div class="col s5">
<img class="backgrounds" src="{{data?.Poster}}">
<div class="background" style="background-image: url({{data?.Poster}}); background-size: cover; background-position: center center; background-repeat: no-repeat; background-attachment: fixed; height:300px; width: 100%;"></div>
</div>
<div class="col s7">
<div class="information">
<p class="title">Title: {{data?.Title}}</p>
<p class="runtime">Runtime: {{data?.Runtime}}</p>
<p class="other-data">Year: {{data?.Year}}</p>
<p class="other-data"> Genre: {{data?.Genre}}</p>
<p class="resumen"> Plot: {{data?.Plot}}</p>
<p class="other-data"> Tipo: {{data?.Type}}</p>
</div>
</div>
</div>
</ng-container>
</div>
<h1>{{id}}</h1>
#Component({
selector: 'app-half-hour',
templateUrl: './half-hour.component.html',
styleUrls: ['./half-hour.component.css']
})
export class HalfHourComponent implements OnInit {
constructor(private http: Http) {
}
data: any [];
id;
getRandom() {
const omdbData = ['0386676', '1865718', '0098904', '4508902', '0460649', '2861424', '0108778', '1305826', '0096697', '0149460'];
const randomItem = omdbData[Math.floor(Math.random() * omdbData.length - 1) + 1];
return this.id = randomItem;
}
searchData() {
this.getRandom();
this.http
.get('https://cors-anywhere.herokuapp.com/http://www.omdbapi.com/?i=tt' + this.id + '&apikey=')
.pipe(map((res: Response) => res.json()))
.subscribe(data => {
this.data = Array.of(this.data);
console.log(data);
console.log(this.id);
});
}
ngOnInit() {
}
}
The properties of data show as empty.
HTTP request call should be added inside ngOninit(). Here is the updated code
ngOnInit(){
this.data = [];
this.getRandom();
this.http
.get('https://cors-anywhere.herokuapp.com/http://www.omdbapi.com/?i=tt' + this.id + '&apikey=')
.pipe(map((res: Response) => res.json()))
.subscribe(data => {
this.data = (data) ? data.slice() : [];
console.log(data);
console.log(this.id);
});
}
I'm using Angular 5, and I wanted to press another button to get another button.
I do not know if I would have to use the ngIf, but I do not know how to identify the previous button.
example.ts
import { Component, OnInit } from '#angular/core';
import { Hero } from '../hero';
import { HeroService } from '../hero.service';
#Component({
selector: 'app-heroes',
templateUrl: './heroes.component.html',
styleUrls: ['./heroes.component.css']
})
export class HeroesComponent implements OnInit {
heroes: Hero[];
constructor(private heroService: HeroService) { }
ngOnInit() {
this.getHeroes();
}
getHeroes(): void {
this.heroService.getHeroes()
.subscribe(heroes => this.heroes = heroes);
}
add(name: string): void {
name = name.trim();
if (!name) { return; }
this.heroService.addHero({ name } as Hero)
.subscribe(hero => {
this.heroes.push(hero);
});
}
delete(hero: Hero): void {
this.heroes = this.heroes.filter(h => h !== hero);
this.heroService.deleteHero(hero).subscribe();
}
}
example.html
<ul class="heroes">
<li *ngFor="let hero of heroes">
<a routerLink="/detail/{{hero.id}}">
<span class="badge">{{hero.id}}</span> {{hero.name}}
</a>
<button class="delete" title="delete hero" (click)="delete(hero)">x</button>
</li>
</ul>
In your component.ts:
#Component({
selector: 'app-heroes',
templateUrl: './heroes.component.html',
styleUrls: ['./heroes.component.css']
})
export class HeroesComponent implements OnInit {
heroes: Hero[];
showSecondButton: boolean = false;
constructor(private heroService: HeroService) { }
ngOnInit() {
this.getHeroes();
}
delete(hero: Hero): void {
this.heroes = this.heroes.filter(h => h !== hero);
this.heroService.deleteHero(hero).subscribe();
this.showSecondButton = true;
}
}
In your html:
<ul class="heroes">
<li *ngFor="let hero of heroes">
<a routerLink="/detail/{{hero.id}}">
<span class="badge">{{hero.id}}</span> {{hero.name}}
</a>
<button class="delete" title="delete hero" (click)="delete(hero)">x</button>
<button *ngIf="showSecondButton"> Your second button</button>
</li>
</ul>
so your best bet is to create two buttons within a div, then have a toggle that switches the button that is displayed.
Example:
<div>
<button *ngIf=!displaysecondbutton (click)='showsecondbutton()'>First Button Yo</button>
<button *ngIf=displaysecondbutton>SecondButtonYo</button>
</div>
typescript file;
displaysecondbutton = false;
showsecondbutton(){
this.displaysecondbutton = true;
}
To keep the code concise I would implement an if statement in your delete function:
public deleteConfirmed = false;
public confirmDelete = false;
delete(hero: Hero): void {
if (deleteConfirmed) {
confirmDelete = deleteConfirmed = false;
this.heroes = this.heroes.filter(h => h !== hero);
this.heroService.deleteHero(hero).subscribe();
}
else{
confirmDelete = true;
}
}
Then in your html:
<button class="delete" title="delete hero" (click)="delete(hero)">Delete</button>
<button *ngIf="confirmDelete" class="delete" title="delete hero" (click)="deleteConfirmed=true; delete(hero)">Confirm Deletion</button>
This way, you are always cycling the same function and just altering some states along the way.