Output array values to template - json

I'm currently learning Angular 2 and have confused myself with how to output data returned from a service to my template.
My API Response :
{
"site": {
"success": true,
"title": "foo",
"description": "bar"
}
}
My Service :
import { Injectable } from '#angular/core';
import {HTTP_PROVIDERS, Http, Response, Headers, RequestOptions } from "#angular/http";
import { Observable } from 'rxjs/Rx';
#Injectable()
export class ContentService {
constructor(private _http:Http) {}
getContent() {
return this._http.get('http://localhost:8080/api/foobar-endpoint/')
.map((res:Response) => res.json())
}
}
My Component :
import { Component, OnInit } from '#angular/core';
import { ContentService } from "../../services/content/content.service";
const template = require('./home.jade');
const styles = require('./home.sass');
#Component({
selector: 'home',
templateUrl: template,
styleUrls: [styles]
})
export class HomeComponent implements OnInit {
public foo = {}
constructor(private _contentService: ContentService) {}
ngOnInit() {
this.getContent();
}
getContent() {
this._contentService.getContent()
.subscribe(
data => {this.foo = data},
err => { console.log(err) },
() => console.log()
);
}
}
My Template :
pre
p {{ foo.site.title }}
If I place {{ foo | json }} in my template I can see the returned values in a JSON format, but when I try and output a single value, such as title I get undefined errors.
How can I access the values being returned?

I think the only thing you are missing here is the ?. Basically the problem is that when the components instantiates your foo property has no site param so angular throws the error.
So what you can do is either this:
{{foo.site?.title}}
Or this:
<p *ngIf="foo.site">{{foo.site.title}}</p>
This way angular won't try to bind the title before there is a site.

Related

put the response of a service inside of a string variable with typescript

i'm working on an angular 4 project and i made a service to get a json from a url, the service.ts looks like this:
import {Injectable} from '#angular/core';
import {Http , Response} from '#angular/http';
import 'rxjs/add/operator/map';
#Injectable()
export class EventsService{
constructor(private http:Http){
}
private url: string = "http://urlofmyjson/events";
getEvents() {
return (
this.http.get(this.url).map((response: Response) => response.json())
)
}
}
the content of that json looks like this:
{
"events":[
{
"title":"event1"
"location":"location1"
"date":"date1"
},
{
"title":"event2"
"location":"location2"
"date":"date2"
},
{
"title":"event3"
"location":"location3"
"date":"date3"
},
]
}
and in my component i have this:
import { Component, OnInit } from '#angular/core';
import {EventsService} from './conciertos.service';
#Component({
selector: 'app-events',
templateUrl: './events.component.html',
styleUrls: ['./events.component.scss']
})
export class EventsComponent implements OnInit {
constructor(private EventsService: ConciertosService) { }
events = []:
ngOnInit() {
this.EventsService.getEvents().subscribe( ResponseEvents => this.events=ResponseEvents);
}
}
and then i want to iterate each event of the json with an *ngFor, but as the json retrieves an object with an array inside of it that contains the events objects, i can't iterate it because it throws an error.
how can i put the response of the service inside a string type variable to call and iterate it with *ngFor?

Angular 2/4 - Can't resolve all parameters for GameEditComponent: ([object Object], [object Object], ?)

I am developing the services of my application, but when I try to load the page it shows the following error:
Can't resolve all parameters for GameEditComponent: ([object Object],
[object Object], ?).
I tried in the service to put as an array or just leave any, but even then the error continued
game-edit.service.ts
import { Injectable } from '#angular/core';
import { Http } from '#angular/http';
import { Observable } from 'rxjs';
#Injectable()
export class GameEditService {
constructor(private http: Http) { }
getGame(id): Observable<any> {
return this.http.get('http://localhost:8080/lightning/api/game' + id).map(res => res.json()).catch(error => {
throw new Error(error.message);
});
}
getManufactures(): Observable<any> {
return this.http.get('http://localhost:8080/lightning/api/manufacture').map(res => res.json()).catch(error => {
throw new Error(error.message);
});
}
getPlatforms(): Observable<any> {
return this.http.get('http://localhost:8080/lightning/api/platform').map(res => res.json()).catch(error => {
throw new Error(error.message);
});
}
}
game-edit.component.ts
import { ActivatedRoute, Params } from '#angular/router';
import { Component, OnInit } from '#angular/core';
import { GameEditService } from './game-edit.service';
#Component({
moduleId: module.id,
selector: 'app-game-edit',
templateUrl: './game-edit.component.html',
styleUrls: ['./game-edit.component.css', '../styles.css' ]
})
export class GameEditComponent implements OnInit {
constructor(private activatedRoute: ActivatedRoute, private gameEditService: GameEditService, private id) {
this.gameEditService.getPlatforms().subscribe(platforms => {
console.log(platforms);
}), erro => console.log(erro);
this.gameEditService.getManufactures().subscribe(manufactures => {
console.log(manufactures);
}), erro => console.log(erro);
}
ngOnInit() {
this.activatedRoute.params.subscribe((params: Params) => {
this.id = params['id'];
console.log(this.id);
});
this.gameEditService.getGame(this.id).subscribe(game => {
console.log(game);
}), erro => console.log(erro);
}
onSubmit(form){
console.log(form);
}
verificaValidTouched(campo){
return !campo.valid && campo.touched;
}
aplicaCssErro(campo){
return {
'subError': this.verificaValidTouched(campo)
}
}
}
This is the json that is coming, the first is for a selected game, the second is for the platforms and the third is for the manufacturers
json game selected
{
"id":1,
"name":"Street Fighter",
"category":"luta",
"price":20.5,
"quantity":1000,
"production":true,
"description":"descricao",
"image":"ps4.jpg",
"manufacture":
{
"id":1,
"name":"Sony",
"image":"ps4.jpg",
"imageFullPath":"http://localhost:8080/lightning/images/ps4.jpg"
}
}
json platforms
{
"id":1,
"name":"PC",
"image":"ps4.jpg",
"imageFullPath":"http://localhost:8080/lightning/images/ps4.jpg"
}
json manufactures
{
"id":1,
"name":"Sony",
"image":"ps4.jpg",
"imageFullPath":"http://localhost:8080/lightning/images/ps4.jpg"
}
Console
I'm using angular cli with with all packages in the most current versions.
I do not know if maybe this error is because of the platforms you have inside the game, or some other code problem, if you know something that could do to repair, I tried several solutions that I found through the internet, but none worked.
Thanks in advance.
The problem is the last argument in the component's constructor, private id. Angular will try to resolve this dependency, but can't find an injectable class for id. When looking at the code, I think there is no need to inject id into the constructor. Just define it as a property on your component:
// ... import statements
#Component({
moduleId: module.id,
selector: 'app-game-edit',
templateUrl: './game-edit.component.html',
styleUrls: ['./game-edit.component.css', '../styles.css' ]
})
export class GameEditComponent implements OnInit {
private id; // put the declaration of id here
// remove id declaration from the constructor, no need to inject it
constructor(private activatedRoute: ActivatedRoute,
private gameEditService: GameEditService) { // ...constructor code}
// other code
}
I solved it otherwise: My problem was that the HttpClient has a rare condition, it's not the same "import" line on the component that on the app.module...
On the Component is this:
import { HttpClient } from '#angular/common/http';
in app module is this:
import { HttpClientModule } from '#angular/common/http';

Angular 2 NFor loop not displaying

I don't get any errors to go off and the JSON is returned from the backend fine.
Question is, have I done anything wrong in the code below?
JSON
{
"Data": [{
"ProfileId": "121212",
"Name": "Charles",
"info": {
"rating": "0",
"plot": "Nothing happens at all."
}
}]
}
Home.Component.ts
import { Component, OnInit } from "#angular/core";
import { HomeService } from './home.service';
import { Profile } from './profile';
import 'rxjs/add/operator/map';
#Component({
moduleId: module.id,
selector: "home-page",
templateUrl: "home.component.html",
styleUrls: ["home.component.css"],
providers: [ HomeService ]
})
export class HomeComponent implements OnInit {
constructor(private service: HomeService) {}
Profiles: Profile[];
getProfile(): void {
this.service
.getData()
.then(profiles => this.Profiles = profiles);
}
ngOnInit(){
this.getProfile();
}
}
Home.service.ts
import {Injectable } from "#angular/core";
import {Headers, Http, Response} from '#angular/http';
import 'rxjs/add/operator/toPromise';
import { Profile } from './profile';
#Injectable()
export class HomeService {
private usersUrl = 'http://localhost:8888/';
private headers = new Headers({'Content-Type': 'application/json'});
constructor(private http: Http) {}
getData(): Promise<Profile[]> {
return this.http.get(this.usersUrl)
.toPromise()
.then(response => response.json().data as Profile[])
.catch(this.handleError);
//let err = new Error('Cannot get object of this type');
}
private handleError(error: any): Promise<any> {
console.error('An error occurred', error); // for demo purposes only
return Promise.reject(error.message || error);
}
}
home.component.html
<h2>HOME</h2>
<ul>
<li *ngFor="let prof of Profiles;">
{{prof.name}}
</li>
</ul>
Rendered as this in browser
{{prof.name}}
should be
{{prof.Name}}
Your picture gives a hint of the array being null with:
...ng-for-of: null
so besides the mention by Günther of that {{prof.name}} should be {{prof.Name}},
your JSON holds Data, (with capital letter), but in your get-request you are using data. This is actually case sensitive, so the following line
.then(response => response.json().data as Profile[])
should be:
.then(response => response.json().Data as Profile[])
that should populate your array correctly :)

Angular2 - cannot display json objects

my boss decided to implement Angular2 into our project. I'm preety new to this technology. I'm trying to display JSON from url, but the result is not as I expected. *ngFor doesn't display any data.
This is the code:
vehicle.service.ts
import { Injectable } from '#angular/core';
import { Http } from '#angular/http';
import 'rxjs/add/operator/map';
#Injectable()
export class VehicleService {
constructor(private http: Http){ }
getVehicle() {
return this.http.get('https://jsonplaceholder.typicode.com/posts')
.map(res => res.json());
}}
vehicle.component.ts
import { Component } from '#angular/core';
import { VehicleService } from './vehicle.service';
#Component({
moduleId: module.id,
selector: 'vehicle-json',
templateUrl: 'vehicle.html',
providers: [ VehicleService ]
})
export class VehicleComponent {
vehicle: Vehicle[];
constructor(private vehicleService: VehicleService){
this.vehicleService.getVehicle().subscribe(vehicle => {
/*console.log(vehicle);*/this.vehicle = vehicle;
});
}
}
interface Vehicle {
id: number;
title: string;
body: string;
}
vehicle.html
<div *ngFor="let vehicle of vehicles">
<h3>{{vehicle.title}}</h3>
<p>{{vehicle.body}}</p>
</div>
test 1-2-3
The output is: "test 1-2-3". I checked if the jsons will be displayed inside the console using: console.log(vehicle); - it worked, it returns Array of Objects.
What am I doing wrong? Any ideas how to fix my code?
You have an error:
this.vehicleService.getVehicle().subscribe(vehicle => {
this.vehicle = vehicle;
})
but in your html you refer to let vechicle of vehicles
You should add an "s" to your this.vehicle to your subscription like so:
this.vehicleService.getVehicle().subscribe(vehicle => {
this.vehicles = vehicle;
})
Edit: Just forgot to meantion to change the local variable vehicle: Vehicle[] to vechicles: Vehicle, but that you figured out that yourself! ;)

How can I sanitize css properties to use in template given from a data service

I need to generate sanitized css property to use with my component template to set the background image of the div:
<div *ngFor="let Item of Items"
[style.background-image]="Item.imageStyle
(click)="gotoDetail(Item.iditems)">
</div>
using data obtained through a data service. The component is:
import { Component } from '#angular/core';
import { Router } from '#angular/router';
import { DomSanitizer } from '#angular/platform-browser';
import { OnInit } from '#angular/core';
import { Item } from '../models/Item';
import { CollectionDataService } from '../services/CollectionData.service';
#Component({
selector: 'mainpage',
templateUrl: 'app/mainpage/mainpage.component.html',
styleUrls: ['app/mainpage/mainpage.component.css']
})
export class MainpageComponent implements OnInit {
Items: Item[];
ngOnInit() {
this.collectionDataService.getItems().subscribe(
Items => this.Items = Items
);
// Generates and sanitizes image links
this.Items.map(
(LItem) => LItem.imageStyle = this.sanitizer.bypassSecurityTrustStyle("url(template/images/"+LItem.iditems+".jpg)")
)
}
constructor(
private router: Router,
private sanitizer: DomSanitizer,
private collectionDataService: CollectionDataService
) {
}
gotoDetail($iditems: number): void {
this.router.navigate(['/viewer', $iditems]);
}
}
But it doesn't work because the statement that generates the sanitized property
this.Items.map(
(LItem) => LItem.imageStyle = this.sanitizer.bypassSecurityTrustStyle("url(template/images/"+LItem.iditems+".jpg)")
)
doesn't find the loaded data. The error that I'm seeing in the browser console is:
core.umd.js:3070 EXCEPTION: Uncaught (in promise): Error: Error in ./MainpageComponent class MainpageComponent_Host - inline template:0:0 caused by: Cannot read property 'map' of undefined
TypeError: Cannot read property 'map' of undefined
The data service is:
import { Injectable } from '#angular/core'
import { Http } from '#angular/http'
import { Item } from '../models/Item';
import { DomSanitizer } from '#angular/platform-browser';
#Injectable()
export class CollectionDataService {
constructor(
private http: Http,
private sanitizer: DomSanitizer
) { }
getItems() {
return this.http.get('app/mocksdata/items.json').map(
response => <Item[]>response.json().items
)
}
}
And the provided items.json:
{
"items": [{
"iditems": 1,
"imageStyle": ""
}, {
"iditems": 2,
"imageStyle": ""
}]
}
If I set static data in the component, instead of using the data service, everything works:
export class MainpageComponent implements OnInit {
Items: Item[];
ngOnInit() {
this.Items = [{
"iditems": 1,
"imageStyle": ""
}, {
"iditems": 2,
"imageStyle": ""
}]
// Generates and sanitizes image links
this.Items.map(
(LItem) => LItem.imageStyle = this.sanitizer.bypassSecurityTrustStyle("url(template/images/"+LItem.iditems+".jpg)")
)
}
How can I force the sanitizer statement to wait that the async data are fully loaded? Alternatively how can I generate sanitized properties directly in the service?
EDIT
The best answer comes from PatrickJane below:
Items: Item[] = [];
ngOnInit() {
this.collectionDataService.getItems().subscribe(Items => {
this.Items = Items;
this.Items.map(LItem => LItem.imageStyle = this.sanitizer.bypassSecurityTrustStyle("url(template/images/"+LItem.iditems+".jpg)"))}
});
}
I also solved this problem working directly in the service method (credits), but it is more verbose:
return this.http.get('app/mocksdata/items.json')
.map( (responseData) => {
return responseData.json().items;
})
.map(
(iitems: Array<any>) => {
let result:Array<Item> = [];
if (iitems) {
iitems.forEach((iitem) => {
iitem.imageStyle = this.sanitizer.bypassSecurityTrustStyle("url(template/images/"+iitem.iditems+".jpg)");
result.push(<Item>iitem);
});
}
return result;
}
)
The subscribe function is async so your map function called before the subscribe function run. So in this phase the array is undefined because you doesn't set any initial value.
The solution is to do this inside the subscribe function and to initialize the Items with empty array.
Items: Item[] = [];
ngOnInit() {
this.collectionDataService.getItems().subscribe(Items => {
this.Items = Items;
this.Items.map(LItem => LItem.imageStyle = this.sanitizer.bypassSecurityTrustStyle("url(template/images/"+LItem.iditems+".jpg)"))}
});
}