I'm working on an Angular application which uses a .NET Core back end with EF to learn Angular. The solution was generated by selecting the Angular and ASP.NET Core project template in Visual Studio 2022. My controllers were scaffolded by selecting the option API Controller with actions, using Entity Framework.
There're two models. Employee and Salary. Each one has a controller. Namely EmployeesController and SalariesController. There's a service class which accesses the controllers. When the user clicks a button on the first page the employees page loads. This works correctly. The user can click a link next to each employee to view their salary. The code for the Salaries page is identical to that of the employees page. But when I click the link the page loads without any data. When I debug the action method on the controller doesn't get hit.
Here's my Employees controller.
namespace EmployeesAngular.Server.Controllers
{
[Route("[controller]")]
[ApiController]
public class EmployeesController : ControllerBase
{
private readonly EmployeesAngularServerContext _context;
public EmployeesController(EmployeesAngularServerContext context)
{
_context = context;
}
[HttpGet]
public async Task<ActionResult<IEnumerable<Employee>>> GetEmployee()
{
return await _context.Employee.ToListAsync();
}
}
}
This is the Salaries controller
namespace EmployeesAngular.Server.Controllers
{
[Route("[controller]")]
[ApiController]
public class SalariesController : ControllerBase
{
private readonly EmployeesAngularServerContext _context;
public SalariesController(EmployeesAngularServerContext context)
{
_context = context;
}
[HttpGet]
public async Task<ActionResult<IEnumerable<Salary>>> GetSalary()
{
return await _context.Salary.ToListAsync();
}
}
}
This is the app.component.html file.
<div class="container">
<h3 class="d-flex justify-content-center">Employee Details</h3>
<nav class="navbar navbar-expand-sm bg-light navbar-dark">
<ul class="navbar-nav">
<li class="nav-item">
<button routerLink="employees" class="m-1 btn btn-light btn-outline-primary" Button>Employees</button>
</li>
</ul>
</nav>
<router-outlet></router-outlet>
</div>
Here's the employees.component.html file.
<table class="table table-striped">
<thead>
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Department</th>
<th>Date Of Joining</th>
<th>Total Salary</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let dataItem of EmployeeList">
<td>{{dataItem.firstName}}</td>
<td>{{dataItem.lastName}}</td>
<td>{{dataItem.department}}</td>
<td>{{dataItem.joinDate}}</td>
<td>{{dataItem.totalSalary}}</td>
<td><a routerLink="/salaries" routerLinkActive="active" ariaCurrentWhenActive="page">View Salary Components</a></td>
<td><a routerLink="/editEmployee" routerLinkActive="active" ariaCurrentWhenActive="page">Edit</a></td>
</tr>
</tbody>
</table>
This is the code for the salaries.component.html file.
<table class="table table-striped">
<thead>
<tr>
<th>Basic</th>
<th>Allowance</th>
<th>Bonus</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let dataItem of SalaryList">
<td>{{dataItem.basic}}</td>
<td>{{dataItem.allowance}}</td>
<td>{{dataItem.bonus}}</td>
</tr>
</tbody>
</table>
Here's the employees.component.ts file.
import { Component, OnInit } from '@angular/core';
import { ApiserviceService } from '../apiservice.service';
@Component({
selector: 'app-employees',
templateUrl: './employees.component.html',
styleUrls: ['./employees.component.css']
})
export class EmployeesComponent implements OnInit {
constructor(private service: ApiserviceService) { }
EmployeeList: any = [];
ngOnInit(): void {
this.refreshEmpList();
}
refreshEmpList() {
this.service.getEmployeeList().subscribe(data => {
this.EmployeeList = data;
});
}
}
Here's the salaries.component.ts file.
import { Component, OnInit } from '@angular/core';
import { ApiserviceService } from '../apiservice.service';
import { ActivatedRoute } from '@angular/router';
import { HttpClient } from '@angular/common/http';
@Component({
selector: 'app-salaries',
templateUrl: './salaries.component.html',
styleUrl: './salaries.component.css'
})
export class SalariesComponent implements OnInit {
constructor(private service: ApiserviceService) {
}
SalaryList: any = [];
ngOnInit(): void {
this.refreshSalary();
}
refreshSalary() {
this.service.getSalaryList().subscribe(data => {
this.SalaryList = data;
});
}
}
This is my service called the apiservice.
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class ApiserviceService {
constructor(private http: HttpClient) { }
getEmployeeList(): Observable<any[]> {
return this.http.get<any[]>('employees');
}
getSalaryList(): Observable<any[]> {
return this.http.get<any[]>('salaries');
}
}
This is how routing is done in the app-routing-module.ts file.
const routes: Routes = [
{ path: 'employees', component: EmployeesComponent },
{ path: 'salaries', component: SalariesComponent },
{ path: 'editEmployee', component: EditEmployeeComponent },
];
When I click the salary link and observe the console under developer tools in the browser I see an error saying
SyntaxError: Unexpected token '<', "<!doctype "... is not valid
I searched for this error and tried to implement the suggested fixes. As mentioned in this page I modified the code to look like this.
getSalaryList(): Observable<any[]> {
return this.http.get<any[]>('salaries', { responseType: 'text' });
}
This gives me a compiler error saying
Type 'Observable' is not assignable to type 'Observable<any[]>'
In the responseType property it also says that
No overload matches this call
As suggested in this page I tried to change base href in the Index.html page like this but that didn't work either.
<base href="/">
to
<base href=".">
Based on another answer I modified the code in the service class like this.
getSalaryList(): Observable<any[]> {
const httpOptions: Object = {
headers: new HttpHeaders({
'Accept': 'text/html',
'Content-Type': 'text/plain; charset=utf-8'
}),
responseType: 'text'
};
return this.http.get<any[]>('salaries', httpOptions);
}
This also doesn't hit the controller action method. And gives me an error in the browser console saying
NG0900: Error trying to diff...Only arrays and iterables are allowed.
I looked at several other answers to similar questions. But the responses seems to be incomplete. Most questions don't have a selected answer and the suggestions on the answers do not seem to work for this problem. So I'm posting this question.
Although I tried various suggestions because they're given in answers I'm mystified as to why the code doesn't work for Salaries while it works for Employees.
Help is much appreciated.