.NET Core + Angular-CLI App - can't pass data from api to components [closed] - asp.net-web-api

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
I'm building an ASP .NET Core App with Angular-CLI using this tutorial.
App works great, I got pre-build event to ng build before starting the app in VS, it works OK. I also can successfully get to my API over localhost:port/api/[controller] (in this case it would be Contacts as it's supposed to be a contact book).
Now, I'm trying to have Angular get the data directly from API. For this reason, I created a IContact interface, a ContactService and I pass it onto ContactComponent which is supposed to display it.
I might be making a silly mistake here (my skills are very basic), but for some reason I don't even see the object .json coming in through the network logs when I run the app (before trying to pass it to the view I'm trying to ensure I'm getting the data from the API first).
I might be doing something wrong (so I encourage you to reply even if you think you might be saying silly-obvious stuff) but here's my questions:
Should my code below work (not attaching imports though, I think I got all of them but check me ;-))? I'm not talking super-efficient or stuff, just basic to get the job done.
What is the best way to see if service to getAPI is working? Would that be network logging in your browser if you just import the service into the component and try to call the get method? Or is there another way?
Is my logic and approach towards the general architecture of the app OK or am I getting something wrong? :-)
contact.service.ts
const API_URL = environment.apiUrl;
#Injectable()
export class ContactService {
constructor(private http: Http) { }
public getContacts(): Observable<IContact[]> {
return this.http.get(API_URL)
.map((response: Response) => <IContact[]>response.json())
.catch(this.handleError);
}
private handleError(error: Response) {
console.error(error);
return Observable.throw(error.json().error || 'Server error')
}
}
icontact.ts
export interface IContact {
id: number;
firstName: string,
lastName: string,
address: string,
telephone: string
}
contact.component.ts
#Component({
selector: 'app-contact',
templateUrl: './contact.component.html',
styleUrls: ['./contact.component.css'],
providers: [ContactService]
})
export class ContactComponent implements OnInit {
private _contactService: ContactService;
private contactlist: IContact[];
constructor() {
}
public ngOnInit() {
this._contactService.getContacts()
.subscribe((contacts) => { this.contactlist = contacts });
}
}
Any other code requirements or anything - let me know. All feedback is appreciated. Thanks!

I have slightly changed your code.
File icontact.ts. I have made IContact a simple type. You can make it an interface back to support your object shape.
export type IContact = string;
File contact.service.ts. We call the /api/values API that is created by default in a new ASP.NET Core Web API project if you follow the tutorial you mentioned.
import { Injectable } from "#angular/core";
import { Http } from "#angular/http";
import { Observable } from "rxjs/Observable";
import 'rxjs/add/operator/map'
import { IContact } from "./icontact";
const API_URL = '/api/values'; // environment.apiUrl;
#Injectable()
export class ContactService {
constructor(private http: Http) { }
public getContacts(): Observable<IContact[]> {
return this.http.get(API_URL)
.map(response => <IContact[]>response.json());
}
}
File contact.component.ts. The template simply displays the list.
import { Component, OnInit } from "#angular/core";
import { ContactService } from "./contact.service";
import { IContact } from "./icontact";
#Component({
selector: 'app-contact',
template: '<div *ngFor="let contact of contactList">{{contact}}</div>',
providers: [ContactService]
})
export class ContactComponent implements OnInit {
private contactList: IContact[];
constructor(private contactService: ContactService) { }
public ngOnInit() {
this.contactService.getContacts().subscribe(
(contacts) => { this.contactList = contacts; },
(error) => { console.log(error); }
);
}
}
File app.component.html. Display your component on the application's page.
<app-contact>Wait...</app-contact>
File app.module.ts. Import HttpModule. That fixes one of the error messages on your screenshot.
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import { HttpModule } from '#angular/http';
import { AppComponent } from './app.component';
import { ContactComponent } from "./contact.component";
#NgModule({
declarations: [AppComponent, ContactComponent],
imports: [BrowserModule, HttpModule],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
In the Configure method in Startup.cs, make sure you put the app.Use(...) call before app.UseStaticFiles().
Since you serve your Angular app from wwwroot by a ASP.NET Core middleware, the host is the same for the Angular app and the Web API, so you don't need to configure CORS for that setup.
By the way, you may be interested in taking a look at the Angular CLI Templates on Visual Studio Marketplace. (Disclaimer: I'm the author.) The Item Template supports your project setup out-of-the-box.

Related

Open Telemetry for react and vanilla JS projects

Can someone help me understand if there is a way to configure open Telemetry on the client side for react and vanilla JS projects all I want to do is to console the traces of fetch call that are being made from the browser.
Most of the documentation I see is only for nodejs. Pls pinpoint a documentation if there are any?
The documentation gives a common guide for Javascript. What you do for you React would be same as what you do for Node.js or even simple JS scripts.
Just follow the documentation. Create and export a tracer:
import { ZoneContextManager } from '#opentelemetry/context-zone';
import { registerInstrumentations } from '#opentelemetry/instrumentation';
import { DocumentLoadInstrumentation } from '#opentelemetry/instrumentation-document-load';
import { FetchInstrumentation } from '#opentelemetry/instrumentation-fetch';
import { UserInteractionInstrumentation } from '#opentelemetry/instrumentation-user-interaction';
import { XMLHttpRequestInstrumentation } from '#opentelemetry/instrumentation-xml-http-request';
import { ConsoleSpanExporter, SimpleSpanProcessor } from '#opentelemetry/sdk-trace-base';
import { WebTracerProvider } from '#opentelemetry/sdk-trace-web';
const setupTracer = () => {
const provider = new WebTracerProvider();
provider.addSpanProcessor(new SimpleSpanProcessor(new ConsoleSpanExporter()));
provider.register({
// Changing default contextManager to use ZoneContextManager - supports asynchronous operations - optional
contextManager: new ZoneContextManager(),
});
// Registering instrumentations
registerInstrumentations({
instrumentations: [
new DocumentLoadInstrumentation(),
new UserInteractionInstrumentation(),
new XMLHttpRequestInstrumentation(),
new FetchInstrumentation()
],
});
}
export default setupTracer;
Import the tracer like this in your app's entry point (usually index.js):
setupTracer();
ReactDOM.render(<App />, document.getElementById('root'));

angular 9 candeactivate not working although code seems to be fine and not throwing any error

Hello Guys I am new to Angular and learning the things using the following tutorial link. For some reason the canDeactivate route guard seem to not work. Any help would be appreciated as I tried checking many things but none worked. I have the latest angular CLI and there are not errors in my code and for some reason the canDeactivate function is not at all called during the route change.
I am applying the function on the CreateEmployee route so when I fill the form for createEmployee and I try to navigate to different route then it should kick in.
create-employee-component.html: In this, I have few form elements
<form #employeeForm = "ngForm" (ngSubmit)="saveEmployee()" [ngClass]="{'was-validated': employeeForm.submitted}" novalidate>
create-employee-component.ts
import { Component, OnInit, ViewChild } from '#angular/core';
import { NgForm } from '#angular/forms';
import { Department } from '../models/department.model';
import { BsDatepickerConfig } from 'ngx-bootstrap/datepicker';
import { Employee } from '../models/employee.model';
import { EmployeeService } from './employee.service';
import { Router } from '#angular/router';
#Component({
selector: 'app-create-employee',
templateUrl: './create-employee.component.html',
styleUrls: ['./create-employee.component.css']
})
export class CreateEmployeeComponent implements OnInit {
#ViewChild('employeeForm') public createEmployeeForm: NgForm;
datePickerConfig: Partial<BsDatepickerConfig>;
previewPhoto = false;
create-employee-can-deactivate-guard.service.ts
import { Injectable } from '#angular/core';
import { CanDeactivate } from '#angular/router';
import { CreateEmployeeComponent } from './create-employee.component';
#Injectable()
export class CreateEmployeeCanDeactivateGuardService implements CanDeactivate<CreateEmployeeComponent>{
canDeactivate(component: CreateEmployeeComponent): boolean{
alert("HJEJJEJEJ");
if(component.createEmployeeForm.dirty)
{
return confirm('Are you sure you want to discard your changes?');
}
return true;
}
}
app-routing.module.ts
import { NgModule } from '#angular/core';
import { Routes, RouterModule } from '#angular/router';
import { ListEmployeesComponent } from './employees/list-employees.component';
import { CreateEmployeeComponent } from './employees/create-employee.component';
import { CreateEmployeeCanDeactivateGuardService } from './employees/create-employee-can-deactivate-guard.service';
const routes: Routes = [
{path: 'list', component: ListEmployeesComponent},
{
path:'create',
component: CreateEmployeeComponent,
canDeactivate: [CreateEmployeeCanDeactivateGuardService]
},
{path: '', redirectTo:'/list', pathMatch:'full'}
];
#NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule],
providers: [CreateEmployeeCanDeactivateGuardService]
})
export class AppRoutingModule { }
I feel everything is correct as per some of the other answers I found on the StackOverflow. Please let me know what am I doing wrong here. I have also posted my code here.
I finally found out what was the issue. After some time spending on the research I found out that in the navbar previously I was using the href element with the anchor tag hence the canDeactivate guard was not kicking in. Now I changed it to [routerLink]="['/list']" and the canDeactivate started working correctly.
Posting the answer as it may be useful for someone who is looking for solution:
Previous Navbar with the anchor tag and href element:
<a class="nav-link" href="list">List <span class="sr-only">(current)</span></a>
Changed Navbar with the anchor tag and routerLink which is working fine with the canDeactivate:
<a class="nav-link" [routerLink]="['/list']">List <span class="sr-only">(current)</span></a>
If in case you are looking for the whole code please check the question where I have mentioned all the code chunks related to canDeactivate guard.

Nativescript Audio: Access Player across pages?

I am using the nativescript-audio plugin for my iOS angular NS app.
I want to start playing an audio file on one page, navigate to a different page, and manipulate the audio player from that second page. So I need to access the player instance on a page that is different than where the instance was created.
For example, start playing audio on Page 1, and then pause the player on Page 2.
How can I do this?
I have tried saving the player instance in local storage to access later, but local storage saves items as strings, so I need to convert the player instance to a string, which doesn't work.
As #Brad Martin recommended, it works to put the player in an injectable Angular service and access it app wide. So, for example:
Create the Service:
app.module.ts:
import { AudioService } from "./audio-service"
#NgModule({
...
providers: [
AudioService //registers the service with the provider's metadata
]
})
audio-service.ts:
import { Injectable, EventEmitter } from '#angular/core'
import { TNSPlayer } from "nativescript-audio"
#Injectable()
export class AudioService {
private _player: TNSPlayer;
playEvent = new EventEmitter<any>()
constructor() {}
playAudio(audioFilePath){
this._player = new TNSPlayer();
this._player.initFromFile({
audioFile: audioFilePath,
loop: false,
}).then(()=>{
this._player.play()
this.playEvent.emit('File is playing now')
})
}
pausePlayer(){
this._player.pause()
}
}
Access the Service:
cool-component.ts:
import {OnInit} from #angular/core"
import { AudioService } from "~/audio-service"
import { Page } from "tns-core-modules/ui/page"
#Component({...})
export class CoolComponent implements OnInit {
public getPlay: any;
constructor(private _audioService: AudioService) {}
ngOnInit(): void {
this.getPlay = this._audioService.playEvent.subscribe((value)=>{
console.log(value) //when audio is playing, should say 'File is playing now'
}
this.page.on('navigatingFrom', (data) => {
if (this.getPlay){
this.getPlay.unsubscribe() //unsubscribe from service emitter when exit the page--to avoid multiplying the subscription every time you go to this page
})
}
playAudioFromService(audioFilePathDetail){
this._audioService.playAudio(audioFilePathDetail)
}
pauseAudioFromService(){
this._audioService.pausePlayer()
}
}

Navigating from single page view to side-menu layout in ionic 4

I'd like to build an app using Ionic 4 that simplistically works the following way:
On-boarding page is shown with some images/text
After user clicked 'start' button, some flag onboarded=true is written into local-storage
User redirected to the main app view which is a ion-split-pane containing side-menu layout
Next time when user launches the app, I check if he/she already viewed on-boarding screen (by checking presence of onboarded var in storage) and if it is - I immediately redirect the user to the main app having side-menu layout as I mentioned, omitting on-boarding screen.
I started the project using ionic cli, based on side-menu template and to fulfill logic described above, I modified it the following way:
app.component.ts
import { Component } from '#angular/core';
import { Platform } from '#ionic/angular';
import { SplashScreen } from '#ionic-native/splash-screen/ngx';
import { StatusBar } from '#ionic-native/status-bar/ngx';
import { Storage } from '#ionic/storage';
import { Router } from '#angular/router';
#Component({
selector: 'app-root',
template: '<router-outlet></router-outlet>',
})
export class AppComponent {
constructor(
private platform: Platform,
private splashScreen: SplashScreen,
private statusBar: StatusBar,
private storage: Storage,
private router: Router
) {
this.initializeApp();
}
async initializeApp() {
await this.platform.ready();
this.statusBar.styleDefault();
this.splashScreen.hide();
const onboarded = await this.storage.get('onboarded');
if (onboarded) {
this.router.navigate(['main-app']);
} else {
this.router.navigate(['onboarding']);
}
}
}
onboarding.page.html
<ion-header>
<ion-toolbar>
<ion-title>onboarding</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
Welcome aboard!
<ion-button (click)="start()">Start app!</ion-button>
</ion-content>
onboarding.page.ts
import { Component } from '#angular/core';
import { Storage } from '#ionic/storage';
import { Router } from '#angular/router';
#Component({
selector: 'app-onboarding',
templateUrl: './onboarding.page.html',
styleUrls: ['./onboarding.page.scss'],
})
export class OnboardingPage {
constructor(
private storage: Storage,
private router: Router
) { }
start() {
this.storage.set('onboarded', true);
this.router.navigate(['main-app']);
}
}
main-app.page.html
<ion-app>
<ion-split-pane>
<ion-menu>
<ion-header>
<ion-toolbar>
<ion-title>Menu</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-list>
<ion-menu-toggle auto-hide="false" *ngFor="let p of appPages">
<ion-item [routerDirection]="'root'" [routerLink]="[p.url]">
<ion-icon slot="start" [name]="p.icon"></ion-icon>
<ion-label>
{{p.title}}
</ion-label>
</ion-item>
</ion-menu-toggle>
</ion-list>
</ion-content>
</ion-menu>
<ion-router-outlet main></ion-router-outlet>
</ion-split-pane>
</ion-app>
main-app.page.ts
import { Component } from '#angular/core';
#Component({
selector: 'app-main-app',
templateUrl: './main-app.page.html',
styleUrls: ['./main-app.page.scss'],
})
export class MainAppPage {
public appPages = [
{
title: 'Home',
url: '/home',
icon: 'home'
},
{
title: 'List',
url: '/list',
icon: 'list'
}
];
constructor() { }
}
List and Home pages are just empty pages and their content is not important for this example
Problem is that main-app containing side menu and content is not working properly. I know that there is a problem in <ion-router-outlet main></ion-router-outlet>'s usage but couldn't find the right solution.
Does anyone have idea how to make it work?
Thanks!
Andrew.
try adding contentId="content" to your <ion-menu>
ie: <ion-menu contentId="content">
and also add id="content" to your <ion-router-outlet>
ie: <ion-router-outlet id="content" main>
i seem to remember something about the router-outlet not working without that.

ionic 2 build error on visual studio

I imported my ionic 2 app into the visual studio. Before I did that, There was not any build error but, know it gives me following errors;
this is my firms.ts file;
import { Component } from '#angular/core';
import { FirmService } from '../../providers/getFirms';
import { Observable } from 'rxjs/Rx';
import {ReportsPage} from '../report/report';
import { Auth } from '../../providers/auth';
import {LoginPage} from '../login-page/login-page';
import { NavController, ModalController, AlertController, LoadingController,NavParams } from 'ionic-angular';
import {
FormGroup,
FormControl
} from '#angular/forms';
/*
Generated class for the Firms page.
See http://ionicframework.com/docs/v2/components/#navigation for more info on
Ionic pages and navigation.
*/
#Component({
selector: 'page-firms',
templateUrl: 'firms.html'
})
export class FirmsPage {
langs;
langForm;
loading: any;
username : string;
firms: string[];
constructor(public navCtrl: NavController, private navParams: NavParams, public firmService: FirmService, public loadingCtrl: LoadingController, public authService: Auth) {
this.getFirms();
this.username = this.navParams.get("param");
this.langForm = new FormGroup({
"langs": new FormControl('')
});
}
how can it cannot find them. I think, I imported correct paths.
Probably you are not taking the correct names of those Providers. Remember that you have to make reference to the class name.
export class AuthService { }
Both seem related to the providers route, are you 100% sure its correct? It would be easier to answer your question if you could make a jsfiddle or link to a repo.
1 - install npm https://nodejs.org
2 - install typescript npm install -g typescript
3 - Change the settings in VS to use your PATH first, this is the main issue always when you install npm, VS now comes with npm embedded.
Tools -> Options -> Projects and Solutions -> External Web Tools
Select $(PATH) and with the arrows (right corner) move the PATH to the first row.

Resources