I'm learning Ang2. I ran the Hero tutorial successfully. to practice, I just added a link in the main page to a get a new component. there is a json file with a list of Radio Station. the following are my service, and the Component:
import { Radio } from '../models/radio';
import { Injectable } from '#angular/core';
import { Http, Response } from '#angular/http';
import 'rxjs/Rx';
#Injectable()
export /**
* RadioService
*/
class RadioService {
radios: Radio[] = [];
len: Number = 0;
http: Http;
constructor(http: Http) {
this.http = http;
}
getRadios() {
console.log('Radios Service is being called');
this.http.get('app/mock/FranceRadioJSON.json')
.map((res: Response) => res.json())
.subscribe((rad: Radio[]) => { // Succes
console.log('Radios Service Success');
this.radios = rad;
this.len = rad.length;
}
, err => {// Failure
console.log('Radio Services Failure');
console.error(err);
}
, // complete
() => {
console.log('Get Radios Complete');
console.log('Records NB: ' + this.len);
console.log('radios nb: ' + this.radios.length)
}
)
;
return this.radios;
}
and the Component is:
import { Component, OnInit } from '#angular/core';
import { RouteParams } from '#angular/router-deprecated';
import { Radio } from '../../models/radio';
import { RadioService } from '../../services/radio.service';
#Component({
selector: 'radio'
, templateUrl: 'app/html/radio.component.html'
, providers: [RadioService]
})
export /**
* RadioComponent
*/
class RadioComponent {
radios: Radio[] = [];
constructor(
private radioservice: RadioService) {
}
getRadios() {
this.radios = this.radioservice.getRadios();
console.log('radio component NB: ' + this.radios.length);
}
ngOnInit() {
this.getRadios()
}
}
the problem is the call of service is coming first, and no Radio is return while when the service is called with console.log I see that's is successful and get all records from JSON file. Any help would be greatly appreciated.
You can't get data this way from async calls (which is when you use Promise or Observable). Http returns and Observable. You need to subscribe() and in the callback you pass to subscribe(...) you get the data and can assign it to local properties.
And example how you can solve this:
In getRadios we don't call subscribe() and use map() instead. map() returns an Observable which allows the caller to get the data. subscribe() returns a Subscription and doesn't allow to get the response data, it only allows to cancel the subscription (which is also often handy, but not now ;-) ).
getRadios() {
console.log('Radios Service is being called');
return this.http.get('app/mock/FranceRadioJSON.json')
.map((res: Response) => res.json())
.map((rad: Radio[]) => { // Succes
console.log('Radios Service Success');
this.radios = rad;
this.len = rad.length;
});
}
We subscribe in getRadios because here we want to get the data. When we subscribe, the map() calls in getRadios are executed as well. subscribe() makes the Observable actually do its work:
getRadios() {
this.radios = this.radioservice.getRadios()
.subscribe((radios) => {
this.radios = radios;
} , err => {// Failure
console.log('Radio Services Failure');
console.error(err);
} , // complete
() => {
console.log('Get Radios Complete');
console.log('Records NB: ' + this.len);
console.log('radios nb: ' + this.radios.length)
});
// executed before the HTTP get call to the server
// console.log('radio component NB: ' + this.radios.length);
}
Because data is not returned immediately but only when the callback passed to subscribe(...) is executed you can get errors for bindings like
<div>{{radios.xxx}}</div>
when radios is still null when Angular2 already resolves the bindings in the template. To avoid errors you can use the safe-navigation (Elvis) operator
<div>{{radios?.xxx}}</div>
Angular2 doesn't try to access .xxx while radios is null.
The problem is that you are subscribing to your observable from within your service. Your service should return an Observable and then you Subscribe to it from your component.
So your service should be:
getRadios() : Observable<Radio[]> {
return this.http.get('app/mock/FranceRadioJSON.json')
.map((res: Response) => <Radio[]>res.json())
}
And your component:
getRadios() {
this.radios = this.radioservice.getRadios().subscribe(
r => {
this.radios = r;
}
...
);
}
Related
I tried to get json from tne internal json file within angular.
with this service (village.service):
import { Injectable, OnInit } from '#angular/core';
import { Http, Response } from '#angular/http';
import { environment } from '../../environments/environment';
import { Observable } from 'rxjs'
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/map';
#Injectable()
export class RecordsService {
data: any;
constructor(private http: Http) { }
getVillages(id) {
return this.http.get('../assets/data/villages.json')
.map(data => {
this.data = data.json();
return data.json();
}, err => {
if (err) {
return err.json();
}
});
}
}
and under commponet i put the:
ngOnInit() {
this.getVillages();
....
}
and here to load as the chain dropdown
onSubDistrictSelected(subDistrictId: number) {
if (subDistrictId) {
this.onLoading.emit(true);
this.customer.subDistrict = this.subDistricts.filter(c => (c.id == subDistrictId))[0].name;
this.customer.sdid = subDistrictId;
this.customer.subDistrictId = subDistrictId;
this.villages = this.getVillages().filter((item) => {
return item.subDistrictId === Number(subDistrictId)
});
this.onLoading.emit(false);
}
}
I got error when compile said: this.getVillages is not function, But is working correctly if i put the json value inside the component file:
getVillages() {
return [
{ json_data}
]
}
What I want to achieved is I want to used the JSon file instead put directly inside the commponet.
Thanks,
getVillages is a method in service, so you need to instantiate the service before you use it.
First you need to provide the RecordsService in a module, like,
app.module.ts
...
providers : [
RecordsService
]
...
And in your component,
abc.component.ts
constructor(public recordService : RecordsService) {
}
ngOnInit() {
this.recordService.getVillages();
}
Let me know if you still get the error or have some different error.
EDIT:
getVillages() is returning an Observable, so you need to subscribe in order to use the data returned.
this.recordService.getVillages().subscribe( data => {
console.log(data);
} )
I am developing angular REST application using ngrx/effects, I am using example application GIT. I am trying to replace hardcoded json data in effects, from http REST end. I am getting errors "Effect "GetTodoEffects.todo$" dispatched an invalid action" . Could you please help me in solving it. Every thing is same as git code, except effects code which is i am pasting below.
Effects code:
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/mergeMap';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/debounceTime';
import 'rxjs/add/operator/withLatestFrom'
import { of } from 'rxjs/observable/of';
import { Injectable } from '#angular/core';
import { Observable } from 'rxjs/Observable';
import { Action, Store } from '#ngrx/store';
import { Actions, Effect, toPayload } from '#ngrx/effects';
import * as Act from '../actions/app.actions';
import * as fromStore from '../reducers';
import { HttpClient } from '#angular/common/http';
#Injectable()
export class GetTodoEffects {
#Effect() todo$ = this.actions$.ofType(Act.GET_TODO)
.map(toPayload)
.withLatestFrom(this.store$)
.mergeMap(([ payload, store ]) => {
return this.http$
.get(`http://localhost:4000/data/`)
.map(data => {
return [
new Act.GetTodoSuccess({ data: data })
]
})
.catch((error) => {
return [
new Act.GetTodoFailed({ error: error })
]
})
});
constructor(
private actions$: Actions,
private http$: HttpClient,
private store$: Store<fromStore.State>
) {}
}
I am using json-server as REST end point. json-server --port 4000 --watch expt-results-sample.json
expt-results-sample.json
[
{
text: "Todo 1"
},
{
text: "Todo 2"
},
{
text: "Todo 3"
}
]
})
]
First thing I suspect is the array. Try changing it to an observable.
return this.http$
.get(`http://localhost:4000/data/`)
.map(data => {
// You don't need an array because it's only 1 item
// If you want array use `Observable.from([ /* actions here */ ])`
// but then you'll need to change `map` above to
// `mergeMap` or `switchMap`
// (no big difference for this use case,
// `switchMap` is more conventional in Ngrx effects)
return new Act.GetTodoSuccess({ data: data });
})
.catch((error) => {
// You probably haven't called this yet,
// but `catch` must return `Obsrvable`
// Again, if you want an array use `Observable.from([ /* array */ ])`
return Observable.of(
new Act.GetTodoFailed({ error: error })
);
})
I have trying to get json data from when i calling service method. I got a return object but i didn't get json data. Which part i have to change?
"goods.services.ts"
getAllData(): Observable<Product>{
let jwtTok1 ="Something";
let headers = new Headers();
headers.append('Content-Type', 'application/json');
headers.append('Authorization', 'Token ' + jwtTok1);
let options = new RequestOptions({ headers: headers, body: {} });
return this.http.get(BASE_URL_GOODS, options)
.map((res:Response) => {return Observable.of ({type: "success", payload: res.json().data})})
.catch(error => this.handleError(error));
}
Another is test case file "goods.component.spec.ts"
import {
inject,
TestBed,fakeAsync,tick
} from '#angular/core/testing';
import { Component } from '#angular/core';
import {
BaseRequestOptions,
ConnectionBackend,
Http
} from '#angular/http';
import { MockBackend,MockConnection } from '#angular/http/testing';
// Load the implementations that should be tested
import { Observable } from 'rxjs/Rx';
import { AppState } from '../app.service';
import { ActionReducer, Action, Store } from '#ngrx/store';
import { AppStore } from '../models/appstore.model';
import {goodsDescriptionComponent } from './goods-desc.component';
import { goodsService } from '../common/service/goods.service';
import { goodsReducer } from '../common/reducers/goods.reducer';
import {provideStore} from '#ngrx/store';
import { goods} from '../common/models/goods.model';
import { Input } from '#angular/core';
describe('GoodsDescriptionComponent', () => {
//let store:Store<AppStore>;
beforeEach(() => TestBed.configureTestingModule({
providers: [
BaseRequestOptions,
MockBackend,
{
provide: Http,
useFactory: function(backend: ConnectionBackend, defaultOptions: BaseRequestOptions) {
return new Http(backend, defaultOptions);
},
deps: [MockBackend, BaseRequestOptions]
},
goodsService, provideStore({goodsData: goodsReducer}),goodsDescriptionComponent
]}));
it('should url will be same ',
inject(
[goodsService, MockBackend],
fakeAsync((service:ProductsService, backend: MockBackend) => {
backend.connections.subscribe((connection: MockConnection) => {
expect(connection.request.url).toBe(
'http://localhost:3001/goodsMS/');
});
service.getAllData();
console.log("goods what we got: ",service.getAllData());
})));
});
Getting Response Result is,
This Response object getting from console in google chrome. Still i can't get correct solution for getting json data from service method call.i can't reach json server. my json server URL is , "http://localhost:3001/goods". please anyone help me. Thanks in advance.
You need to set a response on the connection
backend.connections.subscribe((connection: MockConnection) => {
expect(connection.request.url).toBe(
'http://localhost:3001/goodsMS/');
connection.mockRepond(new Response(new ResponseOptions({
body: `{"some":"json", "response":"body"}`
}));
});
You need to subscribe to your service call
service.getAllData().subscribe((result) => {
expect(somethingWithData)
})
tick()
since you are using fakeAsync, you need to tick to force completion of the asynchronous observable. If you use async instead of fakeAsync, then you don't need to call tick
You should not be returning an Observable in the service method map function. Just return a normal object.
.map((res:Response) => {type: "success", payload: res.json().data})
Yes another Aurelia question, apologies!
So I'm trying to access data within my view passed from a model, whilst I can see the data within the response, I cannot seem to get it to display on the view. Any help greatly appreciated.
I've tried a few things but I guess being new to Aurelia,ES6 and promises, it's throwing me out a little or I've been staring at to long.
//EDIT Data Access Component
import {inject} from "aurelia-framework";
import {HttpClient} from "aurelia-http-client";
let baseUrl = "/FormDesigner";
#inject(HttpClient)
export class FormData{
constructor(httpClient)
{
this.http = httpClient;
}
GetFormById(formId)
{
return this.http.get(`${baseUrl}/GetFormById/${formId}`)
.then(f => f.content);
};
}
Model:
activate(params)
{
return this.form.GetFormById(params.formId)
.then(f => this.form = f);
}
The View:
<p class="navbar-text navbar-left">
${form.name}
</p>
The Response:
{"Id":"x","OrganisationId":"x","OrganisationDepartmentId":null,"ScheduleId":null,"DefinitionTypeId":"x","ReferenceNumber":11171,"Name":"New Form Test External Access","Description":"","IsTemplate":true,"IsActive":true,"IsSingleFormTemplate":false,"MinimumInstances":null,"MaximumInstances":null,"IsAdhocCreationEnabled":false,"HasCalculation":false,"Calculation":null,"Recalculate":true,"IsHidden":false}
So again I don't see the data appearing on the view and I feel I'm missing something rather simple.
//EDITS
So after a little digging I made a little change to my API returning a JSON array rather than a JSON object and also switched Aurelia to use Fetch... So now I can access the data in my data component but not my model - rather frustrating!
import {inject} from "aurelia-framework";
//import {HttpClient} from "aurelia-http-client";
//import 'fetch';
import {HttpClient} from 'aurelia-fetch-client';
let baseUrl = "/FormDesigner";
#inject(HttpClient)
export class FormData{
constructor(httpClient)
{
httpClient.configure(config => {
config
.withBaseUrl('/FormDesigner')
.withDefaults({
credentials: 'same-origin',
headers: {
'Accept': 'application/json',
'X-Requested-With': 'Fetch'
}
})
.withInterceptor({
request(request) {
console.log(`Requesting ${request.method} ${request.url}`);
return request;
},
response(response) {
console.log(`Received ${response.status} ${response.url}`);
return response;
}
});
});
this.http = httpClient;
}
GetFormById(formId)
{
return this.http.fetch(`/GetFormById/${formId}`)
.then(response => response.json())
.then(data => {
//Log here, to check incoming data
console.log("From component: " + data.Name);
//This WORKS
});
};
}
Again I've created an abstraction where as my model does not need to know about calls to the server.
import {inject} from "aurelia-framework";
import {FormData} from "form/formData";
#inject(FormData)
export class Form
{
constructor(formData)
{
this.form = formData;
}
activate(params)
{
if(params.formId != null)
{
return this.form.GetFormById(params.formId)
.then(data =>
{
this.form = data
console.log(this.form.Name);
//This does not work!!
});
}
else
{
//Show message that param does not exist or redirect to no form page
console.log("No Id");
}
}
}
Any help greatly appreciated,
Most likely you need to deserialize the JSON response into a Javascript object using JSON.parse.
GetFormById(formId)
{
return this.http.get(`${baseUrl}/GetFormById/${formId}`)
.then(response => JSON.parse(response.content));
};
Hi I am new to Angular and I have been trying to learn Angular 2 so be gentle :).
I have been trying to use WordPress as my data API using WP API plugin. And have so far been able to get posts from WordPress. And below is my code for the data service.
import {Injectable} from "angular2/core";
import {Http, Response} from 'angular2/http';
import {Observable} from 'rxjs/Rx';
import {PostInterface} from './data.interface';
import {Headers} from "angular2/http";
import {RequestOptions} from "angular2/http";
#Injectable()
export class DataService{
private _dataURL : string = 'http://localhost/wordpress/?rest_route=/wp/v2/posts';
posts : PostInterface [];
post : PostInterface;
errorMessage : string;
constructor(private http:Http){}
getPosts():Observable<any[]>{
//return this.http.get(this._dataURL).map((res:Response) => res.json());
return this.http.get(this._dataURL)
.map(res=>res.json())
//.do(data => console.log(data)) // eyeball results in the console
.catch(this.handleError);
}
//todo fix search
getPost(filterid:number):Observable<any[]>{
//filterid is the id of a specific post
this._dataURL = this._dataURL + '/' + filterid;
return this.http.get(this._dataURL)
.map(res => res.json())
.catch(this.handleError);
}
private handleError (error: Response) {
console.error(error);
return Observable.throw(error.json().error || 'Server error');
}
}
In the code I get all the post data using the getPosts() method but I also have a getPost() method to fetch specific post.
I was wondering if I could use the JSON data fetched by getPosts() and use it again in getPost() method. Currently what the getPost() does is call the http.get again I do not want to make http.get request again and again.
I want the getPosts() to make one request, fetch the data and store is somewhere so that other methods can use the data and do their specific manipulations.
Thanks
Yes you can firstly fetch your all data and save into one variable or another methods is where you subscribing your data perform for loop and match with your filterId where the process matches store that data into array and implement your manipulation according to need. here is example assuming your data is in array form..
import {Injectable} from "angular2/core";
import {Http, Response} from 'angular2/http';
import {Observable} from 'rxjs/Rx';
import {PostInterface} from './data.interface';
import {Headers} from "angular2/http";
import {RequestOptions} from "angular2/http";
#Injectable()
export class DataService{
private _dataURL : string = 'http://localhost/wordpress/?rest_route=/wp/v2/posts';
posts : PostInterface [];
post : PostInterface;
errorMessage : string;
constructor(private http:Http){}
getPosts():Observable<any[]>{
//return this.http.get(this._dataURL).map((res:Response) => res.json());
return this.http.get(this._dataURL)
.map(res=>{
if(res.json()){
return res.json()
}
});
//.do(data => console.log(data)) // eyeball results in the console
.catch(this.handleError);
}
// Method in any file where you want to subscribe your data and wanna fetch specific post //
singlePost: Array<any>= [];
methodName(filterid:number){
service.getPosts()
.subscribe(res=>{
console.log(res) // Here you data whihc is coming from .map i.e getPosts methods using Http
for(let i=0; i< res.length ; i++){ // I am asuming your data is in array from so performing length functionality
if(filterid == res[i].filterid){
this.singlePost = res[i];
break;
}
}
console.log(this.singlePost) // This will return your single Specific POst without using `Http` again and again
})
}
You could try something like that using the do operator to save the data into your service when the getPosts result is received:
#Injectable()
export class DataService{
private _dataURL : string = 'http://localhost/wordpress/?rest_route=/wp/v2/posts';
posts : PostInterface [];
post : PostInterface;
errorMessage : string;
constructor(private http:Http){}
getPosts():Observable<any[]>{
//return this.http.get(this._dataURL).map((res:Response) => res.json());
return this.http.get(this._dataURL)
.map(res=>res.json())
.do(data => this.posts = data) // <--------
.catch(this.handleError);
}
findPostById(id) {
if (this.posts != null) {
return this.posts.find(((element, index, array) {
return (element.id = id);
});
} else {
return null;
}
}
getPost(filterid:number):Observable<any[]>{
var post = findPostById(filterid);
if (post != null) { // <--------
return post;
} else {
this._dataURL = this._dataURL + '/' + filterid;
return this.http.get(this._dataURL)
.map(res => res.json())
.catch(this.handleError);
}
}
Feel free to adapt this code to your needs.