Angular - passing data in to component - html

I'm still somewhat new to Angular development.
I'm building a website for a construction company, where I'm using three different components on one page. Here's a basic outline of what the page currently has, and what I want it to do:
The projects component contains a list of projects on the right side
of the page. Out of all those projects, the one that is selected
shows up on the left side of the page (projectdetail.component.html)
The user may click on any of the projects on the right side of the page to change the selected project. This new one will show up on the left side of the page in projectdetail.component.html
In the projectdetail component, there is a mini gallery of other
images that the user can click on in order to change the main image
that displays (like a typical photo slideshow).
THE PROBLEM I'M HAVING RIGHT NOW: The main image in projectdetail.component no longer changes whenever I click on any of the projects in the right panel (all of the other data, including the address, images in the slideshow, etc. do update as they should); they only time it changes is when I click on any of the images in the gallery in the projectdetail component. A solution I've proposed is to try to make updates to 'mainImage' (See code below) whenever you click on a project on the right panel, which it does not do. I am not sure how to accomplish this.
My Project class:
export class Project {
id: number;
address: string;
images: string[];
price: string;
featured: boolean;
description: string;
}
My Project Service:
import { Injectable } from '#angular/core';
import { Project } from '../shared/project';
import { PROJECTS } from '../shared/projects';
#Injectable()
export class ProjectService {
constructor() { }
getProjects(): Project[] {
return PROJECTS;
}
getProject(id: number): Project {
return PROJECTS.filter((project) => (project.id === id))[0];
}
}
Not including one of the components, which is irrelevant to the question, they are as follows:
projects.component.html
<div class="container"
fxLayout.sm="row"
fxLayout.xs="column">
<div fxFlex=60>
<app-projectdetail [project]="selectedProject" ></app-projectdetail>
</div>
<div fxFlex=40 *ngIf="projects">
<mat-grid-list cols="1" rowHeight="300px">
<mat-grid-tile *ngFor="let project of projects" (click)="onSelect(project)">
<img src="{{ project.images[0] }}">
<mat-grid-tile-footer>
<h1 mat-line ngDefaultControl>{{ project.address | uppercase }}</h1>
</mat-grid-tile-footer>
</mat-grid-tile>
</mat-grid-list>
</div>
</div>
projects.component.ts
import { Component, OnInit, Inject, Optional } from '#angular/core';
import { MatDialog } from '#angular/material';
import { ProjectDialogComponent } from '../project-dialog/project-dialog.component';
import { Project } from '../shared/project';
import { ProjectService } from '../services/project.service';
#Component({
selector: 'app-projects',
templateUrl: './projects.component.html',
styleUrls: ['./projects.component.scss']
})
export class ProjectsComponent implements OnInit {
projects: Project[];
selectedProject: Project;
image: String;
mainImage: String;
constructor(private projectService: ProjectService, private dialog: MatDialog) { }
ngOnInit() {
this.projects = this.projectService.getProjects();
this.selectedProject = this.projectService.getProject(0);
}
onSelect(project: Project) {
this.selectedProject = project;
this.mainImage = project.images[0];
}
}
projectdetail.component.html
<div class="container"
fxLayout="row"
fxLayoutGap="10px">
<div fxFlex=100>
<mat-card *ngIf="project">
<img src="{{ mainImage }}" (click)="openDialog(project)">
<mat-card-header>
<mat-card-title><h1>{{ project.address | uppercase }}</h1></mat-card-title>
</mat-card-header>
<div id="preWrapper">
<div id="imageWrapper">
<div id="imageContainer" *ngFor="let image of project.images">
<img src="{{ image }}" (click)="changeImage(image)" />
</div>
</div>
</div>
<mat-card-content>
<p>{{ project.description }}</p>
</mat-card-content>
</mat-card>
</div>
</div>
projectdetail.component.ts
import { Component, OnInit, Inject, Input } from '#angular/core';
import { MatDialog } from '#angular/material';
import { ProjectDialogComponent } from '../project-dialog/project-dialog.component';
import { Project } from '../shared/project';
import { ProjectService } from '../services/project.service';
#Component({
selector: 'app-projectdetail',
templateUrl: './projectdetail.component.html',
styleUrls: ['./projectdetail.component.scss']
})
export class ProjectdetailComponent implements OnInit {
#Input()
project: Project;
projects: Project[];
selectedProject: Project;
image: String;
mainImage: String;
constructor(private projectService: ProjectService, private dialog: MatDialog) { }
ngOnInit() {
this.mainImage = this.projectService.getProject(0).images[0];
}
openDialog(project: Project): void {
let dialogRef = this.dialog.open(ProjectDialogComponent, {
data: {
address: this.project.address,
images: this.project.images
}
})
}
changeImage(image: String) {
this.mainImage = image;
}
}

you write ngOnChange event in you detail component and then raise event for changing image in you main page ,
ngOnChanges(changes: SimpleChanges) {
for (let propName in changes) {
if (propName === 'project') {
Promise.resolve(null).then(() =>
{raise event or write code toc hange main page image});
}
}
}

Related

Sharing data between two pages upon clicking button Angular

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

Problem with My Wish List Items Showing Source unknown

I am having a problem showing my wish list items on the page. I'm using Angular 10 and json. Wen I click to add to favorites it color the heart and add it to to my json folder under wishlistitem, but when I route to page to look at the items no products are there. I can tell it hits the the *ngFor because the pipe for the dollar amount for each item appears but no images. When inspecting the source it shows src=unknown.
I have two folders wishlist-list and wishlistitem. I have a service for wishlistitem that is where I think my problem resides. I have included my code.
import { Component, OnInit, Input } from '#angular/core';
import {ProductService} from 'src/app/services/product.service'
import { MessengerService } from 'src/app/services/messenger.service';
import { WishlistService } from 'src/app/services/wishlist.service';
import { WishlistItemService } from '#app/services/wishlist-item.service';
import { Wish} from 'src/app/models/wish';
import {Product} from 'src/app/models/product';
#Component({
selector: 'app-wishlist-list',
templateUrl: './wishlist-list.component.html',
styleUrls: ['./wishlist-list.component.scss']
})
export class WishlistListComponent implements OnInit {
productList: Product[]= [];
wishlistItem: Wish[]= [];
wishItem = []
constructor( private msg: MessengerService,
private productService: ProductService,
private wishlistService: WishlistService,
private _wishlistitemService: WishlistItemService ) { }
ngOnInit(): void {
this.loadWishlistList();
}
loadWishlistList(){
this._wishlistitemService.getWishlistitem().subscribe((items: Wish[]) => {
this.wishItem= items;
this.msg.sendMsg("Is the item being captured" + items)
})
}
}
//Here is my Wishlist-list HTML
<p>wishlist-list works!</p>
<div class="container">
<div class="row">
<div class="col-md-2" *ngFor="let product of wishItem">
<app-wishlistitem [wishitemItem]="product"></app-wishlistitem>
</div>
</div>
</div>
//Here is my wishlist item service
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { wishlistitemUrl } from 'src/app/config/api';
import { map } from 'rxjs/operators';
import { ProductItemComponent } from '#app/shopping-cart/product-list/product-
item/product-item.component';
import { Observable, of } from 'rxjs';
import { catchError} from 'rxjs/operators';
import {Product} from 'src/app/models/product';
import {Wish} from 'src/app/models/wish';
#Injectable({
providedIn: 'root'
})
export class WishlistItemService {
product:any
wishlistitemUrl = 'http://localhost:3000/wishlistitem';
constructor(private http: HttpClient) { }
getWishlistitem(): Observable<Wish[]>{
return this.http.get<Wish[]>(wishlistitemUrl)
.pipe(
map((result: any[]) => {
let wishItem: Wish[]= [];
for(let item of result) {
let productExists = false
if (!productExists){
wishItem.push(new Wish(item.id, item.name, item.description,
item.price, item.imageUrl);
}
}
return wishItem;
})
);
}
addProductToWishlistItem(product:Wish):Observable<any>{
return this.http.post(wishlistitemUrl, {product});
}
}
//Here is wishlistitem
import { Component, Input, OnInit } from '#angular/core';
import { ProductService } from 'src/app/services/product.service'
import { WishlistService } from 'src/app/services/wishlist.service';
import { WishlistItemService } from '#app/services/wishlist-item.service';
import { MessengerService } from 'src/app/services/messenger.service';
import { map } from 'rxjs/operators';
import { Wish } from '#app/models/wish';
import { Product } from '#app/models/product';
#Component({
selector: 'app-wishlistitem',
templateUrl: './wishlistitem.component.html',
styleUrls: ['./wishlistitem.component.scss']
})
export class WishlistitemComponent implements OnInit {
#Input() wishitemItem: Wish
#Input() productItem: Product
#Input() product: string
constructor(private wishlistService: WishlistService, private _wishlistitemService:
WishlistItemService, private msg:MessengerService ) { }
ngOnInit(): void {
}
//This function works as expected
handleAddToWishlistitem(){
this._wishlistitemService.addProductToWishlistItem (this.wishitemItem).subscribe(()
=>{
alert("Get wish list item");
this.msg.sendMsg(this.wishitemItem)
})
}
}
//Here is wishlistitem Html
<p>wishlistitem works!</p>
<div class="test">
<div class="container" style="margin:0 auto">
<div class="row no-gutters" style="margin-top: 30px">
<div class="col-4">
<img class="shacker" [src]="wishitemItem.imageUrl" />
<div class="card-body">
<p class="card-text" style="text-align:left; width:130px">
{{wishitemItem.name}}</p>
<p class="card-text" style="text-align:left; width:130px;">
<strong>{{ wishitemItem.price | currency }}</strong>
</p>
<p class="card-text" style="text-align:left; width: 150px">
{{wishitemItem.description | slice: 0:20}}...</p>
</div>
</div>
</div>
</div>
</div>
//I hope the explanation is sufficient. I have tried many scenarios, the issue I'm
having is with the property for the wishlist item, carItem does not have a property
and when I create one the application doesn't behave as expected.
Thank you in advance
PDH

How to make the creation of a card dynamic?

My Problem is that every template created will be Added to the same Card like the image below shows it
And if i set the height rather than auto it will cut the card until the giving measurement.
is there anyone who can help me to make each template have it own card ?
Card.Html
<div class="content" >
<div fxLayout="row wrap" fxLayoutGap="16px grid">
<div [fxFlex]="(100/gridColumns) + '%'" fxFlex.xs="100%" fxFlex.sm="33%" >
<mat-card class="mat-elevation-z4 info" >
<mat-card-content *ngFor="let item of templates" [innerHTML]="item.templatebody | safeTemplate"></mat-card-content> <!-- named one way flow syntax property binding-->
</mat-card>
</div>
</div>
</div>
Card.ts
import { Component, OnInit, ViewChild,Pipe, PipeTransform } from '#angular/core';
import { DomSanitizer } from "#angular/platform-browser";
import { EmailEditorComponent } from 'angular-email-editor';
import { SenderService } from "../sender.service";
import { TemplateCard } from "src/app/layouts/default/templates/template";
//this pipe is designed to make the HtmlRender Safe using SanitizerDOM
#Pipe({ name: "safeTemplate" })
export class SafeHtmlPipe implements PipeTransform {
constructor(private sanitizer: DomSanitizer) {}
transform(value: any) {
return this.sanitizer.bypassSecurityTrustHtml(value);
}
}
#Component({
selector: 'app-cards',
templateUrl: './cards.component.html',
styleUrls: ['./cards.component.scss']
})
export class CardsComponent implements OnInit {
public templates:TemplateCard[];
public model: any;
options = {
};
gridColumns = 3;
toggleGridColumns() {
this.gridColumns = this.gridColumns === 3 ? 4 : 3;
}
dangerousUrl='<input type="checkbox">';
constructor(public http:SenderService) { }
ngOnInit(): void {
this.model=this.http.getEmail("http://localhost:3000/savetemplate").subscribe( data => {
this.templates=data;
console.log(this.templates);
},
err => console.error(err),
() => console.log('template completed')
);}
}

How can I route from a component to a section of another component in Angular?

I have two components and they are situtated in the different routes. In the Second component There is a div. I want to route from first component to the div of the second component. Yes, It is simple to route the second component. But I want to scroll be top of the div.
Thank you for answers.
This tag is declared in component1
<a [routerLink] = "['/c2']" fragment="c2id"> Link </a>
Here are the component2 changes
import { Component, OnInit } from '#angular/core';
import { ActivatedRoute } from '#angular/router';
#Component({
selector: 'app-c2',
templateUrl: './c2.component.html',
styleUrls: ['./c2.component.css']
})
export class C2Component implements OnInit {
private fragment: string;
constructor(private route: ActivatedRoute) {}
ngOnInit() {
this.route.fragment.subscribe(fragment => {
this.fragment = fragment;
});
}
ngAfterViewInit(): void {
try {
document.querySelector('#' + this.fragment).scrollIntoView();
} catch (e) {}
}
}
And your component2 html will be like this
<p style="height: 800px;">
c2 works!
</p>
<hr>
<div id="c2id" style="height: 500px;">
The div with c2id
</div>
Here is the updated and working stackblitz
https://angular-fragment-example.stackblitz.io
I think you are looking for Fragments.
Official Docs : Angular Docs- Query Params and Fragments
Examples:
Manual Navigation
in c1.html
<a [routerLink] = "['/c2']" [fragment]="c2id"> Link </a>
in c2.html
<div id="c2id">content</div>
Programatic Navigation
in c1.ts
private fragmentSetDynamically: string;
constructor(private router: Router){}
onClickButton(){
this.router.navigate(['/c2'], {fragment: fragmentSetDynamically});
}
Getting the fragment :
in c2.ts
private fragment: string;
constructor(private activatedRoute: ActivatedRoute){}
ngOnInit(){
this.fragment = this.activatedRoute.snapshot.fragment;
}

Angular 4 SideNav does not display

I am trying to insert a Material Sidenav into my component. For some reason, when I try to insert a basic sidenav it does not show anything -- main content, button to trigger sidenav, nor side content. I have imported both { MatSidenavModule } and { MatButtonModule} . However, if I comment out the mat-sidenav portion of the code, then the button will appear, so I think it may be an issue with the way I am setting up mat-sidenav.
Here is my HTML code:
<!--product.component.html-->
<h2>Store Inventory</h2>
<div class = "products">
Remaining: {{displayRemain}}
Requested: {{displayRequest}}
{{title}}
Total: {{cartTotal}}
</div>
<div>
<mat-sidenav-container class="example-container">
<mat-sidenav #sidenav class="example-sidenav">
Sidenav opened!
</mat-sidenav>
<div class="example-sidenav-content">
<button type="button" mat-button (click)="sidenav.open()">
Open sidenav
</button>
</div>
</mat-sidenav-container>
</div>
Here is the corresponding product.component.ts file: (I took out some functions which I commented out in the HTML)
import { Component, OnInit } from '#angular/core';
import { Product } from '../product';
import { ProductService } from '../product.service';
import {element} from 'protractor';
#Component({
selector: 'app-products',
templateUrl: './products.component.html',
styleUrls: ['./products.component.css']
})
export class ProductsComponent implements OnInit {
products: Product[];
displayRemain: number;
displayRequest: number;
title: string;
prevRemain: number;
cartTotal: number;
constructor(private productService: ProductService) {
}
ngOnInit() {
this.title = 'Not Hello';
this.displayRemain = 0;
this.displayRequest = 0;
this.prevRemain = 10;
this.cartTotal = 0;
this.getProducts();
}
EDIT: got the answer, I didn't install the angular material animation library. Leaving this up in case others have the same problem.
Try to use sidenav.toggle() instead sidenav.open()
Regards