Question detail page not working in angular - javascript

I created all-question component it is visible but when i click on particular question view that redirect to that id but not got details on the id page. here i attached some files,
Admin Service file
Model file
Detail question component file
Detail question ts file
All question component file
All question ts file
admin.service.ts - this is admin service file
import { Injectable } from '#angular/core';
import { HttpClient, HttpHeaders } from '#angular/common/http';
import { Observable } from 'rxjs';
import { Admin } from "../model/admin";
#Injectable({
providedIn: 'root'
})
export class AdminService {
private ROOT_URL = "http://localhost:3300/questions";
private httpOptions = {
headers: new HttpHeaders().set("Content-Type", "application/json")
};
constructor(private http: HttpClient) { }
getQuestion(): Observable<Admin[]> {
return this.http.get<Admin[]>(this.ROOT_URL);
}
getQue(id: string){
return this.http.get<Admin>(`${this.ROOT_URL}/${id}`);
}
addQue(admin){
return this.http.post<any>(this.ROOT_URL, admin, this.httpOptions);
}
}
**model=>admin.ts** - this is model file
export interface Admin {
description: String,
// alternatives: String
alternatives: [
{
text: {
type: String,
required: true
},
isCorrect: {
type: Boolean,
required: true,
default: false
}
}
]
}
**que-detail.comp.html** - this is question detail component file
<div class="card">
<div class="card-body">
<h4>Question: {{admin.description}}</h4>
<h4>Options: {{admin.alternatives}}</h4>
</div>
</div>
**que-detail.comp.ts** - this is question details ts file
import { Component, OnInit } from '#angular/core';
import { ActivatedRoute } from '#angular/router';
import { Subscription } from 'rxjs';
import { Admin } from '../model/admin';
import { AdminService } from '../service/admin.service';
#Component({
selector: 'app-question-detail',
templateUrl: './question-detail.component.html',
styleUrls: ['./question-detail.component.css']
})
export class QuestionDetailComponent implements OnInit {
id: string;
admin: Admin;
adminSub$: Subscription;
constructor(private adminService: AdminService, private route: ActivatedRoute ) { }
ngOnInit(): void {
this.id = this.route.snapshot.paramMap.get("id");
this.adminSub$ = this.adminService.getQue(this.id).subscribe(admin => {
this.admin = admin;
});
}
}
**all-que.comp.html** - this is all question component file
<div class="card bg-dark text-white my-4 dashboard-bg">
<div class="card-body text-center">
<ul class="questions" *ngIf="admin$ | async as questions">
<li *ngFor="let question of questions">
<h4 class="card-title my-2">{{question.description}}</h4>
<h5 *ngFor="let x of question.alternatives">{{x.text}}</h5>
<a [routerLink]="question._id">View</a>
</li>
</ul>
</div>
</div>
**all-que.comp.ts** - this is all question ts file
import { Component, OnInit } from '#angular/core';
import { Observable } from 'rxjs';
import { Admin } from '../model/admin';
import { AdminService } from '../service/admin.service';
#Component({
selector: 'app-all-question',
templateUrl: './all-question.component.html',
styleUrls: ['./all-question.component.css']
})
export class AllQuestionComponent implements OnInit {
admin$: Observable<Admin[]>;
constructor(private adminService: AdminService) { }
ngOnInit(): void {
this.admin$ = this.adminService.getQuestion()
}
}

Your Question Details Component should be like,
<div class="card">
<div class="card-body">
<h4>Question: {{admin.description}}</h4>
<h5>Options:</h5>
<ng-container *ngFor="alternative of admin.alternatives">
<h6>{{alternative.text}}</h6>
</ng-container>
</div>
You are just using the undefined questions variable ig.

Related

how to show a Blog detail link in Angular

I want to show the Detail of a Blog in a different link in Angular. I already have a Blog file (blog.component.ts) and an Angular service where I can get all the blogs data from an API backend made with Strapi. There is one button in every single blog, which allows you to view the detail or complete Blog in a different link calling the unique ID, that is named 'pagina.component.ts'.
For that purpose, I think I must call the ID of every single Blog.
Here is my blog.component.html, where I already have the list of my blogs:
<section class="articles">
<article class="blue-article" *ngFor="let data of datas; index as i">
<div class="articles-header">
<time>{{ data.fecha }}</time>
<span class="articles-header-tag-blue">{{ data.relevante }}</span>
<span class="articles-header-category">
{{ data.category.name }}
</span>
</div>
<div class="articles-content">
<h1><a title="">{{ data.title }}</a></h1>
<!--<img *ngIf="!data.image" class="foto" [src]="data.image.name" alt="foto">-->
<div *ngIf="data.image">
<img
src="http://localhost:1337{{ data.image.url }}"
alt="foto"
width="100%"
/>
</div>
<p>
{{ data.content }}
</p>
<h3>{{ data.description }}</h3>
</div>
<div class="articles-footer">
<ul class="articles-footer-info">
<li><i class="pe-7s-comment"></i> 7 Respuestas
</li>
<li><i class="pe-7s-like"></i> 1221</li>
</ul>
<a [routerLink]="['./pagina',i]" class="btn">Leer más</a>
</div>
</article>
</section>
Here is my blog.component.ts file
import { Component, OnInit } from '#angular/core';
import { Meta, Title } from '#angular/platform-browser';
import { StrapiService } from '../../../services/strapi.service';
import { Router } from '#angular/router';
#Component({
selector: 'app-blog',
templateUrl: './blog.component.html',
styleUrls: ['./blog.component.scss']
})
export class BlogComponent implements OnInit {
datas:any=[];
errores:string="";
constructor(
public strapiserv:StrapiService,
private router: Router
) { }
ngOnInit(): void {
this.title.setTitle('Blog');
this.strapiserv.getData().subscribe(res=>{
this.datas= res as string[];
}, error =>{
console.log(error);
if(error.status == 0){
this.errores="Código del error: "+error.status+" \n Ha ocurrido un error del lado del cliente o un error de red.";
}else{
this.errores="Código del error: "+error.status+"\n\n"+error.statusText;
}
})
}
}
Here is my Angular service named 'strapi.service.ts'
import { Injectable } from '#angular/core';
import { HttpClient, HttpHeaders, HttpErrorResponse } from '#angular/common/http';
import { Observable, throwError } from 'rxjs';
import { catchError, map } from 'rxjs/operators';
#Injectable({
providedIn: 'root'
})
export class StrapiService {
REST_API: string ='http://localhost:1337/articles';
//https://strapi-dot-gmal-api-313723.uc.r.appspot.com/
httpHeaders = new HttpHeaders().set('Content-Type', 'application/json');
constructor(private httpClient: HttpClient) { }
getData():Observable<any>{
console.log();
let API=this.REST_API;
return this.httpClient.get(API,{headers:this.httpHeaders}) .pipe(
map((data:any) => {
return data;
}), catchError( error => {
return throwError(error);
})
)
}
/*getItem( idx:number ){
return this.data[idx];
}*/
}
And Here is my pagina.component.ts file where I want to show the complete detailed Blog
import { Component, OnInit } from '#angular/core';
import { ActivatedRoute } from '#angular/router';
import { Router } from '#angular/router';
import { StrapiService } from '../../../../services/strapi.service';
#Component({
selector: 'app-pagina',
templateUrl: './pagina.component.html',
styleUrls: ['./pagina.component.scss']
})
export class PaginaComponent implements OnInit {
data:any = {};
constructor( private activatedRoute: ActivatedRoute,
private router: Router,
public strapiserv:StrapiService
){
this.activatedRoute.params.subscribe( params => {
this.data = this.strapiserv.getData( params['id'] );
});
}
ngOnInit(): void {
}
}
My routes are:
const routes: Routes = [
{ path: 'blog', component: BlogComponent },
{ path: 'pagina/:id', component: PaginaComponent },
];
There are a lot of issues with what you have done:
The 'i' is the index of the loop, not the 'id' you want to use. I guess the 'id' is a property of data, so you should point to data.id
You don't have to use relative path when using [routerLink] (with brackets)
so replace this:
[routerLink]="['./pagina',i]"
with this:
[routerLink]="['/pagina', data.id]" // remove the '.'
Finally in your blog.component.ts file, your're receiving array of objects so you don't have to cast it as an array of string, this.datas= res; is enough

In my component add new Item is not working in angular

All files are attached as below,
component.html - This is component file
component.ts - This is component ts file
admin-service - This is service file
admin.ts - This is model file
add-que.html - This is component html file.
<div>
<form [formGroup]="adminForm" (ngSubmit)="newQuestion()">
<div class="form-group">
<label for="exampleInputEmail1">Question</label>
<input formControlName="description" type="description" placeholder="Enter question"
class="form-control" id="exampleInputEmail1" aria-describedby="emailHelp">
<small class="text-danger"
*ngIf="!adminForm.get('description').valid && adminForm.get('description').touched">
Please Enter a Question</small>
</div>
<div class="form-group m-auto">
<div class="col-6">
(a)<input formControlname="alternatives" type="text">
(b)<input formControlname="alternatives" type="text">
</div>
<div class="col-6">
(c)<input formControlname="alternatives" type="text">
(d)<input formControlname="alternatives" type="text">
</div>
</div>
<div class="m-auto">
<input type="submit" value="Add" class="btn btn-primary"/>
</div>
</form>
</div>
**add-que.ts** - This is component ts file.
import { Component, OnInit } from '#angular/core';
import { FormControl, FormGroup, Validators } from '#angular/forms';
import { Router } from '#angular/router';
import { AdminService } from '../service/admin.service';
#Component({
selector: 'app-add-question',
templateUrl: './add-question.component.html',
styleUrls: ['./add-question.component.css']
})
export class AddQuestionComponent implements OnInit {
adminForm = new FormGroup({
description: new FormControl("", [Validators.required]),
alternatives: new FormControl("", [Validators.required])
});
constructor(private adminService: AdminService, private router: Router) { }
ngOnInit(): void {
}
newQuestion(){
if(this.adminForm.valid){
this.adminService.addQue(this.adminForm.value).subscribe(res => {
this.adminForm.reset();
this.router.navigate(["/admin"]);
})
}
}
}
**admin-service.ts** - This is service ts file.
import { Injectable } from '#angular/core';
import { HttpClient, HttpHeaders } from '#angular/common/http';
import { Observable } from 'rxjs';
import { Admin } from "../model/admin";
#Injectable({
providedIn: 'root'
})
export class AdminService {
private ROOT_URL = "http://localhost:3300/questions";
private httpOptions = {
headers: new HttpHeaders().set("Content-Type", "application/json")
};
constructor(private http: HttpClient) { }
getQuestion(): Observable<Admin[]> {
return this.http.get<Admin[]>(this.ROOT_URL);
}
getQue(id: string){
return this.http.get<Admin>(`${this.ROOT_URL}/${id}`);
}
addQue(admin){
return this.http.post<any>(this.ROOT_URL, admin, this.httpOptions);
}
}
**admin.ts** - This is model ts file.
export interface Admin {
description: String,
alternatives: [
{
text: {
type: String,
required: true
},
isCorrect: {
type: Boolean,
required: true,
default: false
}
}
]
}
I did created add-question component with form as above. I did tried to add new question through form in angular but not get anything. i did attached my files as above.
you sould'nt use this.router.navigate(["/admin"]); to try "refresh a component". That's no work (there are no changes). In general you has a component with a ngOnInit. Simply get out the code under a ngOnInit in a function and call this function in subscribe, e.g.
ngOnInit()
{
this.init()
}
init()
{
..here you initialize your variables
}
submit(){
...
.subscribe(res=>{
....
this.init()
})
}

Angular routing - On routing to a child, View updates only on refresh of the page

I am learning routing from the example on angular docs.
The problem is that on clicking an element from crisis list, crisis detail isnt displayed right after click.
If i refresh my screen, then relevant crisis detail is displayed.
So the question is why is the detail visible after refreshing? Whats the solution?
//crisis-center-routing-module.ts
import { NgModule } from '#angular/core';
import { RouterModule, Routes } from '#angular/router';
import { CrisisCenterHomeComponent } from './crisis-center-home/crisis-center-home.component';
import { CrisisListComponent } from './crisis-list/crisis-list.component';
import { CrisisCenterComponent } from './crisis-center/crisis-center.component';
import { CrisisDetailComponent } from './crisis-detail/crisis-detail.component';
const crisisCenterRoutes: Routes = [
{
path: 'crisis-center',
component: CrisisCenterComponent,
children: [
{
path: '',
component: CrisisListComponent,
children: [
{
path: ':id',
component: CrisisDetailComponent
},
{
path: '',
component: CrisisCenterHomeComponent
}
]
}
]
}
];
#NgModule({
imports: [
RouterModule.forChild(crisisCenterRoutes)
],
exports: [
RouterModule
]
})
export class CrisisCenterRoutingModule { }
//crisis-list.component.html
<h2>CRISES</h2>
<ul class="crises">
<li *ngFor="let crisis of crises$ | async" [class.selected]="crisis.id === selectedId">
<a [routerLink]="[crisis.id]">
<span class="badge">{{ crisis.id }}</span>{{ crisis.name }}
</a>
</li>
</ul>
<router-outlet></router-outlet>
//crisis-list-component.ts
import { CrisisService } from '../crisis.service';
import { Crisis } from '../crisis';
import { Component, OnInit } from '#angular/core';
import { Observable } from 'rxjs';
import { switchMap } from 'rxjs/operators';
import { ActivatedRoute } from '#angular/router';
#Component({
selector: 'app-crisis-list',
templateUrl: './crisis-list.component.html',
styleUrls: ['./crisis-list.component.css']
})
export class CrisisListComponent implements OnInit {
selectedCrisis: Crisis;
crises: Crisis[];
crises$;
selectedId: number;
constructor(private crisisService: CrisisService, private service: CrisisService, private route: ActivatedRoute) { }
ngOnInit() {
this.crises$ = this.route.paramMap.pipe(
switchMap(params => {
this.selectedId = +params.get('id');
return this.service.getCrises();
})
);
}
onSelect(crisis: Crisis): void {
this.selectedCrisis = crisis;
}
getCrises(): void {
this.crisisService.getCrises()
.subscribe((crises) => {
this.crises = crises;
});
}
}
//crisis-detail.component.html
<button (click)='gotoCrises(crisis)'>Back</button>
<div *ngIf="crisis">
<h2>{{crisis.name | uppercase}} Details</h2>
<div><span>id: </span>{{crisis.id}}</div>
<div>
<label>name:
<input [(ngModel)]="crisis.name" placeholder="name" />
</label>
</div>
</div>
//crisis-detail.component.ts
import { Observable } from 'rxjs';
import { CrisisService } from '../crisis.service';
import { Component, OnInit, Input } from '#angular/core';
import { Crisis } from '../crisis';
import { Router, ActivatedRoute, ParamMap } from '#angular/router';
import { switchMap } from 'rxjs/operators';
#Component({
selector: 'app-crisis-detail',
templateUrl: './crisis-detail.component.html',
styleUrls: ['./crisis-detail.component.css']
})
export class CrisisDetailComponent implements OnInit {
crisis: Crisis;
private crisis$;
constructor(private route: ActivatedRoute, private router: Router, private service: CrisisService) { }
ngOnInit() {
const id = this.route.snapshot.paramMap.get('id');
this.crisis$ = this.service.getCrisis(id);
this.crisis$.subscribe((crisis) => {
this.crisis = crisis;
});
}
gotoCrises(crisis: Crisis) {
const crisisId = crisis ? crisis.id : null;
this.router.navigate(['/crisises', { id: crisisId, foo: 'foo' }]);
}
}
The problem was that i was getting id from the url using
activatedRoute.snapshot.paramMap.get('id)
The router-outlet renders the route once. For other clicks in the list, the detail view isnt updated.
In order to constantly listen to changes in id in the url, I had to subscribe to
ActivatedRoute.url
This solution was helpful https://stackoverflow.com/a/47030238/2416260

Sharing data with a service

I'm trying to display the data for every corresponding name(data from json-server) like firstName, lastName, email etc.
user.component.html - this is where I want to display the corresponding data
<div>
<h2>{{selectedUser.firstName | uppercase}} Details</h2>
<div><span>id: </span>{{selectedUser.id}}</div>
<div>
<label>First name:
<input [(ngModel)]="selectedUser.firstName" placeholder="First Name" />
</label>
</div>
<div>
<label>Last name:
<input [(ngModel)]="selectedUser.lastName" placeholder="Last Name" />
</label>
</div>
<div>
<label>Email:
<input [(ngModel)]="selectedUser.email" placeholder="example.com" />
</label>
</div>
<div>
<label>Start date:
<input [(ngModel)]="selectedUser.startDate" placeholder="Start date" />
</label>
</div>
</div>
user.component.ts
import { Component, OnInit, Input } from '#angular/core';
import { User } from '../user';
import { DataService } from '../data.service';
#Component({
selector: 'app-user',
templateUrl: './user.component.html',
styleUrls: ['./user.component.css']
})
export class UserComponent implements OnInit {
users: any
constructor(private dataService: DataService) { }
ngOnInit() {
this.dataService.getUsers()
.subscribe(data => this.users = data);
}
}
home.component.html - this is where I display the name for each user and when I click I want to display the content on the user page
<h2>Users</h2>
<ul class="users">
<a routerLink="/user"><li *ngFor="let user of users['users']"
[class.selected]="user === selectedUser"
(click)="onSelect(user)">
<span class="badge">{{user.id}}</span> {{user.firstName}} {{user.lastName}}
</li> </a>
</ul>
home.component.ts
import { Component, OnInit } from '#angular/core';
import { DataService } from '../data.service';
import { Router } from '#angular/router';
import { User } from '../user';
#Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {
public users = [];
constructor(private dataService: DataService) { }
ngOnInit() {
this.dataService.getUsers()
.subscribe(data => this.users = data);
}
}
And here is the data.service
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { BehaviorSubject } from 'rxjs';
import { Observable } from 'rxjs';
import { User } from "./user";
#Injectable({
providedIn: 'root'
})
export class DataService {
selectedUser: User;
constructor(private http: HttpClient) {}
getUsers(): Observable<User[]>{
return this.http.get<User[]>("http://localhost:3000/users");
}
onSelect(user: User): void {
console.log(user);
this.selectedUser = user;
}
}
It's work when I display the names on the home page.
I've also made this display of data on a single page(home.component) and it worked, but now I must to display it on another page. I've tried to do this with BehaviourSubject but I got stuck.
You are incorrectly accessing the property in your .html files. Example:
<h2>Users</h2>
<ul class="users">
<a routerLink="/user"><li *ngFor="let user of users['users']"
[class.selected]="user === selectedUser"
(click)="onSelect(user)">
<span class="badge">{{user.id}}</span> {{user.firstName}} {{user.lastName}}
</li> </a>
</ul>
Should be:
<h2>Users</h2>
<ul class="users">
<a routerLink="/user"><li *ngFor="let user of users['users']"
[class.selected]="user === dataService.selectedUser"
(click)="dataService.onSelect(user)">
<span class="badge">{{user.id}}</span> {{user.firstName}} {{user.lastName}}
</li> </a>
</ul>
You can let the DataService cache the users for you in a BehaviorSubject and all components bind to users$ property of the DataService.
import { Injectable } from '#angular/core';
import { BehaviorSubject } from 'rxjs';
import { HttpClient, HttpResponse, HttpErrorResponse } from '#angular/common/http';
import { User } from "./user";
#Injectable({
providedIn: 'root'
})
export class DataService {
isLoading$ = new BehaviorSubject<boolean>(false);
users$ = new BehaviorSubject<User[]>(undefined);
constructor(private http: HttpClient) { }
loadUsers(): void {
this.isLoading$.next(true);
this.http.get<User[]>("http://localhost:3000/users", { observe: "response" }).subscribe(
(res: HttpResponse<User[]>) => {
this.users$.next(res.body);
},
(res: HttpErrorResponse) => this.onError(res),
() => this.isLoading$.next(false)
);
}
private onError(res: HttpErrorResponse) {
console.log(res.message);
}
}

Angular 2 - Load route component and then gets back to previous component

I have a problem with Angular 2 routing. When I click on my link to get the team details, it takes the right route and loads the component specified (TeamComponent). But, immediately "gets back" to the previous component (TeamsComponent), which is the teams list.
This is the structure of my project:
/app
|_shared
|_team
|_team.component.css
|_team.component.html
|_team.component.ts
|_team.model.ts
|_team.service.ts
|_team-list
|_team-list.component.css
|_team-list.component.html
|_team-list.component.ts
|_teams
|_teams.component.css
|_teams.component.html
|_teams.component.ts
|_teams.module.ts
|_teams-routing.module.ts
First, I set the routes on teams-routing.module.ts:
import { NgModule } from '#angular/core';
import { RouterModule, Routes } from '#angular/router';
import { TeamsComponent } from './teams.component';
import { TeamComponent } from '../shared/team/team.component';
const teamsRoutes: Routes = [
{
path: 'team/:id',
component: TeamComponent
},{
path: 'teams',
component: TeamsComponent
}
];
#NgModule({
imports: [
RouterModule.forChild(teamsRoutes)
]
})
export class TeamsRoutingModule { }
Load the team list from the teamService on teams.component.ts and send it to team-list on teams.component.html:
import { Component, OnInit } from '#angular/core';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/from';
import { TeamService } from '../shared/team/team.service';
import { Team } from '../shared/team/team.model';
#Component({
selector: 'app-teams',
templateUrl: './teams.component.html',
styleUrls: ['./teams.component.css']
})
export class TeamsComponent implements OnInit {
teamList: Team[] = [];
constructor(private teamService: TeamService) { }
ngOnInit() {
this.teamService.getTeams().subscribe(teams => {
Observable.from(teams).subscribe(team => {
this.teamList.push(team);
});
});
}
}
teams.component.html
<section class="teams">
<app-team-list [teams]="teamList"></app-team-list>
</section>
Then, with my teams list, I set the HTML list on team-list.component.html:
<section *ngFor="let team of teams" class="team_list">
<div class="card" style="width: 20rem;">
<img class="card-img-top" src="/assets/logos/{{team.logo}}" alt="Team Logo">
<div class="card-block">
<h4 class="card-title">{{team.name}}</h4>
<p class="card-text">{{team.location}}</p>
<a routerLink="/team/{{team.id}}" class="btn btn-primary">Team Info</a>
</div>
</div>
</section>
Finally, I get the team info from param "id" and the service in team.component.ts:
import { Component, Input, OnInit } from '#angular/core';
import { Router, ActivatedRoute, Params } from '#angular/router';
import { Team } from './team.model';
import { TeamService } from "./team.service";
import 'rxjs/add/operator/switchMap';
#Component({
selector: 'app-team',
templateUrl: './team.component.html',
styleUrls: ['./team.component.css']
})
export class TeamComponent implements OnInit {
team: Team = null;
constructor(private teamService: TeamService,
private activatedRoute: ActivatedRoute,
private router: Router
) {}
ngOnInit() {
let teamId: number = this.activatedRoute.snapshot.params['id'];
console.log("Vamos a buscar el equipo");
this.teamService.getTeamById(teamId).subscribe(team => this.team = team);
}
}
It loads the TeamComponent HTML with the team data, but gets back to /teams direction (and doesn't print the team list). I tried to change the routes names (/detail/:id for example) but still doesn't work. Any suggestions? Thanks in advance.
Ok, got it. Your request will be exuted async, so at the creation-time of your component, team is null. I think you have a binding like this in your TeamComponent:
{{ team.name }}
If team is null, name cannot be accessed and it crashes. To be sure the html will be rendered without errors, use the elvis-operator like this:
{{ team?.name }}
This will only access name if team is not null or undefined
Update: The getTeamById service
getTeamById(id: number): Observable<Team> {
let team: Team = null;
return this.http.get(this.urlTeams+'/'+id)
.map(response => {
let dbTeam: any = response.json();
for(let i in dbTeam) {
team = new Team(dbTeam[i].teamId,dbTeam[i].teamName,dbTeam[i].teamLocation,dbTeam[i].teamFoundation,dbTeam[i].teamDivision,dbTeam[i].teamConference,dbTeam[i].teamStadium,dbTeam[i].teamAttendance,dbTeam[i].teamLogo,dbTeam[i].teamStadiumPhoto);
}
return team;
})
.catch(this.handleError);
}

Categories

Resources