Indeed, I don't know why my url in _http.get('app/api/apiUsers') is not found while in a angular version 2.3.1 is functional but in angular version 4.0.0 it does not work.
This is my code and they are the same in both angular versions:
import { Injectable } from '#angular/core';
import { Http } from '#angular/http';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/do';
#Injectable()
export class LoginService {
constructor(private _http: Http){}
getFromApiLogin(){
console.log("I am here");
return this._http.get('app/api/apiUsers.json)
.do(x => console.log(x))
.map(res => res.json());
}
}
I assume you are using a CLI project... so it does just serve paths that you have added to the assets in the file .angular.cli.json
Try that:
"assets": [
"assets",
"favicon.ico",
"./app/api/apiUsers.json"
]
Related
I've read every other article or post about this I can find. I cannot for the life of me figure out where I'm going wrong with this simple task. (Specifically following this example.) I must be doing something obviously stupid but I've been looking at this so long I can't see it.
I have a json file called isRecognized.json in assets/mockData. I've added the mockData directory to my webpack config file so it's included in the /dist directory. If I go to http:localhost:4200/assets/mockData/isRecognized.json I'm able to see the file, so I know it's available.
However, when I try to retrieve the file using HTTP Client, it throws a 404 no matter what I try.
EDIT: I'm using Webpack, not Angular CLI.
app.component.ts
import { MyService } from './services/my.service';
import { Component, OnInit, Renderer2 } from '#angular/core';
import { ActivatedRoute } from '#angular/router';
/*
* Main app component that houses all views.
*/
#Component({
selector: 'app-comp',
templateUrl: './app.component.html'
})
export class AppComponent implements OnInit {
constructor(
private route: ActivatedRoute, private service: MyService
) {}
ngOnInit() {
this.service.isRecognized();
}
}
my.service.ts
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import 'rxjs/add/observable/throw';
#Injectable()
export class MyService {
constructor(private http: HttpClient) { }
isRecognized() {
this.getJSON('isRecognized').subscribe(data => {
console.log(data);
});
}
getJSON(fileName): Observable<any> {
return this.http.get('http://localhost:4200/assets/mockData/' + fileName + '.json');
}
}
The error I get in the browser console is:
AppComponent_Host.ngfactory.js? [sm]:1 ERROR Error: [object Object]
at viewWrappedDebugError (core.js:9795)
at callWithDebugContext (core.js:15101)
at Object.debugCheckAndUpdateView [as checkAndUpdateView] (core.js:14628)
at ViewRef_.webpackJsonp../node_modules/#angular/core/esm5/core.js.ViewRef_.detectChanges (core.js:11605)
at core.js:5913
at Array.forEach (<anonymous>)
at ApplicationRef.webpackJsonp../node_modules/#angular/core/esm5/core.js.ApplicationRef.tick (core.js:5913)
at core.js:5746
at ZoneDelegate.webpackJsonp../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke (zone.js:391)
at Object.onInvoke (core.js:4756)
If I debug the error, I can see the body of the error is:
I have this working successfully in my app just using a URL like this:
private productUrl = 'api/products/products.json';
Notice that it does not have the localhost part of the path.
So try something more like this:
'assets/mockData/' + fileName + '.json'
Also ensure that your angular.json has the path listed under assets:
"assets": [
"src/favicon.ico",
"src/assets",
"src/api"
],
NOTE: I also didn't do anything to modify my webpack configuration. (But I'm using the CLI.)
If you want to look at some working code that accesses a json file, I have an example here:
https://stackblitz.com/edit/github-gettingstarted-deborahk
I would suggest subscribing in the component, and returning an Observable from the service:
Service:
#Injectable()
export class MyService {
constructor(private http: HttpClient) { }
isRecognized(fileName): Observable<any> {
return this.http.get('http://localhost:4200/assets/mockData/' + fileName + '.json');
}
}
Component:
export class AppComponent implements OnInit {
constructor(
private route: ActivatedRoute, private service: MyService
) {}
ngOnInit() {
this.service.isRecognized(fileName)
.subscribe(data => {
console.log(data);
});
}
}
While this might not be a direct solution to your specific problem, you should take a look at the npm package json-server. I use it to mock the API when developing and testing the client.
json-server npm
It will run a node web server on port 3000, and is really easy to use right out of the box.
See this tutorial example of how to use it:
Mock api with json-server
There might be better examples and setting up the proxy isn't necessary, but should be good enough.
Finally figured out the answer! I had this in my app.module.ts file as an import:
InMemoryWebApiModule.forRoot(InMemoryDataService, { dataEncapsulation: false })
Removing this fixed the issue immediately.
I am using proxy.conf.json as I develop my Angular application.
However I would like to, for a few endpoints, simply return a JSON object when called. Currently my proxy.conf file redirects to a locally running backend which returns these JSONs. However I'd rather not run the backend server and simply return the JSON from proxy.conf.json.
Is this possible somehow?
It is possible by using proxy.conf.js instead of proxy.conf.json. Then you can specify a bypass function where you can return a response directly. This is mentioned in the angular-cli documentation for the proxy but it does not give many details. Here is a sample proxy.conf.js file to do it.
const PROXY_CONFIG = {
'/api': {
'target': 'http://localhost:5000',
'bypass': function (req, res, proxyOptions) {
switch (req.url) {
case '/api/json1':
const objectToReturn1 = {
value1: 1,
value2: 'value2',
value3: 'value3'
};
res.end(JSON.stringify(objectToReturn1));
return true;
case '/api/json2':
const objectToReturn2 = {
value1: 2,
value2: 'value3',
value3: 'value4'
};
res.end(JSON.stringify(objectToReturn2));
return true;
}
}
}
}
module.exports = PROXY_CONFIG;
You need to recheck the url in the bypass function because it is called for all /api requests and then you just directly return a response for the ones you want the others will still be redirected to the target address. You return true to tell the proxy the request finished.
Make sure to then specify the correct file when running ng serve --proxy-config proxy.conf.js.
For returning JSON from proxy.config.conf, there doesn't seem to be an easy way to do it.
One way would be to have a baseApiUrl in the environment.ts file as well urlSuffix set to .json. Then all of the API calls would have to be something like this: enviroment.baseApiUrl + uri + environment.urlSuffix. Then in environment.prod.ts, the urlSuffix would be an empty string. This is a hacky solution but would work.
Alternative using HTTP_INTERCEPTORS
A cleaner solution that leverages the framework, would be to use an HttpInterceptor with the HttpClient along with setting the baseApiUrl in the environment.ts file. This allows for different API endpoints per environment.
environment.ts
export const environment = {
apiBaseUrl: 'http://localhost:4200/assets/api',
production: false
}
development.interceptor.ts
import {Injectable} from '#angular/core';
import {HttpEvent, HttpHandler, HttpInterceptor, HttpRequest} from '#angular/common/http';
import {Observable} from 'rxjs/Observable';
import {environment} from '../environments/environment';
#Injectable()
export class DevelopmentInterceptor implements HttpInterceptor {
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
let clonedRequest = null;
if (!environment.production) {
clonedRequest = request.clone({
url: `${request.url}.json`
});
return next.handle(clonedRequest);
}
return next.handle(clonedRequest);
}
}
This class will intercept any http request made by the HttpClient. Using the properties in the environment.ts file, you can check if the current build is a production build. If it is, clone the request and append .json to it. Anything that is in the assets folder is accessible from the browser. Below is a sample file that maps to the url http:localhost:4200/assets/api/test.json.
/src/assets/api/test.json
{
"name": "test",
"description": "Test Data"
}
Place this file in the assets directory and have the directory structure follow the endpoints of the actual API.
test.service.ts
import {Injectable} from '#angular/core';
import {HttpClient} from '#angular/common/http';
import {Observable} from 'rxjs/Observable';
import {environment} from '../environments/environment';
#Injectable()
export class TestService {
private baseUrl = `${environment.apiBaseUrl}/test`;
constructor(private http: HttpClient) {
}
getTestData(): Observable<any> {
return this.http.get(this.baseUrl);
}
}
Import the environment.ts file here and set the base url to the apiBaseurl property. As long as you import the environment.ts file and not the environment.prod.ts file, this will work in all environments as the appropriate environment file will be read from when the app is built. So this url only has to be change in one place per environment.
Angular CLI Build Targets & Environment Files
app.component.ts
import {Component, OnInit} from '#angular/core';
import {TestService} from './test.service';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
title = 'app';
constructor(private testService: TestService) {
}
ngOnInit() {
this.testService.getTestData().subscribe(
(testData) => console.log(testData)
);
}
}
Here the TestService is injected into the AppComponent and the getTestData() method is called to fetch data from the API. The DevelopmentInterceptor checks the environment and appends .json to the request. Then the data is logged to the console.
app.module.ts
import {BrowserModule} from '#angular/platform-browser';
import {NgModule} from '#angular/core';
import {HTTP_INTERCEPTORS, HttpClientModule} from '#angular/common/http';
import {AppComponent} from './app.component';
import {DevelopmentInterceptor} from './development.interceptor';
import {TestService} from './test.service';
#NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
HttpClientModule
],
providers: [
TestService,
{
provide: HTTP_INTERCEPTORS,
useClass: DevelopmentInterceptor,
multi: true
}
],
bootstrap: [AppComponent]
})
export class AppModule {
}
Register the TestService and the DevelopmentInterceptor as providers.
Using this setup, proxy.config.json is not necessary.
For more information on HttpInterceptors, there is the Angular Documentation Intercepting Http Requests & Responses.
There is also a tutorial by Jason Watmore that does some more advanced things with this approach. Angular 5 - Mock Backend Example for Backendless Development
I am trying to load a json file into my Angular app, but can't find the culprit. It keeps telling me it can't resolve all parameters of my component.
(loading the data directly from the component worked, so it has to do with the code I added most recently for loading data from a json file)
My module:
import { NgModule} from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { HttpModule } from '#angular/http';
import { Injectable } from '#angular/core';
import { Http, Response } from '#angular/http';
import 'rxjs/Rx';
import {Observable} from 'rxjs/Observable';
import { AppComponent } from './component.app';
#Injectable()
export class Service {
constructor(private _http: Http) {}
getData(){
return this.http.get('./assets/data/data.json')
.map(res => res.json())
}
}
#NgModule({
imports: [
BrowserModule,
HttpModule
],
declarations: [
AppComponent
],
bootstrap: [
AppComponent
],
providers: [
Service
]
})
export class AppModule {}
My component:
import { Component } from '#angular/core';
#Component({
selector: 'app',
templateUrl: './assets/partials/component-app.html',
styleUrls: ['./assets/css/component-app.css']
})
export class AppComponent {
tests: any;
constructor(private service : Service){}
ngOnInit() {
this.service.getData()
.subscribe(data => {
this.tests = data;
})
}
The error:
(index):18 Error: Error: Can't resolve all parameters for AppComponent: (?).
at CompileMetadataResolver.getDependenciesMetadata (http://localhost:3000/node_modules/#angular/compiler//bundles/compiler.umd.js:14404:21)
at CompileMetadataResolver.getTypeMetadata (http://localhost:3000/node_modules/#angular/compiler//bundles/compiler.umd.js:14301:28)
at CompileMetadataResolver.getDirectiveMetadata (http://localhost:3000/node_modules/#angular/compiler//bundles/compiler.umd.js:14074:30)
at eval (http://localhost:3000/node_modules/#angular/compiler//bundles/compiler.umd.js:14167:51)
at Array.forEach (<anonymous>)
at CompileMetadataResolver.getNgModuleMetadata (http://localhost:3000/node_modules/#angular/compiler//bundles/compiler.umd.js:14161:51)
at RuntimeCompiler._compileComponents (http://localhost:3000/node_modules/#angular/compiler//bundles/compiler.umd.js:16803:49)
at RuntimeCompiler._compileModuleAndComponents (http://localhost:3000/node_modules/#angular/compiler//bundles/compiler.umd.js:16741:39)
at RuntimeCompiler.compileModuleAsync (http://localhost:3000/node_modules/#angular/compiler//bundles/compiler.umd.js:16732:23)
at PlatformRef_._bootstrapModuleWithZone (http://localhost:3000/node_modules/#angular/core//bundles/core.umd.js:6954:29)
data.json, I need to loop through test_cases and Test_steps:
{
"test_run_id": "A233-CA92-3293-B9AA",
"app_name": "Chewy.com",
"time_stamp": "2018-01-20T12:00:00Z",
"test_cases": [
{
"test_name": "View dog bone",
"status": true,
"test_steps": [
{
"step_name": "Click Dog Category",
"screenshot": "file1.png",
"launch_times": [
100,
134,
123
],
HTML:
<section class="tested-app" *ngFor = "let item of tests">
<h2>----<span> {{ item.app_name }} </span>----</h2>
<p id="time"> Time: <span> {{item.time_stamp}} </span> </p>
<section class="flexWrap">
<div class="module" *ngFor="let subItem of item.test_cases">
<h3> {{ subItem.test_name }} </h3>
<p class="status"> {{subItem.status}} </p>
<div class="step" *ngFor = "let testStep of subItem.test_steps">
<h4>{{testStep.step_name}}</h4>
<img src="../assets/images/{{testStep.screenshot}}">
You need to import your service in app.component.ts
import { Service} from '...';
you also need implement OnInit
export class AppComponent implements OnInit
In your getData function, you have typo:
return this._http.get('./assets/data/data.json')
And the most important is you need put your service out of app.module.ts Why? Because it will create a circular dependency:
app.module.ts -> app.component.ts -> app.module.ts
Create a new service.ts
import { Injectable } from '#angular/core';
import { Http, Response } from '#angular/http';
import 'rxjs/add/operator/map';
#Injectable()
export class Service {
constructor(private _http: Http) {}
getData(){
return this._http.get('./assets/data/data.json')
.map(res => res.json());
}
}
Import it in app.module
import { Service } from './service';
Just like the first line:
import { Component } from '#angular/core';,
you need to add a line
import { Service } from X
where X is the path of the file which defines Service. I guess in your case you are defining Service in app.module, so try
import { Service } from ./app.module.ts
(if app.module.ts is in same directory, otherwise include path to that directory)
I'm desperate.
My problem is that I write the full path to my json file (I tried different possibilities) but it returns me an error 404 (GET http://localhost:4200/src/app/ficheros/nacionalidades.json 404 (Not Found)). I was investigating before asking the question. I dont know what I'm doing wrong and I'm not an expert. I leave my code so that you see it.
The component:
import { Component, OnInit } from '#angular/core';
import { Servicio1Service } from './../../services/servicio1.service';
#Component({
selector: 'app-componente-hijo1',
templateUrl: './componente-hijo1.component.html',
styleUrls: ['./componente-hijo1.component.css']
})
export class ComponenteHijo1Component implements OnInit {
listaPersonas: any;
constructor( private _servicio1service: Servicio1Service ) { }
ngOnInit() {
this._servicio1service.getTodasPersonas().subscribe((personas) => {
this.listaPersonas = personas;
console.log("this.listaPersonas");
console.log(this.listaPersonas);
});
}
}
The service:
import { Injectable } from '#angular/core';
import { Http } from '#angular/http';
import 'rxjs/add/operator/map';
#Injectable()
export class Servicio1Service {
constructor( private _http:Http ) { }
getTodasPersonas(){
return this._http.get("./src/app/ficheros/nacionalidades.json").map((res) => res.json());
}
}
Structure of project:
src-app-{components,ficheros,services}
Thank you in advance.
I once tried to load a local json like you but it didn't work.
The solution was to put the json file in assets folder.
Then in your code :
getTodasPersonas(){
return this._http.get("assets/nacionalidades.json").map((res) => res.json());
}
Hope it can solve your problem :)
Best regards
I can't get JSON local file Angular HTTP service. I have these codes:
import {Injectable} from '#angular/core';
import {Http, Response} from "#angular/http";
import 'rxjs/add/operator/map'
#Injectable()
export class ApiService {
constructor(private http:Http) {
}
private coinsUrl:string = 'app/data/coins.json';
getMines() {
return this.http.get(this.coinsUrl).subscribe(
(res:Response)=> {
const sss = res.json();
console.log('sss', sss);
}
);
}
}
Since you are using angular-cli that file location will not be available to you at runtime (either using ng serve or a production build). Put the file in the assets folder and then you can load /assets/coins.json.