I have the data being printed out to a log . Have do I simply put this in an array? So I can do
<ul *ngIf="courses$ | async as courses else noData">
<li *ngFor="let course of courses">
{{course.name}}
</li>
</ul>
<ng-template #noData>No Data Available</ng-template>
export class SurveyComponent {
surveys: Survey[];
survey: Survey;
constructor(private http: HttpClient) {
}
ngOnInit(): void {
this.http.get('http://localhost:54653/api/survey/').subscribe(data => {
console.log(data);
},
err => {
console.log('Error occured.');
}
);
}
}
export class Survey {
constructor(id?: string, name?: string, description?: string) {
this.id = id;
this.name = name;
this.description = description;
}
public id: string;
public name: string;
public description: string;
}
EDIT 1: Why does the first .map work and the other doesn't ?
Like this ?
surveys$: Observable<Survey[]>;
ngOnInit(): void {
this.surveys$ = this.http.get<Survey[]>('http://localhost:54653/api/survey/');
}
You can use rxjs map operator after your API call:
...
courses$: Observable<Survey[]>
...
ngOnInit(): void {
// if you want use the async pipe in the view, assign the observable
// to your property and remove .subscribe
this.courses$ = this.http
.get('http://localhost:54653/api/survey/')
.map(surveys =>
surveys.map(survey => new Survey(survey.id, survey.name, survey.description))
)
}
...
Related
I am trying to call a list of actors from movies; in the DB I made, they all have commas at the end of each string. When the array is called, the content displays with 2 commas after each other and I am wondering how I can get rid of that. I have tried to use .join but I don't know how to implement it into the HTML (I am new at Angular).
Here is the HTML and .ts files:
import { Component, OnInit } from '#angular/core';
import { Router } from '#angular/router';
import { FetchApiDataService } from '../fetch-api-data.service'
import { MatDialog } from '#angular/material/dialog';
import { GenreComponent } from '../genre/genre.component';
import { DirectorComponent } from '../director/director.component';
#Component({
selector: 'app-movie-card',
templateUrl: './movie-card.component.html',
styleUrls: ['./movie-card.component.css']
})
export class MovieCardComponent implements OnInit {
movies: any[] = [];
actors: any[] = [];
constructor(
public dialog: MatDialog,
public fetchApiData: FetchApiDataService,
public router:Router,
) { }
ngOnInit(): void {
this.getMovies();
}
removeCommas(): void {
this.actors.join(' ');
}
getMovies(): void {
this.fetchApiData.getAllMovies().subscribe((response: any) => {
this.movies = response;
console.log(this.movies);
return this.movies;
});
}
openGenreDialog(genreName: string): void {
this.dialog.open(GenreComponent, {
width: '280px',
data: {
genreName: genreName
}
});
}
openDirectorDialog(directorName: string): void {
this.dialog.open(DirectorComponent, {
width: '280px',
data: {
directorName: directorName
}
});
}
}
<div style="display: flex;">
<mat-card *ngFor="let movie of movies;" style="flex: 1 1 auto;">
<mat-card-header>
<mat-card-title>{{movie.Title}}</mat-card-title>
<mat-card-subtitle>Starring: {{movie.Actors}}</mat-card-subtitle>
</mat-card-header>
<img src={{movie.ImagePath}} alt= {{movie.Title}} />
<mat-card-actions>
<button
mat-button
color="primary"
(click)="openGenreDialog(movie.Genre.Name)"
>
Genre
</button>
<button
mat-button
color="primary"
(click)="openDirectorDialog(movie.Director.Name)"
>
Director
</button>
<button
mat-button
color="primary"
>
Synopsis
</button>
<mat-icon>favorite_border</mat-icon>
</mat-card-actions>
</mat-card>
</div>
You can run the map pipe and replace method in your array.
getMovies(): void {
this.fetchApiData.getAllMovies().pipe(
map((actor) => actor.replace(',', ''))).
subscribe((response: any) => {
this.movies = response;
console.log(this.movies);
return this.movies;
});
}
First of all, I will advice you to not use 'any' everywhere. It removes type checking and that can lead to issues and bugs in future.
As the returned object will be an Observable of type any[] (or Movies[] if you create a movie object with a string property named actor), you can do something like this. It will return an array of actors. For replace function, you will have to use a regexp expression to select all the commas in the value -
getMovies() {
this.fetchApiData
.getAllMovies()
.subscribe((res: any[]) => {
this.movies = res;
this.actors = res.map((movie: any) => movie.actor.replace(/,/g, ''));
console.log(this.actors);
});
}
I am getting the below JSON data from a rest web service. I am trying to figure out how I can convert to an array of object.
{
"John": "Buttler"
"Hugh": "Martin"
.
.
.
}
I am trying to convert to below object. Basically I am expecting Person[]. In above JSON, John, Hugh are first names and Buttler, Martin are last names.
export class Person{
firstName: string;
lastName: string;
}
I am able to convert if I get the json as below
[
{
"firstName": "John"
"lastName:: "Buttler"
},
{
"firstName": "Hugh"
"lastName:: "Martin"
}
]
Angular Service Code:
findAllPersons(): Observable<Person[]> {
return this.httpClient.get<Person[]>('url');
}
You have to process the recieved response in your required format.
findAllPersons(): Observable<Person[]> {
return this.httpClient.get<object>('url');
}
findAllPersons().subscribe((response) =>{
let array = [];
for(let key in response){
let p = new Person();
p.firstName = key;
p.lastName = response[key];
array.push(p);
}
console.log(array); // your required array
});
import { HttpClient } from '#angular/common/http';
import { Injectable } from '#angular/core';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
interface NameData {
[firstName: string]: string;
}
interface Person {
firstName: string;
lastName: string;
}
#Injectable()
class PersonService {
constructor(private httpClient: HttpClient) {}
findAllPersons(): Observable<Person[]> {
return this.httpClient.get<NameData>('url').pipe(
map((v) =>
Object.entries(v).map(([firstName, lastName]) => ({
firstName,
lastName,
}))
)
);
}
}
I have this simple app based on JSON local data. Basically a product list and and a category. The goal is to filter products per category, and somewnat I've managed todo it so, but something is weird and wrong because the product list dosnt'te get updated on click in the category list, but is I refresh the page and leave the filter as I wanted, the products ara updated, corresponding to the filter. I dont know hat is causing this and after inumeous arrenots I ended up here asking the community... The code:
The service providing json data:
export class ProductService {
constructor(private htttp: HttpClient) {}
getAllProducts(): Observable<Product[]> {
return this.htttp.get<Product[]>("assets/products.json").pipe(
map((p) => {
let result = p[0]["products"];
return result;
})
);
}
getCategories(): Observable<any[]> {
return this.htttp.get<any[]>("assets/categories.json").pipe(
map((p) => {
let result = p[0]["categories"];
return result;
})
);
}
}
The basw component that holdsand handles all the logic:
export class BaseShopComponent implements OnInit {
categories: any[];
products: Product[];
category: string;
filteredProducts: Product[] = [];
constructor(
private productService: ProductService,
private route: ActivatedRoute
) {}
ngOnInit(): void {
this.route.queryParams.subscribe((params) => {
this.category = params["categories"];
console.log(this.category);
});
this.productService.getAllProducts().subscribe((data: Product[]) => {
this.products = data;
this.filteredProducts = this.category
? this.products.filter(
(p) => p.category.toLowerCase() === this.category.toLowerCase()
)
: this.products;
});
this.getCategories();
}
getCategories() {
this.productService.getCategories().subscribe((data: any[]) => {
this.categories = data;
});
}
}
The way data is passed to other components:
<div class="container">
<div class="row">
<div class="col-md-3">
<app-left-shop></app-left-shop>
</div>
<div class="col-md-6">
<app-content-shop
[products]="products"
[filteredProducts]="filteredProducts"
></app-content-shop>
</div>
<div class="col-md-3">
<app-right-shop
[categories]="categories"
[category]="category"
></app-right-shop>
</div>
</div>
</div>
And the receivers/redenders TS
export class RightShopComponent implements OnInit {
#Input() categories: any[];
#Input() category:string;
And HtML
<ul class="list-group">
<a class="list-group-item"
*ngFor="let c of categories"
[class.active]="c.name===category"
routerLink="/shop"
[queryParams]="{categories:c.name}">
{{c.name}}
</a>
</ul>
TS
export class ContentShopComponent implements OnInit {
#Input() products: Product[];
#Input() filteredProducts: Product[] = [];
}
nd finally, the Html:
<ul>
<li *ngFor="let p of filteredProducts">
{{p.name}}
</li>
</ul>
Im lost, I admit. I cant figure out the reason for this bad behaviour. Someone can help»
In your BaseShopComponent your'e fetching queryParams and the category list. Also to filter the products based on the category you need to call the product fetch method whenever the queryParams changes. currently your'e doing in onInit it will execute only once.
write fetchProducts as separate function and call whenever the queryParams changes
onInit(){
this.route.queryParams.subscribe((params) => {
if(params.categories){
this.category = params["categories"];
this.fetchProducts(); <== Refresh When Category Changes
console.log(this.category);
}
});
this.fetchProducts(); <== Initial Call
this.getCategories();
}
fetchProducts() {
this.productService.getAllProducts().subscribe((data: Product[]) => {
this.products = data;
this.filteredProducts = this.category
? data.filter(
(p) => p.category.toLowerCase() === this.category.toLowerCase()
)
: data;
});
}
module of MarketEvent.tsx,The function is a centralized controller:
import * as React from 'react';
import EventList from './EventList';
import FullReduce from './FullReduce';
import './MarketEvent.less'
export default class MarketEvent extends React.Component<{},any> {
public id: string;
public name: string;
public target: JSX.Element;
public defaultId: string;
public state = {
target: this.target,
defaultId: 'marketMain'
};
public constructor(defaultId:any) {
super(defaultId);
this.changeTarget = this.changeTarget.bind(this);
this.target = this.state.target;
console.log('传到父组件的ID:',this.state.defaultId);
switch (this.state.defaultId) {
case 'marketMain':
this.target = <EventList currentRoute={this.changeTarget}/>;
break;
case 'fullReduce':
this.target = <FullReduce currentRoute={this.changeTarget}/>;
break;
default:
this.target = <EventList currentRoute={this.changeTarget}/>;
}
}
public componentWillMount(){
console.log('componentWillMount MarketEvent');
}
public componentDidMount(){
console.log('componentDidMount MarketEvent');
}
public changeTarget = (id: string) => {
console.log('子组件传到父组件的ID:',this.state);
this.setState({
defaultId: id
})
};
public render(){
return(
<div>
{this.target}
</div>
)
}
}
module of EventList.tsx,The function is to show 3 lists.:
import * as React from 'react';
import './MarketEvent.less'
interface EventListProps {
currentRoute: any
}
export default class EventList extends React.Component<EventListProps,any> {
public componentWillMount(){
console.log('componentWillMount EventList')
}
public componentDidMount(){
console.log('componentDidMount EventList')
}
public refName = (id: string) => {
this.props.currentRoute(id);
};
public render(){
return(
<div className="market_event">
<div className="market_top">
营销活动
</div>
<div className="market_body">
<ul className="market_ul">
<li onClick={this.refName.bind(this,'fullReduce')}><a href="javascript:;"><span className="l1">减</span>
<div className="event_box">
<h2>店铺满减</h2>
<i>促销</i><i>客单价</i>
<p>下单满足条件可享受减免</p>
</div>
</a></li>
<li><a href="javascript:;"><span className="l2">店</span>
<div className="event_box">
<h2>店铺代金券</h2>
<i>拉新</i><i>引流</i>
<p>进店时可领取店铺专用代金券</p>
</div>
</a></li>
<li><a href="javascript:;"><span className="l3">促</span>
<div className="event_box">
<h2>折扣促销</h2>
<i>新品</i><i>爆款</i>
<p>下单满足条件可享受减免</p>
</div>
</a></li>
</ul>
</div>
</div>
)
}
}
module of FullReduce.tsx,Act as a detail page in a list:
import * as React from 'react';
import {Button} from "antd";
interface FullReduceProps {
currentRoute: any
}
export default class FullReduce extends React.Component<FullReduceProps,any> {
public componentWillMount(){
console.log('componentWillMount FullReduce');
}
public componentDidMount(){
console.log('componentDidMount FullReduce')
}
public refName = (id:string) => {
this.props.currentRoute(id);
};
public render(){
return(
<div>
<Button htmlType='button' onClick={this.refName.bind(this,'marketMain')}>返回</Button>
已经进入了店铺满减页面了
</div>
)
}
}
The effect I want to achieve is click on a list in EventList. tsx, return an ID to the centralized controller MarketEvent. tsx, and then render the corresponding page by judgment,But after clicking, I found that defaultID had changed, and the page was not rendered.I print this.state on the console and find that the target in this.state is undefined.
I don't know why. Is there a good hand to help me? Thank you very much!!
The MarketEvent constructor does not run again after the state is changed. If you want the switch statement to run again to choose a different subcomponent to show, move it to the render method:
export default class MarketEvent extends React.Component<{},any> {
public id: string;
public name: string;
public defaultId: string;
public state = {
defaultId: 'marketMain'
};
public constructor(defaultId:any) {
super(defaultId);
this.changeTarget = this.changeTarget.bind(this);
console.log('传到父组件的ID:',this.state.defaultId);
}
public componentWillMount(){
console.log('componentWillMount MarketEvent');
}
public componentDidMount(){
console.log('componentDidMount MarketEvent');
}
public changeTarget = (id: string) => {
console.log('子组件传到父组件的ID:',this.state);
this.setState({
defaultId: id
})
};
public render(){
let target;
switch (this.state.defaultId) {
case 'marketMain':
target = <EventList currentRoute={this.changeTarget}/>;
break;
case 'fullReduce':
target = <FullReduce currentRoute={this.changeTarget}/>;
break;
default:
target = <EventList currentRoute={this.changeTarget}/>;
}
return(
<div>
{target}
</div>
)
}
}
Hello i want to pass the user id (uid) from the home page to a user Details Page. Because i display multiple users on my home page i don’t wan to pass the user session id (as given by the JSON.parse(localStorage.getItem("userData")); ), i want to click on the name of any user on the home page and pass its id and other parameters on the user details page.
home.html
<p (click)="UserPage()" [innerHTML]="item.username | linky"></p>
home.ts
public userDetails: any;
public resposeData: any;
public dataSet: any;
public noRecords: boolean;
rootPage: any = HomePage;
pages: Array<{ title: string, component: any }>;
userPostData = {
uid: “”,
token: “”,
username: “”,
message: “”,
msg_id: “”,
title: “”,
description: “”,
media_pic: “”,
created:""
};
constructor(
public common: Common,
public navCtrl: NavController,
public app: App,
public menu: MenuController,
public authService: AuthService,
platform: Platform,
statusBar: StatusBar,
splashScreen: SplashScreen,
) {
const data = JSON.parse(localStorage.getItem("userData"));
this.userDetails = data.userData;
this.userPostData.uid = this.userDetails.uid;
this.userPostData.token = this.userDetails.token;
this.userPostData.username = this.userDetails.username;
this.userPostData.msg_id = this.userDetails.msg_id;
this.userPostData.message = this.userDetails.message;
this.userPostData.title = this.userDetails.title;
this.userPostData.description = this.userDetails.description;
this.userPostData.media_pic = this.userDetails.media_pic;
this.userPostData.created = this.userDetails.created;
this.noRecords = false
this.allArtists();
}
note: this is how i call the users via Auth Service
allArtists() {
this.common.presentLoading();
this.authService.postData(this.userPostData, “newsFeed”).then(
result => {
this.resposeData = result;
if (this.resposeData.friendsNewsFeed) {
this.common.closeLoading();
this.dataSet = this.resposeData.friendsNewsFeed;
console.log(this.dataSet);
} else {
console.log("No access");
}
},
err => {
//Connection failed message
}
);
}
UserPage() {
this.navCtrl.push(UserPage, { uid: this.userPostData.uid });
userProfile.ts
mport { NavController, App, AlertController, MenuController, NavParams } from “ionic-angular”;
export class UserPage {
public uid: string;
constructor(
public common: Common,
public navCtrl: NavController,
public app: App,
public menuCtrl: MenuController,
public navParams: NavParams,
public authService: AuthService
) {
this.uid = navParams.get(‘uid’);
console.log(this.uid);
this.userProfile();
}
}
auth-service.ts
import { Injectable } from '#angular/core';
import { Http, Headers } from '#angular/http';
import 'rxjs/add/operator/map';
let apiUrl = "http://localhost/PHP-Slim-Restful1/api/";
//let apiUrl = 'https://api.thewallscript.com/restful/';
/*
Generated class for the AuthService provider.
See https://angular.io/docs/ts/latest/guide/dependency-injection.html
for more info on providers and Angular 2 DI.
*/
#Injectable()
export class AuthService {
constructor(public http: Http) {
console.log('Hello AuthService Provider');
}
postData(credentials, type){
return new Promise((resolve, reject) =>{
let headers = new Headers();
this.http.post(apiUrl+type, JSON.stringify(credentials), {headers: headers}).
subscribe(res =>{
resolve(res.json());
}, (err) =>{
reject(err);
});
});
}
}
With NavParams, you doing it the right way already.
It is not visible for me how your item structure is. When you setup your links at your homepage like this: <p (click)="UserPage()" [innerHTML]="item.username | linky"></p>, you could pass the user id of this item into the function like this: UserPage(user.uid).
What happens now, is that your UserPage function already gets the right uid and can pass it to the detailed view.
OK I got the answer. You need to pass the parameters in the with onclick.
home.html
home.ts
UserPage(uid_fk) {
this.navCtrl.push(UserPage, { uid_fk: uid_fk });
console.log(uid_fk);
}