I have component A button which displays form on click and component B button to show name. I want to trigger ComponentA button and display form when componentB button is clicked
componentA HTML
<section>
<button (click)="toggle()">Click Here To Search</button>
<div *ngIf="!showInput">
<input type="text"/><br/>
<button type="submit">Submit</button>
<button>Cancel</button>
</div>
</section>
componentA TS
showInput = true;
//...
toggle() {
this.showInput = !this.showInput;
}
componentB HTML
<button (click)="toggleText()">Add Fruit</button>
<div *ngIf="showText">Apple</div>
I have created an example.Please use this link
Example Link
Well in that case make use of rxjs BehaviorSubject in a service, so that your entire application can make use of the variable and will update accordingly, like below
import { Injectable } from '#angular/core';
import { BehaviorSubject } from 'rxjs';
#Injectable({
providedIn: 'root'
})
export class Service {
toggle: BehaviorSubject<boolean> = new BehaviorSubject(false);
toggle$ = this.toggle.asObservable();
}
and in your my text component
toggleText() {
this.showText = !this.showText;
this.service.toggle.next(this.showText)
}
and in your FormsComponent
showInput;
ngOnInit() {
this.service.toggle$.subscribe(
toggle => this.showInput = toggle
)
}
Working demo
Related
So I'm currently making an image that, when clicked, it expands using MatDialog. I'm currently creating a new component to make the MatDialog, however, one thing bugs me.
In my main component's HTML, I have the image as shown in the code below:
<section class="carousel" *ngIf="image">
<div class="container">
<div class="background">
<img class="image-src" [src]="image" alt="" (click)="openImage()" />
</div>
</div>
</section>
As seen, when the image is clicked, it triggers the openImage() in my typescript component:
openImage(){
this.dialog
.open(DialogExpandImageComponent)
.afterClosed()
.subscribe(() => console.log("test successful"))
}
My issue here is that, for the Dialog that expands the image, I'm creating another HTML and TS.
The TS code is currently as follows:
import { Component } from '#angular/core';
import { MatDialogRef } from '#angular/material/dialog';
#Component({
selector: 'app-dialog-expand-image',
templateUrl: './dialog-expand-image.component.html',
styleUrls: ['./dialog-expand-image.component.scss'],
})
export class DialogExpandImageComponent {
constructor(public dialogRef: MatDialogRef<DialogExpandImageComponent>) {}
closeImage() {
this.dialogRef.close();
}
}
In my HTML, I just put a "TEST" word and it works when I click the image (the TEST is displayed accordingly). My issue here is that I don't know how I'm going to bring the image that's on my other component (the main component above where the image can be clicked) to be shown in this current dialog component. If anyone has a good suggestion, I'd be bery thankful.
You need to send the data when you perform the open dialog, and catch them in the dialog component by using injection token of MAT_DIALOG_DATA
// in other component
dialog.open(YourDialog, {
data: { name: 'austin' },
});
// dialog component
import {Component, Inject} from '#angular/core';
import {MAT_DIALOG_DATA} from '#angular/material/dialog';
#Component({
selector: 'your-dialog',
template: 'passed in {{ data.name }}',
})
export class YourDialog {
constructor(#Inject(MAT_DIALOG_DATA) public data: {name: string}) { }
}
// dialog template
<ng-template let-data>
Hello, {{data.name}}
</ng-template>
For example if you have a thumbnail and you click it you will open the dialog and send the image url or image id and render it in the dialog template.
reference: https://material.angular.io/components/dialog/overview
Angular Material suggests sending the data using the injection token of MAT_DIALOG_DATA, so in the openImage() method you have some options, with your code you can pass the image as a parameter and send it as part of the data to the modal
openImage(image: string) {
this.dialog
.open(DialogExpandImageComponent, { data: { image } })
.afterClosed()
.subscribe(() => console.log('test successful'));
}
So, in your modal DialogExpandImageComponent you can receive like this
#Component({
selector: 'app-dialog-expand-image',
templateUrl: './dialog-expand-image.component.html',
styleUrls: ['./dialog-expand-image.component.scss'],
})
export class DialogExpandImageComponent {
constructor(
public dialogRef: MatDialogRef<DialogExpandImageComponent>,
#Inject(MAT_DIALOG_DATA) public data: DialogData
) {}
closeImage() {
this.dialogRef.close();
}
}
I have an example similar running, I put parts of your code, and works this is the link code:
https://stackblitz.com/edit/angular-2egim9-pqiqxc?file=src%2Fapp%2Fdialog-overview-example.ts
link Demo running: https://angular-2egim9--4200.local.webcontainer.io/
Overview:
Im trying to get the hero details to show on hero-details page upon clicking on the button but I cant seem to figure out how to make it work. When I click on the button Im able to show the details on hero-list page but if I try to reroute it using routerLink I cant get the data to show. Right now Im just using <app-hero-details [hero]="selectedHero" > so I can have the data display when the hero button is clicked. I guess it has something to do with this [hero]="selectedHero".
heroes-list.components.html
<h1>Hero List</h1>
<ul>
<!--Displays a list of hero names-->
<li *ngFor="let hero of heroes">
<button type="button" (click)="onSelect(hero)" [class.selected]="hero === selectedHero" >
<span class="name">{{hero.name}}</span >
</button>
</li>
</ul>
<!-- just used to test hero-details page routing -->
<!-- <p><a routerLink="/hero-details" routerLinkActive="active">Click here</a></p> -->
<!-- just used to test 404/wildcard page routing -->
<!-- <p><a routerLink="/fakeLink" routerLinkActive="active">Click here</a></p> -->
<!-- this will show the data on this page-->
<app-hero-details [hero]="selectedHero" ></app-hero-details>
heroes-list.component.ts
import { Component, OnInit } from '#angular/core';
import { BackendService } from '../services/backend.service';
import { Hero } from '../types/Hero';
#Component({
selector: 'app-heroes-list',
templateUrl: './heroes-list.component.html',
styleUrls: ['./heroes-list.component.css']
})
export class HeroesListComponent implements OnInit {
selectedHero?: Hero;
heroes: Hero[] = [
];
onSelect(hero: Hero): void {
this.selectedHero = hero;
}
constructor(private backend: BackendService) { }
async ngOnInit(): Promise<void> {
// Gets a list of heroes to display
this.heroes = await this.backend.getHeroes();
}
}
hero-details.components.html
<p>Hero Details section</p>
<!-- <p><a routerLink="" routerLinkActive="active">Click here to go back to Hero List</a></p>
<h1>Hero Details page</h1> -->
<div *ngIf="hero" >
<!-- the hero details that will be displayed upon clicking on name -->
<h2 >{{hero.name | uppercase}} Details</h2>
<div><span>Id: </span>{{hero.id}}</div>
<div><span>Level: </span>{{hero.level}}</div>
<div><span>Class: </span>{{hero.class}}</div>
</div>
hero-details.components.ts
import { Component, Input, OnInit } from '#angular/core';
import { ActivatedRoute } from '#angular/router'
import { Hero } from '../types/Hero';
#Component({
selector: 'app-hero-details',
templateUrl: './hero-details.component.html',
styleUrls: ['./hero-details.component.css']
})
export class HeroDetailsComponent implements OnInit {
#Input() hero: Hero | undefined;
constructor(
private route: ActivatedRoute,
) { }
ngOnInit(): void {
}
}
Does your backend return anything? Show us the backend and show what it is returning. Also I would advise to refactor ngOnInit() to not be async function. Refactor logic away from ngOnInit to a new function and have ngOnInit call out the said new function.
Otherwise it looks like it should work.
ngOnInit(): void {
this.getHeroes();
}
async getHeroes() {
// Gets a list of heroes to display
this.heroes = await this.backend.getHeroes();
}
Example: https://stackblitz.com/edit/heroes-list-fjdq6g?file=src%2Fapp%2Fheroes%2Fheroes.component.ts
Below I have written on for the open dialog method in the component
import { Component, OnInit } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { AuthService } from '../_services/auth.service';
import { AlertifyService } from '../_services/alertify.service';
import { ModalService } from '../_modal';
#Component({
selector: 'app-view-customer',
templateUrl: './ViewCustomer.component.html',
styleUrls: ['./ViewCustomer.component.css']
})
export class ViewCustomerComponent implements OnInit {
bookings: any;
bodyText: string;
constructor(private authService: AuthService, private http: HttpClient, private alertify: AlertifyService
, private modalService: ModalService) { }
ngOnInit() {
this.Bookings();
console.log(this.Bookings());
this.bodyText = 'This text can be updated in modal 1';
}
openModal(id: string) {
this.modalService.open(id);
}
closeModal(id: string) {
this.modalService.close(id);
}
Bookings() {
this.http.get('http://localhost:5000/api/Book/').subscribe(response => {
this.bookings = response;
console.log(this.bookings);
}, error => {
console.log(error);
});
}
}
Below I've included the template.
I'm trying to make the first button show the first data displayed the second button displaying the second data.
Currently, I have the dialog displaying all the data whenever the user clicks on both of the buttons.
<h1>List of reservations</h1>
<div>
<p *ngFor= "let booking of bookings">
{{booking.customers.firstName}},
{{booking.id}}, {{booking.date}},
{{booking.id}},{{booking.tableNumber}}
{{booking.id}},{{booking.additionalInfo}}
</p>
<button (click)="openModal('custom-modal-2')">Open Modal 2</button>
<button (click)="openModal('custom-modal-3')">Open Modal 3</button>
</div>
<p>
</p>
<div>
<p>{{bodyText}}</p>
<button (click)="openModal('custom-modal-1')">Open Modal 1</button>
<button (click)="openModal('custom-modal-2')">Open Modal 2</button>
</div>
<jw-modal id="custom-modal-1">
<h1>A Custom Modal!</h1>
<p>Home page text: <input type="text" [(ngModel)]="bodyText" /></p>
<button (click)="closeModal('custom-modal-1');">Close</button>
</jw-modal>
<jw-modal id="custom-modal-2">
<h1 style="height:100px">A Tall Custom Modal!</h1>
<p *ngFor= "let booking of bookings">
{{booking.id}}, {{booking.date}},
{{booking.id}},{{booking.tableNumber}}
{{booking.id}},{{booking.additionalInfo}}
</p>
<button (click)="closeModal('custom-modal-2');">Close</button>
</jw-modal>
<jw-modal id="custom-modal-3">
<h1 style="height:100px">second one hhaha</h1>
<button (click)="closeModal('custom-modal-3');">Close</button>
</jw-modal>
<!-- <p *ngFor= "let customers of bookings ">
{{booking.id}}, {{bookings.firstName}}
{{booking.customerId}}, {{booking.FirstName}}
</p>
<p>hello</p> -->
<p>{{ bookings[0]?.customers[0]?.Color?.Name }}</p>
what do I need to change below in the modal service?
import { Injectable } from '#angular/core';
#Injectable({ providedIn: 'root' })
export class ModalService {
private modals: any[] = [];
selectedBooking: any;
bookings: any;
add(modal: any) {
// add modal to array of active modals
this.modals.push(modal);
}
remove(id: string) {
// remove modal from array of active modals
this.modals = this.modals.filter(x => x.id !== id);
}
open(id: string) {
// open modal specified by id
const modal = this.modals.find(x => x.id === id);
modal.open();
}
close(id: string) {
// close modal specified by id
const modal = this.modals.find(x => x.id === id);
modal.close();
}
}
if you look at the image it shows that whenver i click on open modal button 2 it should only show emma's detail in the dialog box but it shows Tommy's details with Emma's detail.
image 1
iamge 2
That is because you are showing all the records in the modal. Here you are looping through all of them (bookings) in displaying them:
<jw-modal id="custom-modal-2">
<h1 style="height:100px">A Tall Custom Modal!</h1>
<p *ngFor= "let booking of bookings">
{{booking.id}}, {{booking.date}},
{{booking.id}},{{booking.tableNumber}}
{{booking.id}},{{booking.additionalInfo}}
</p>
<button (click)="closeModal('custom-modal-2');">Close</button>
</jw-modal>
If ModalService is something you created in your project (I mean not from a node module) then you can declare a variable there, set that when the button is clicked and use it in the modal. Something like,
export class ModalService {
selectedBooking: any;
.
.
}
Component HTML
<button (click)="openModal(booking)">Open Modal</button>
Component TS
openModal(booking: any) {
this.modalService.selectedBooking = booking;
this.modalService.open();
}
Modal HTML
<jw-modal id="custom-modal-2">
<h1 style="height:100px">A Tall Custom Modal!</h1>
{{selectedBooking.id}}, {{selectedBooking.date}},
{{selectedBooking.id}},{{selectedBooking.tableNumber}}
{{selectedBooking.id}},{{selectedBooking.additionalInfo}}
</p>
<button (click)="closeModal('custom-modal-2');">Close</button>
</jw-modal>
I am working in an Angular 4 application in this I have the same accordion in two components .What I want to do is if a user clicked on the accordion from first component I want to get the index of the selected accordion and pass it to second component there I set the selected accordion to open and show the contents in it on page load (without click on it )
currently I have single accordion in first component ,If multiple accordion binds from API the selected index will changed dynamically.
Here is my code :
https://stackblitz.com/edit/angular-bootstrap-carousel-dynamic2-tsrt1w?file=app%2Fone%2Fone.component.html
You can pass id using route params, look into below sample codes for example:
one.component.html
<h5>One Component</h5>
<h6>Categories</h6>
<div class="accordion col-sm-12" id="accordion1" *ngFor='let data of dropdownData; let i=index'>
<div class="accordion-group">
<div class="accordion-heading">
<a class="accordion-toggle h6" data-toggle="collapse" routerLink="/two/{{i}}" data-parent="#accordion1" href="#collapseTwo + i">
{{data?.CAMD_ENTITY_DESC}}
</a>
</div>
</div>
</div>
<br>
app routes
const appRoutes: Routes = [
{path:'one',component:OneComponent},
{path:'two/:id',component:TwoComponent}]
two.component.ts
import { Component, OnInit, ViewChildren, QueryList, AfterViewInit, ElementRef } from '#angular/core';
import { ActivatedRoute } from '#angular/router';
import { CartdataServiceService } from '../cartdata-service.service';
declare var $:any;
#Component({
selector: 'app-two',
templateUrl: './two.component.html',
styleUrls: ['./two.component.css']
})
export class TwoComponent implements OnInit,AfterViewInit {
dropdownData: any;
id:string;
#ViewChildren('accordian') components:QueryList<ElementRef>;
constructor( private route: ActivatedRoute, private CartdataService: CartdataServiceService) {}
ngOnInit() {
this.CartdataService.get_New_Products().subscribe(
data => {
this.dropdownData = data;
console.log(this.dropdownData);
});
this.id = this.route.snapshot.paramMap.get('id');
}
ngAfterViewInit(){
// print array of CustomComponent objects
this.components.changes.subscribe(() => {
let elem=this.components.toArray()[this.id];
$(elem.nativeElement).trigger("click");
console.log(elem);
});
}
}
Now you can use id and select the required index for accordion.
Example Link
When I click on this button,I want label to change. HTML:
<button pButton type="button" label="Edit" (click) = "foo()" style="width:auto"></button>
For example : before - "Edit", click, after - "Save".
You can simply bind it to your component variable inside your <button> tag.
<button pButton type="button" (click)="foo()"> style="width:auto">
{{myLabel}}
</button>
and in your component class:
#Component({
templateUrl:'./mytemplate'
})
export class MyComponent implements OnInit {
myLabel:string;
ngOnInit() {
this.myLabel = 'Edit';
}
foo() {
this.myLabel = 'Save';
}
}
Here is a working plunker: https://plnkr.co/edit/8TOn8oN63pgJ7eA7h7tY?p=preview
In your component class
#Component({
templateUrl:'./mytemplate'
})
export class MyComponent implements OnInit {
myLabel:string;
ngOnInit() {
this.myLabel = 'Edit';
}
foo() {
this.myLabel = 'Save';
}
}
In your html
<button pButton type="button" [attr.label]="myLabel" (click)="foo()" style="width:auto"></button>
Note that the html syntax has changed to start using property binding, where the "label" attribute of the node associated with the button element is being updated with the value of the myLabel variable in the component.
Read more about template and property bindings in this guide
https://angular.io/guide/template-syntax#property-binding
As a side note, if your requirement is to change the text displayed on the button, I would use interpolation as below
<button pButton type="button" (click)="foo()" style="width:auto">{{myLabel}}</button>
See this plunkr for a working example https://plnkr.co/edit/wEXKxP88kcsLKuBcUUxZ?p=preview
You can bind attributes via [attr.myAttribute] directive and as in your case you have to use [attr.label] to bind a value to the label attribute.
Inside your component you can define a label property which gets toggled on click:
class MyComponent {
private labelStates = ['Edit', 'Save'];
public label: string = this.labelStates[0];
public toggleLabel() {
let index = +(this.label === this.labelStates[0]);
this.label = this.labelStates[index];
}
}
And use it for your button:
<button [attr.label]="label" (click)="toggleLabel()"></button>
In case you want to change the button text use this:
<button (click)="toggleLabel()">{{ label }}</button>