How to load json api data to html template in angular? - django

Can anyone help me with a simple question(I guess). I'm trying to display a json file in a table through Django into an Angular front end app. I can view the data by console logging it, however I can't seem to get the data into the webpage.
I know how to display the table in HTML. The specific problem is that the object which is fetched from the API does not appear in the HTML.
component.ts
import { AfterViewInit, ChangeDetectionStrategy, Component, OnDestroy, OnInit, ViewChild,
ViewEncapsulation } from '#angular/core';
import ApexChart from 'apexcharts'
import { ApexOptions } from 'ng-apexcharts';
import { FinanceService } from 'app/modules/admin/dashboards/finance/finance.service';
#Component({
selector: 'app-finance',
templateUrl: './finance.component.html',
styleUrls: ['./finance.component.scss'],
encapsulation : ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class FinanceComponent implements OnInit {
_stockData: any;
_portData: any;
_effData: any;
_calData: any;
_labels: any;
_table: any;
constructor(
private _financeService: FinanceService,
){
}
ngOnInit(): void {
this._financeService.getFinanceData()
.subscribe((res: any) => {
console.log(res);
this._stockData = res.stocks;
this._portData = res.port;
this._effData = res.eff;
this._calData = res.cal;
this._labels = res.labels;
this._table = res.table;
console.log(res.table);
this._prepareChartData();
},
(response) => {
// Re-enable the form
});
}
Service.ts
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { catchError, switchMap } from 'rxjs/operators';
import { BehaviorSubject, of, Observable } from 'rxjs';
import { environment } from 'environments/environment';
#Injectable({
providedIn: 'root'
})
export class FinanceService {
/**
* Constructor
* #param {HttpClient} _httpClient
*/
constructor(private _httpClient: HttpClient){
}
// -----------------------------------------------------------------------------------------------------
// # Public methods
// -----------------------------------------------------------------------------------------------------
/**
* get Finance Data
*/
getFinanceData(): Observable<any>{
return this._httpClient.get(environment.baseURL + 'apiurls/', {}).pipe(
switchMap((response: any) => {
return of(response);
})
);
}
}
template.html
<div>
<p>{{_table.Percentage}}</p>
</div>
json (as presented by the django API)
{
"stocks":[],
"eff":[],
"port":[],
"cal":[],
"labels":[],
"table":{
"Percentage":{
"AD.AS":16.1,
"ASML.AS":15.67,
"AAPL":68.23
},
"Budget":{
"AD.AS":241.5,
"ASML.AS":235.05,
"AAPL":1023.45
},
"Closing":{
"AD.AS":25.22,
"ASML.AS":314.3,
"AAPL":129.04
},
"Number of stocks to buy":{
"AD.AS":10.0,
"ASML.AS":1.0,
"AAPL":8.0
},
"final":{
"AD.AS":252.0,
"ASML.AS":314.0,
"AAPL":1032.0
},
"final allocation":{
"AD.AS":15.77,
"ASML.AS":19.65,
"AAPL":64.58
},
"Diff":{
"AD.AS":-0.33,
"ASML.AS":3.98,
"AAPL":-3.65
}
}
}

To display the json data on html you may use json pipe
<pre>
{{ _table.Percentage | json }}
</pre>

Related

401 "Unauthorized" error in Django and Angular File Upload

I have created a Django and Angular application to upload files. It was working without errors until I integrated a login page. I have not been able to upload files since integration. I get 401 - "Unauthorized" error. What could have possibly gone wrong?
Auth-interceptor:
import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest,HttpErrorResponse } from "#angular/common/http";
import { Injectable } from "#angular/core";
import { catchError, Observable, throwError } from "rxjs";
import { LoginService } from "src/services/login.service";
#Injectable()
export class AuthInterceptorService implements HttpInterceptor {
constructor(private authService: LoginService) {}
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
if (this.authService.isLoggedIn()) {
const token = this.authService.getAuthToken();
console.log("intercept",token)
// If we have a token, we set it to the header
request = request.clone({
setHeaders: {Authorization: `Token ${token}`}
});
}
return next.handle(request)
}
}
fileupload.component.ts:
import { Component, OnInit } from '#angular/core';
import { FormBuilder, FormGroup } from '#angular/forms';
import { LoginService } from 'src/services/login.service';
import { FileUploader, FileLikeObject } from 'ng2-file-upload';
import { concat, Observable } from 'rxjs';
import { HttpEvent, HttpEventType } from '#angular/common/http';
#Component({
selector: 'app-fileupload',
templateUrl: './fileupload.component.html',
styleUrls: ['./fileupload.component.scss']
})
export class FileuploadComponent {
DJANGO_SERVER = 'http://127.0.0.1:8081'
public uploader: FileUploader = new FileUploader({});
public hasBaseDropZoneOver: boolean = false;
constructor(private formBuilder: FormBuilder, private uploadService: LoginService) { }
fileOverBase(event): void {
this.hasBaseDropZoneOver = event;
}
getFiles(): FileLikeObject[] {
return this.uploader.queue.map((fileItem) => {
return fileItem.file;
});
}
upload() {
let files = this.getFiles();
console.log(files);
let requests= [];
files.forEach((file) => {
let formData = new FormData();
formData.append('file' , file.rawFile, file.name);
requests.push(this.uploadService.upload(formData));
console.log(requests,file)
});
concat(...requests).subscribe(
(res) => {
console.log(res);
},
}
);
}}
console.log(err);
}
);
}}
service:
public upload(formData) {
let token= localStorage.getItem('token');
return this.http.post<any>(`${this.DJANGO_SERVER}/upload/`, formData).pipe(map((res) => {
console.log(res)
})
)
}
Thank you
I resolved the issue. It was because I was usign interceptor and I was using third party API for authentication. So instead of Django token, the third party APIs token was sent in header of POST request.
How I resolved it?
I used Httpbackend to process POST requests to Django DB so that the request is not intercepted and then I added custom header (with Django token to the reuest). I used the code snippet on this website: https://levelup.gitconnected.com/the-correct-way-to-make-api-requests-in-an-angular-application-22a079fe8413

Angular app keeps saying message does not exist

I'm building a chat app with Angular and Django using the get stream tutorial. https://getstream.io/blog/realtime-chat-django-angular/
However, I'm trying to run the app to create the chat view but it keeps saying 'messages' does not exist at the point marked 'this point' in the code.
import { Component, OnInit } from '#angular/core';
import { Router } from '#angular/router';
import { MessageResponse, Channel } from 'stream-chat';
import { StreamService } from '../stream.service';
import { StateService } from '../state.service';
declare const feather: any;
#Component({
selector: 'app-chat',
templateUrl: './chat.component.html',
styleUrls: ['./chat.component.scss'],
})
export class ChatComponent implements OnInit {
constructor(
public streamService: StreamService,
private stateService: StateService,
private router: Router
) {}
messages: MessageResponse[] = [];
message = '';
channel!: Channel;
async sendMessage() {
if (this.message) {
try {
await this.channel.sendMessage({
text: this.message,
});
this.message = '';
} catch (err) {
console.log(err);
}
}
}
getClasses(userId: string): { outgoing: boolean; incoming: boolean } {
const userIdMatches = userId === this.streamService.currentUser.messages.id; (this point)
return {
outgoing: userIdMatches,
incoming: !userIdMatches,
};
}
}

angular not displaying object attributes

I am following the HeroTutorial but using a Django backend. I have an Hero object that I am getting from DRF endpoint (verified with Postman). In my hero-detail.html the hero.name and hero.id are not displaying anything.
I know the hero object is being passed to the hero-detail.html because the browser shows the "Details" and "id:" so the line <div *ngIf="hero"> is telling me that there is a hero..
But if there is a hero why does hero.name not show anything?
There are no errors in the browser console. The link to get to the hero-detail.component is coming from a dashboard.component which uses the same method but for some reason hero.name and hero.number work fine. The dashboard.component.html displays correctly so I know my services are working fine.
My hero-detail.html
<div *ngIf="hero">
<h2>{{hero.name | uppercase}} Details</h2>
<div><span>id: </span>{{hero.number}}</div>
<div>
<label>name:
<input [(ngModel)]="hero.name" placeholder="name">
</label>
</div>
</div>
<button (click)="goBack()">go back</button>
hero-detail.component
import { Component, OnInit, Input } from '#angular/core';
import { Hero } from '../hero'
import { ActivatedRoute } from '#angular/router';
import { Location } from '#angular/common';
import { HeroService } from '../hero.service';
#Component({
selector: 'app-hero-detail',
templateUrl: './hero-detail.component.html',
styleUrls: ['./hero-detail.component.scss']
})
export class HeroDetailComponent implements OnInit {
constructor(
private route: ActivatedRoute,
private heroService: HeroService,
private location: Location
) {}
#Input() hero: Hero;
ngOnInit(): void {
this.getHero();
}
getHero(): void {
const number = +this.route.snapshot.paramMap.get('number');
this.heroService.getHero(number)
.subscribe(hero => this.hero = hero);
}
goBack(): void {
this.location.back();
}
}
dashboard.component
import { Component, OnInit } from '#angular/core';
import { Hero } from '../hero';
import { HeroService } from '../hero.service';
#Component({
selector: 'app-dashboard',
templateUrl: './dashboard.component.html',
styleUrls: [ './dashboard.component.scss' ]
})
export class DashboardComponent implements OnInit {
heroes: Hero[] = [];
constructor(private heroService: HeroService) { }
ngOnInit() {
this.getHeroes();
}
getHeroes(): void {
this.heroService.getHeroes()
.subscribe(heroes => this.heroes = heroes.slice(1, 5));
}
}
dashboard.html
<h3>Top Heroes</h3>
<div class="grid grid-pad">
<a *ngFor="let hero of heroes" class="col-1-4"
routerLink="/detail/{{hero.number}}">
<div class="module hero">
<h1>{{hero.name}}</h1>
</div>
</a>
</div>
hero.service
import { Injectable } from '#angular/core';
import { Hero } from './hero';
import { HEROES } from './mock-heroes';
import { Observable, of } from 'rxjs'
import { HttpClient, HttpHeaders } from '#angular/common/http'
import { catchError, map, tap } from 'rxjs/operators';
#Injectable({
providedIn: 'root'
})
export class HeroService {
private heroesUrl = 'http://127.0.0.1:8000/heroes/'; // URL to web api
constructor(
private http : HttpClient
) { }
/**
* Handle Http operation that failed.
* Let the app continue.
* #param operation - name of the operation that failed
* #param result - optional value to return as the observable result
*/
getHeroes (): Observable<Hero[]> {
return this.http.get<Hero[]>(this.heroesUrl)
}
getHero(number:number): Observable<Hero>{
return this.http.get<Hero>(`${this.heroesUrl}${number}`);
}
// getHero(number: number): Observable<Hero> {
// return of(HEROES.find(hero => hero.number === number));
//}
}
hero.service endpoint response from localhost:8000/heroes/2, taken from Postman:
[
{
"name": "better hero",
"number": 2
}
]
also hero.service endpoint response from localhost:8000/heroes, taken from Postman:
[
{
"name": "bad hero",
"number": 7
},
{
"name": "bad hero",
"number": 7
},
{
"name": "better hero",
"number": 2
}
]
views.py
class HeroList(generics.ListAPIView):
queryset = Hero.objects.all()
serializer_class = HeroSerializer
class Meta:
model = Hero
fields = ('number', 'name')
class HeroDetail(generics.GenericAPIView):
serializer_class = HeroSerializer
#TODO why do i need many=True here, this should returning one instance
def get(self, request, number):
# number = self.request.query_params.get('number')
hero_detail = Hero.objects.filter(number=number)
serializer = HeroSerializer(hero_detail, many=True)
return Response(serializer.data)
class Meta:
model = Hero
fields = ('number', 'name')
Looking at the sample API responses you've posted, it looks like retrieve method for a hero (/heroes/2 for instance) returns a list with only one item, instead of returning the item itself. In your client code though, you expect a hero object, not a hero list. Depending on your client code and for a rest api in general,
localhost:8000/heroes/2 should return
{
"name": "better hero",
"number": 2
}
not
[
{
"name": "better hero",
"number": 2
}
]

cordova.fileTransfer not updating page template Ionic2+Cordova

I have created an Ionic2 App using cordova FileTransferplugin, i am downloading remote server file.
Everything is working perfectly, but when I try to update template while fileTransfer.OnProgress event, the template is not updating the % downloaded.
Pleas see this video for my problem.
Ionic_youtube_link
My Code is, logic is in downloadFile function
import {Component, AfterViewInit, ViewChild} from '#angular/core';
import {NavController, NavParams, ViewController, Nav} from 'ionic-angular';
import {Page, Platform} from 'ionic-angular';
import {File, Device, Cordova, Transfer} from 'ionic-native';
import { SafeResourceUrl, DomSanitizationService } from '#angular/platform-browser';
#Component({
templateUrl: 'build/pages/video-download-modal/video-download-modal.html',
providers: [File, Transfer]
})
export class VideoDownloadModal {
selectedItem: any;
#ViewChild(Nav) nav: Nav;
videoPathUrl: string;
isPlatformReady: boolean;
platformName: string;
directoryName: string = "socialAppDir";
totalVideoSize:number;
totalDownloaded:number;
totalPercent:string = "0%";
constructor(public navCtrl: NavController, navParams: NavParams, private _viewController: ViewController, platform: Platform, private transfer:Transfer) {
// If we navigated to this page, we will have an item available as a nav param
if (platform.is('core')) {//if on dekstop
console.log('dektop');
} else {
this.videoPathUrl = navParams.get('videoPath');
console.log(this.videoPathUrl);
platform.ready().then((readySource) => {
this.isPlatformReady = true;
console.log('ready 1234');
const fs: string = cordova.file.externalRootDirectory;
console.log(cordova.file.dataDirectory);
this.platformName = Device.device.platform;
File.checkDir(cordova.file.externalDataDirectory, this.directoryName).then(() => {
console.log('directory exists');
this.downloadFile();
}, (error) => {
console.log('directory not exists');
this.createDirectory();
})
})
}
}
dismiss() {
let data = { 'foo': 'bar' };
this._viewController.dismiss(data);
}
createDirectory():void{
File.createDir(cordova.file.externalDataDirectory, this.directoryName, true).then(() => {
console.log("created externalDataDirectory");
this.downloadFile();
},(error) => {
console.log('some error happen')
})
}
downloadFile = () => {
console.log(this);
let fileName: string = this.videoPathUrl.split("/").pop();
let targetPath = cordova.file.externalDataDirectory + this.directoryName + "/" + fileName;
console.log(targetPath);
this.transfer.download(this.videoPathUrl, targetPath, true, {}).then(() => {
console.log('video downloaded')
}, (error) => {
console.log(error)
})
this.transfer.onProgress((progress) => {
console.log(this);
this.totalVideoSize = progress.total;
this.totalDownloaded = progress.loaded;
this.totalPercent = ((progress.loaded / progress.total) * 100).toString();
console.log(this.totalPercent);
})
}
ionViewDidEnter() {
console.log("enter login1");
}
}
And HTML is
<ion-content>
<div id="modalContainer" class="abd">
<ion-spinner></ion-spinner>
<br />
{{**totalPercent**}}
<br />
<button dnager block (click)="dismiss()">Exit</button>
</div>
</ion-content>
The totalPercent value either has 0 or 100.But not updating.
Please help.
This is because the totalPercent of this inside the handler was set to the global Window object instead of the object itself.
I have finally got it to work
import { NgZone } from '#angular/core';
fileTransfer.onProgress((progressEvent: ProgressEvent) => {
this.ngZone.run(() => {
if (progressEvent.lengthComputable) {
let lp = progressEvent.loaded / progressEvent.total * 100;
this.loadingPercent = Math.round(lp * 100) / 100;
}
});
})

Angular2 - Testing ngOninit in Components

I have a listing component with following code:
///<reference path="../../node_modules/angular2/typings/browser.d.ts"/>
import { Component, OnInit } from 'angular2/core';
import { ROUTER_DIRECTIVES } from 'angular2/router';
import { Employee } from '../models/employee';
import { EmployeeListServiceComponent } from '../services/employee-list-service.component';
#Component({
selector: 'employee-list',
template: `
<ul class="employees">
<li *ngFor="#employee of employees">
<a [routerLink]="['EmployeeDetail', {id: employee.id}]">
<span class="badge">{{employee.id}}</span>
{{employee.name}}
</a>
</li>
</ul>
`,
directives: [ROUTER_DIRECTIVES],
providers: [EmployeeListServiceComponent]
})
export class EmployeeListComponent implements OnInit {
public employees: Employee[];
public errorMessage: string;
constructor(
private _listingService: EmployeeListServiceComponent
){}
ngOnInit() {
this._listingService.getEmployees().subscribe(
employees => this.employees = employees,
error => this.errorMessage = <any>error
);
}
}
I wish to write unit tests for the ngOninit hook. I have written following test:
/// <reference path="../../typings/main/ambient/jasmine/jasmine.d.ts" />
import {
it,
describe,
expect,
TestComponentBuilder,
injectAsync,
setBaseTestProviders,
beforeEachProviders,
} from "angular2/testing";
import { Component, provide, ApplicationRef, OnInit } from "angular2/core";
import {
TEST_BROWSER_PLATFORM_PROVIDERS,
TEST_BROWSER_APPLICATION_PROVIDERS
} from "angular2/platform/testing/browser";
import {
ROUTER_DIRECTIVES,
ROUTER_PROVIDERS,
ROUTER_PRIMARY_COMPONENT,
APP_BASE_HREF
} from 'angular2/router';
import {XHRBackend, HTTP_PROVIDERS} from "angular2/http";
import { MockApplicationRef } from 'angular2/src/mock/mock_application_ref';
import {MockBackend } from "angular2/src/http/backends/mock_backend";
import {Observable} from 'rxjs/Rx';
import 'rxjs/Rx';
import { Employee } from '../models/employee';
import { EmployeeListComponent } from './list.component';
import { EmployeeListServiceComponent } from '../services/employee-list-service.component';
class MockEmployeeListServiceComponent {
getEmployees () {
return Observable.of([
{
"id": 1,
"name": "Abhinav Mishra"
}
]);
}
}
#Component({
template: '<employee-list></employee-list>',
directives: [EmployeeListComponent],
providers: [MockEmployeeListServiceComponent]
})
class TestMyList {}
describe('Employee List Tests', () => {
setBaseTestProviders(TEST_BROWSER_PLATFORM_PROVIDERS, TEST_BROWSER_APPLICATION_PROVIDERS);
beforeEachProviders(() => {
return [
ROUTER_DIRECTIVES,
ROUTER_PROVIDERS,
HTTP_PROVIDERS,
provide(EmployeeListServiceComponent, {useClass: MockEmployeeListServiceComponent}),
provide(XHRBackend, {useClass: MockBackend}),
provide(APP_BASE_HREF, {useValue: '/'}),
provide(ROUTER_PRIMARY_COMPONENT, {useValue: EmployeeListComponent}),
provide(ApplicationRef, {useClass: MockApplicationRef})
]
});
it('Should be true',
injectAsync([TestComponentBuilder], (tcb) => {
return tcb
.createAsync(TestMyList)
.then((fixture) => {
fixture.detectChanges();
var compiled = fixture.debugElement.nativeElement;
console.log(compiled.innerHTML);
expect(true).toBe(true);
});
})
);
});
However, the output of console.log in the test is an empty ul tag as follows:
'<employee-list>
<ul class="employees">
<!--template bindings={}-->
</ul>
</employee-list>'
Can anyone suggest me the proper way of writing unit tests for component hooks?
SOLUTION
Mock the http request in the injectAsync block as follows:
backend.connections.subscribe(
(connection:MockConnection) => {
var options = new ResponseOptions({
body: [
{
"id": 1,
"name": "Abhinav Mishra"
}
]
});
var response = new Response(options);
connection.mockRespond(response);
}
);
However now i am getting another error as follows:
Failed: EXCEPTION: Component "EmployeeListComponent" has no route config. in [['EmployeeDetail', {id: employee.id}] in EmployeeListComponent#3:7]
ORIGINAL EXCEPTION: Component "EmployeeListComponent" has no route config.
ORIGINAL STACKTRACE:
Error: Component "EmployeeListComponent" has no route config.
If you call async code in ngOnInit() you can't assume it is completed when console.log(...) is executed. this.employees is only set when the callback you passed to subscribe(...) gets called after the response arrived.
If you use MockBackend you can control the response and after the response was passed you have to run fixture.detectChanges() again to make the component re-render with the updated data, then you can read innerHTML and expect it to contain the rendered content.