How can I using angular when I want to click? - html

I'm a beginner to learn this component. And I going to try to create a online book shop like this link https://www.fishpond.com.hk/Books , and I'm facing some problem now. Could you guys please help me? And first in my website, it have backend and frontend, and now I can show all book , insert new book, and now I want to know how can I do when I click the title of the book and what I have to do to transfer to get that book detail.
How can I click the title and I will see those book detail on the book-details page. And I hope get the isbn code to find that book.
My code here
HTML
<h1>All Books</h1>
<ul *ngIf="books" class="info">
<li *ngFor="let book of books">
<p><img [src]="book.image" class="bookimg"></p>
<a routerLink="/book-detail"><h3>{{ book.title }}</h3></a>
<p>{{ "By "+ book.author }}</p>
<span class="price-block" >{{ "HK$" + book.price}}</span>
</li>
</ul>
ts
import { Component, OnInit } from '#angular/core';
import { DataService } from '../data.service';
#Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.scss']
})
export class HomeComponent implements OnInit {
h1Style: boolean = false;
books: Object;
constructor(private data: DataService) {}
ngOnInit() {
this.data.getBooks().subscribe(data=> {
console.log({data}); //show data
this.books = data
//console.log(this.books);
})
}
And I have created a component for book-detail
<h1>Book-detail</h1>
<div *ngIf="books" class="book-detail-block">
<div *ngFor="let bookrecord of books" class="book-record">
<h1>{{bookrecord.title}}</h1>
<p>{{bookrecord.image}}</p>
<p>{{bookrecord.author}}</p>
<p>{{bookrecord.price}}</p>
<p>{{bookrecord.isbn}}</p>
<p>{{bookrecord.description}}</p>
</div>
</div>
ts
import { Component, OnInit } from '#angular/core';
import { DataService } from '../data.service';
#Component({
selector: 'app-book-detail',
templateUrl: './book-detail.component.html',
styleUrls: ['./book-detail.component.scss']
})
export class BookDetailComponent implements OnInit {
h1Style: boolean = false;
books: Object;
constructor(private data: DataService) {}
ngOnInit() {
this.data.getOneBook().subscribe(data => {
this.books = data
console.log(this.books);
})
}
}
I can get the data in the service but how can I implement in show component
export class BookDetailComponent implements OnInit {
h1Style: boolean = false;
books: Object;
constructor(private data: DataService) {}
ngOnInit() {
console.log('-0-----' + this.books)
this.data.getBooks().subscribe(data=> {
console.log({data}); //show data
this.books = data
})
}
}
enter image description here

I may be late to the issue and you've already solved it but in the off-chance that you havent i'll hopefully provide some guidance.
What you want for accessing an individual item when clicking the title is to use a click-event on the tag representing the title, probably the h1-tag. It looks something like this:
<h1 (click)="getBookDetail(bookrecord)">{{bookrecord.title}}</h1>
The line above hooks up a clickevent to a function called getBookDetail and takes the individual object as a parameter, as of now this will render an error saying there's no function named getBookDetail(), so you'll need to create it in the component.ts file that corresponds to the view probably the homecomponent.ts and it looks like this:
getBookDetail(book: any) {
console.log(book);
}
If you now reload the application and click the title you'll see the individual book-object being logged in the console. What you'll need after is to set up routing if you havent already (you get the question to include app-routes module when creating the project) and to create a path for the bookDetailComponent. If you have routing in place add an array of routes as following:
const routes: Routes = [
{ path: '', redirectTo: '/books', pathMatch: 'full' },
{ path: 'books', component: HomeComponent},
{ path: 'book/:id', component: BookDetailComponent },
];
The first item in the routes array will match any route that is empty like localhost:4200 and redirect to the HomeComponent, and the other two arrays are routes for the individual component.
And if you dont have a routing-module i suggest you follow angulars tutorial for adding in-app navigation: https://angular.io/tutorial/toh-pt5.
And for making the click on the title actually navigate to the bookcomponent you first need to inject the Router class, so if you go back to the homecomponent you'll see an constructor (if not create one), add the router class like:
constructor(private router: Router) {}
And in the getBookDetail function you can remove the console.log and add:
getBookDetail(book: any) {
// Wrong path this.router.navigateByUrl('/book/' + book.isbn);
this.router.navigateByUrl('/bookdetail/' + book.isbn);
}
All that you need now is to get the isbn from the url and fetch one book with that identifier, but i'll leave those steps to you, everything you'll need is in the angular tutorial i linked previously. Good luck and if anything is confusing or you have any questions feel free to ask.
Added a stackblitz showing my idea:
https://stackblitz.com/edit/angular-ivy-c2znl2?file=src/app/books/books.component.ts

Related

How to expand image using MatDialog?

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:

Parsing JSON data in Angular that was returned from a Spring controller

I have a strange problem with trying to JSON data returned from a Spring API to populate a list in Angular. I have a datasets-list.component.ts with the following code
import { Component, OnInit } from '#angular/core';
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
#Component({
selector: 'app-datasets-list',
templateUrl: './datasets-list.component.html',
styleUrls: ['./datasets-list.component.css']
})
#Injectable({
providedIn: 'root'
})
export class DatasetsListComponent implements OnInit {
constructor(private http: HttpClient) { }
API_SERVER:string=""; //url of API Gateway
DatasetsMetadata:any; // Object
ngOnInit(): void {
// Get the metadata from the API Gateway
let API_SERVER = "http://localhost:8443/datasets";
let resp = this.http.request("GET", API_SERVER,{responseType:"text"});
resp.subscribe((data)=>this.DatasetsMetadata=data);
}
}
I then have the HTML in datasets-list.component.html to show the raw data as well as try to list the name property two different ways, as follows:
<form class="OodlerDatasetsForm">
<h2 id="DatasetsLabel">Datasets</h2>
<p>{{DatasetsMetadata}}</p>
<ul>
<li ng-repeat="x in DatasetsMetadata">
{{x.name}}
</li>
</ul>
<ul>
<li *ngFor="let element of DatasetsMetadata">{{element.name}},{{element.code}},{{element.frequency}}</li>
</ul>
</form>
When I load the page in the browser, the {{DatasetsMetadata}} element shows the data as follows:
[{"name":"S&P 500 Stock Market Index","code":"SP500","frequency":"Daily"},{"name":"Dow Jones Industrial Average Daily Closing Price","code":"DJIA","frequency":"Daily"},{"name":"U.S. Industrial Production Index","code":"INDPRO","frequency":"Monthly"},{"name":"Gold Prices Daily Spot Value","code":"GSPD","frequency":"Daily"},{"name":"Silver Prices Daily Spot Value","code":"SSPD","frequency":"Daily"},{"name":"Copper Prices Spot Value","code":"CSPD","frequency":"Daily"},{"name":"All-Transactions House Price Index for the United States","code":"USSTHPI","frequency":"Quarterly"},{"name":"U.S. National Unemployment Rate","code":"USNURM","frequency":"Monthly"},{"name":"Crude Oil Prices: West Texas Intermediate","code":"DCOILWTICO","frequency":"Daily"}]
I already tried JSON.parse() and that didn't work. I appreciate any assistance you can give.
I have reproduced your issue and found a solution which helps in the development of your feature. Now you can isolate your issue without questioning if retrieving the data from the API functions properly.
I have added the following class to a folder on the same height as "app"
src/models/datasetsmetadata.ts
export class DatasetsMetadata {
public name: string;
public code: string;
public frequency: string;
}
Besides that I added a file to the assets folder named 'datasetsreponse.json' with the exact JSON list of stock exchanges your mentioned.
I modified the tsconfig.json file in the root of the Angular project to include the following flags in 'compilerOptions':
"resolveJsonModule": true,
"esModuleInterop": true,
These settings are needed to load Javascript Objects from files.
NOTE: make sure to restart the compilation process after your modified tsconfig.json.
The HTML file for datasets-list.component.html is now:
<form>
<h2 id="DatasetsLabel">Datasets</h2>
<ul>
<li *ngFor="let element of DatasetsMetadata">{{element.name}}, {{element.code}}, {{element.frequency}}</li>
</ul>
</form>
The TS file now is as follows:
import { Component, OnInit } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { DatasetsMetadata } from 'src/models/datasetsmetadata';
import DatasetsMetadataListJSON from '../../assets/datasetsresponse.json';
#Component({
selector: 'app-datasets-list',
templateUrl: './datasets-list.component.html',
styleUrls: ['./datasets-list.component.sass']
})
export class DatasetsListComponent implements OnInit {
constructor(private http: HttpClient) { }
API_SERVER = '';
// DatasetsMetadata: any; // old
DatasetsMetadata: DatasetsMetadata[];
ngOnInit(): void {
// Get the metadata from the API Gateway
// let API_SERVER = "http://localhost:8443/datasets";
// let resp = this.http.request("GET", API_SERVER, { responseType: "text" });
// resp.subscribe((data) => this.DatasetsMetadata = data);
this.DatasetsMetadata = DatasetsMetadataListJSON;
console.log(this.DatasetsMetadata);
}
}
The result in my Chrome browser:

Angular strips out data attribute from innerHTML

I have a string returned from an API endpoint as below:
If you died tomorrow, your wife <span class='person' data-relationship='Relationship.Wife' data-avatarid='1212'>Alice</span> will lose everything.
So to display this as HTML I'm using the innterHTML property:
<p *ngFor="let con1Died of consequences?.client1Died" [innerHTML]="con1Died"></p>
But this is outputted to the browser with the data attributes stripped out as:
<p _ngcontent-smy-c63="">If you died tomorrow, your wife <span class="person">Alice</span> will lose everything.</p>
How can I output this WITH the data attributes? Is there a way to this?
EDIT: So I tried the HTML sanitation technique from below but the CSS still isn't applied:
this.reportsService.getConsequences().subscribe(res => {
// Load the consequences to angular
this.consequences = res;
this.client1Died = new Array();
this.consequences.client1Died.forEach(element => {
const safehtml = this.sanitized.bypassSecurityTrustHtml(element);
this.client1Died.push(safehtml);
});
console.log(this.client1Died);
});
Create a pipe to sanitize the Html:
#Pipe({ name: 'safeHtml'})
export class SafeHtmlPipe implements PipeTransform {
constructor(private sanitized: DomSanitizer) {}
transform(value) {
return this.sanitized.bypassSecurityTrustHtml(value);
}
}
#Component({
selector: 'my-app',
template: `<div [innerHTML]="content | safeHtml"></div>`,
})

How fixed method POST with angular 5

I develop application for Portal, but when i create new role,
the role is created but the problem is that the added element is not displayed, it must refresh the browser to display this new element !!!, what do I do to display the added element directly in my table , and how to develop the other methods (put and delete) and thank's (i develop this application with angular 5)
thid my code .html:
<form #personForm="ngForm" (ngSubmit)="onSubmit(personForm.value)">
<input name="RoleName" [(ngModel)]="RoleName">
<button type="submit">Save</button>
</form>
and this my code .ts:
export interface Role {
RoleName: string;
}
#Component({
selector: 'app-role',
templateUrl: './role.component.html',
styleUrls: ['./role.component.css']
})
export class RoleComponent implements OnInit, AfterViewInit {
private roles: any;
constructor(private _roleService: RoleService, private http: HttpClient) { }
onSubmit(role: Role) {
return this.http.post('http://172.16.47.34:8282/MonProject.webservices/api/Roles', role).subscribe(status => console.log(JSON.stringify(status)));
}
async ngOnInit() {
this.roles = await this._roleService.getRoles();
}
ngAfterViewInit(): void {
$('#example-table').DataTable({
pageLength: 10,
});
}
}
If your post is successful, then update your data table with the newly added role.
You can achieve this by adding this logic inside the subscribe function.
Put and delete should follow the same concept. If the response shows that the request was successfully processed, then (in the subscribe) you can modify your data table.
Two things I noticed:
Try to avoid using jQuery with Angular. These two are not the best
together. You can get a reference for the data table with
ViewChild.
Using async/await with ngOnInit is a bad practice.

How can i get a variable from different TS page in HTML?

i'm working on ionic2 and i have two HTML pages (page1.html and page2.html)
how can i get a variable from page1.ts and show it in page2.html ?
If you used ionic g page to create your page1.html and page2.html file, then you should have .ts file associated with every html. You can store variables in that typescript file. And pass those variables between pages using Ionic's NavParams.
https://ionicframework.com/docs/api/navigation/NavParams/
Use a provider for that. Following code to share user's name-
global.provider.ts
import { Injectable } from '#angular/core';
#Injectable()
export class GlobalProvider {
public userName: any;
setUserName(name: string) {
this.userName= name;
}
}
Page1.ts
import { GlobalProvider } from '../providers/global.provider';
#Component({
templateUrl: 'page1.html'
})
export class Page1Page{
constructor(private _globalProvider : GlobalProvider) {}
this.globalProvider.setUserName('John');
}
Page2.ts
import { GlobalProvider } from '../providers/global.provider';
#Component({
templateUrl: 'page2.html'
})
export class Page2Page{
public user: any;
constructor(private _globalProvider : GlobalProvider) {}
this.user = this._globalProvider.userName;
console.log(this.user); // John
}