Angular 2 / ASP.NET Core *ngFor loop issue - asp.net-core

I am having problems displaying information from an database to the angular 2 *ngFor loop. This is my code so far:
.Net Core controller:
// GET: api/Hats
[HttpGet("GetHats")]
public IEnumerable<Hat> GetHats()
{
return _context.Hat;
}
hat-list.component.ts:
//Imports from #Angular
import { Component, OnInit } from '#angular/core';
import { Http } from '#angular/http';
//Other imports
import { HatListService } from '../service/service.component';
import Hat = App.Models.IHat;
//Component Config
#Component({
selector: 'hat-list',
templateUrl: './hat-list.component.html',
providers: [HatListService]
})
//Class
export class HatListComponent implements OnInit {
public Hats: any[];
constructor(public _hatListService: HatListService) {
}
//OnInit
ngOnInit() {
this.getAllHats();
}
//Get All
getAllHats() {
//debugger
this._hatListService.getHatList().subscribe(foundHats =>
this.Hats = foundHats
);
}
}
service.component.ts
//imports from Angular
import { Injectable, Component } from '#angular/core';
import { Http, Request, RequestMethod, Response, RequestOptions, Headers } from '#angular/http';
import 'rxjs/Rx';
import { Observable } from 'rxjs/Observable';
//Other imports
import Hat = App.Models.IHat;
#Component({
providers: [Http]
})
//Exported class
#Injectable()
export class HatListService {
public headers: Headers;
constructor(private _http: Http) {
}
public _getUrl: string = '/api/Hats/GetHats';
//Get
getHatList(): Observable<Hat[]> {
//debugger
return this._http.get(this._getUrl).map(res => <Hat[]>res.json())
.catch(this.handleError);
}
private handleError(error: Response) {
return Observable.throw(error.json().error || 'Opps!! Server error');
}
}
hat-list.component.html:
<table class="table table-hover table-striped table-responsive">
<thead>
<tr>
<th>Name</th>
<th>Color</th>
<th>Count</th>
<th></th>
</tr>
</thead>
<tbody>
<tr *ngFor="let hat of Hats"">
<td>{{hat.Name}}</td>
<td>{{hat.Color}}</td>
<td>{{hat.Count}}</td>
<td>
<a class="glyphicon glyphicon-remove" (click)="delete(hat)"></a>
</td>
</tr>
</tbody>
</table>
Picture of the table
The *ngFor recives the value.
I know the request to the database happens asynch and that one problem might be that the *ngfor loop fires before the data has returned and thus no information is displayed. But diffrent articles on the net say that the *ngFor loop shouldt fire unless the iterable has a value. The strange thing is that when I update the database manually thru SSMS the *ngfor recognises the added content add creates additioanl rows. What am I doing wrong.
Thanx for all the help!

There are wrong variable names used in the template i.e. {{hat.Name}} instead of {{hat.name}}.

Related

Vue JS and Datatable No data available

I am learning Vue JS and I am getting data from the backend using Axios to show it in data table. When I get the data and do a v-for I get No data available in table Below is my code.
Picture
Template
<tbody >
<tr v-for="user in users" v-bind:key="user">
<td>{{user.firstname}} {{user.lastname}}</td>
<td>{{user.username}}</td>
<td>{{user.role}}</td>
<td>{{user.email}}</td>
<td>{{user.is_active}}</td>
<td>View</td>
</tr>
</tbody>
And script
import axios from 'axios';
export default {
name : "SystemAdmin",
data(){
return{
users: []
}
},
mounted(){
this.checkUser()
},
methods:{
async checkUser(){
try {
console.log('System Users')
const response = await axios.get('superadmin/system-admins/');
this.users = response.data.results
console.log(response.data.results)
} catch (err) {
}
}
}
}
Did I miss something?

Angular undefined value of #input variable

I'm new to Angular and I have some issues , hope you'll help me.
so I'm trying to share a value of a variable from a ProjectComponent to an AcceuilComponent , the value of this variable is displaying correctly into my acceuil.component.html but when I try to use it into my acceuil.component.ts it's undefined !
project.component.html (the parent component)
<app-header-in></app-header-in>
<ng-sidebar-container>
<ng-sidebar [opened]="opened">
<p> Sidebar </p>
<button (click)="Sidebar()">
Close Sidebar
</button>
<ul class="menu">
<li class="hh"
*ngFor="let project of projects"
[class.selected]="project === selectedProject"
(click)="onSelect(project)">
{{project.nomprojet}}</li>
</ul>
</ng-sidebar>
<div ng-sidebar-content >
<br><br><br><br>
<button (click)="Sidebar()">
Open Sidebar
</button>
<app-acceuil [message]="idProject"></app-acceuil>
</div>
</ng-sidebar-container>
project.component.ts
import { Component, OnInit } from '#angular/core';
import { ApiService } from '../api.service';
import {ProjectService} from '../project.service';
import {PartService} from '../part.service';
#Component({
selector: 'app-project',
templateUrl: './project.component.html',
styleUrls: ['./project.component.css']
})
export class ProjectComponent implements OnInit {
opened=true;
projects:any;
idProject;
selectedProject;
constructor(private projectService:ProjectService) { }
ngOnInit(): void {
this.projectService.getProjects().subscribe((result)=>{console.log("result",result)
this.projects=result})
}
Sidebar(){
this.opened=!this.opened;
}
onSelect(pro): void {
this.idProject = pro.id;
}
}
acceuil.component.html (my child component)
<p>{{message}}</p>
<ul >
<li class="hh"
*ngFor="let part of parts">
{{part.nomparti}}
</li>
</ul>
acceuil.component.ts
import { Component, OnInit,Input } from '#angular/core';
import { ApiService } from '../api.service';
import {PartService} from '../part.service';
#Component({
selector: 'app-acceuil',
templateUrl: './acceuil.component.html',
styleUrls: ['./acceuil.component.css']
})
export class AcceuilComponent implements OnInit {
#Input() message;
parts:any;
constructor(private partService:PartService) {
}
ngOnInit(): void{
console.log("id",this.message);
this.partService.getPartsFromIdProject(this.message).subscribe((result)=>{console.log("result",result)
this.parts=result})
}
ngOnChanges() {
if(this.message) {
console.log(this.message)
}
}
}
I'm using the message to call a service and displaying data .
in the acceuil.component.html <p>{{message}}</p> is displaying correctly but console.log("id",this.message); in acceuil.component.ts displays undefined
As message is an input property, you need to get its value in ngOnchanges life cycle.
First time, when it is in ngOnChanges, input value will be undefined. So for the safe side, better to add a check for not undefiled condition like below
ngOnChanges(changes: SimpleChanges) {
if (changes.message) {
// Should be defined now
console.log(this.message);
}
}

How to pass value from template HTML to component to then be used in service

I want to fetch id from component.html into component.ts to pass it to a service.
.ts file is;
import { Component, OnInit } from '#angular/core';
import { HttpClient } from '#angular/common/http'
import { HttpErrorResponse } from '#angular/common/http/src/response';
import { SendUsingApiService } from '../send-using-api.service';
import { Router, ActivatedRoute } from '#angular/router';
import { FormBuilder, FormGroup, Validators } from '#angular/forms';
import { setDefaultService } from 'selenium-webdriver/chrome';
#Component({
selector: 'app-org-info',
templateUrl: './org-info.component.html',
styleUrls: ['./org-info.component.css'],
providers: [SendUsingApiService]
})
export class OrgInfoComponent implements OnInit {
orgData: string[] = [];
Id = 1;
editRecord:FormGroup;
constructor(private httpService: HttpClient, private _serv: SendUsingApiService,
private fb: FormBuilder, private _ar:ActivatedRoute, private _r:Router) {
this.editRecord = this.fb.group({
Id:['1', []],
OrganisationName:['', []],
ContactPerson:['', []],
ContactPersonHPNo:['', []],
ContactPersonEmailId:['', []]
});
}
ngOnInit() {
console.log(this._ar.snapshot.params.Id, "+ve");
this._ar.params.subscribe(() => {
this._serv.getUsers(this._ar.snapshot.params.Id).subscribe((res)=>{
console.log(res);
this.setUser(res);
});
});
}
I am getting the value for console.log(this._ar.snapshot.params.Id); as undefined "+ve".
I want to get the Id value in console.
As per requests I am adding html part, though little adjusted;
<td style="text-align: center;">
<a class="btn btn-basic" [routerLink]="['/org-info',data['Id']]" role="button" (click)="getOrgData(data.Id)">View</a>
</td>
I defined a property instead of Id = 1; (above)
paramId = '';
then, within ngOnInit;
ngOnInit() {
this.paramId = this._ar.snapshot.params.Id;
console.log(paramId, "+ve");
}
Doing this, I got the Id value instead of undefined.

"attached" or DOM-render equivalent for nested view-model.ref

We have a page, "parent", which references a template via the view-model.ref called "child" in the parent.html. We change the data of this child template by clicking on items on the parent page which invokes the child function using OpenDetailsDiv. Say I use a button for this event like below:
parent.html
<child view-model.ref="clientusertasks"></child>
<input type="button" value="Click Me" click.trigger="OpenDetailsDiv" />
In this manner we can invoke a function on the "child" view-model from the parent view-model like so:
parent.js
import { inject } from 'aurelia-framework';
import { HttpClient } from 'aurelia-fetch-client';
import 'fetch';
import AuthService from 'AuthService';
import { BpoClientUserTasks } from './bpo-client-user-tasks';
#inject(HttpClient, AuthService, BpoClientUserTasks)
export class Parent {
smallDivObj = {};
freq = '';
period = '';
filterVal = '';
client = '';
constructor(http, AuthService, BpoClientUserTasks) {
http.configure(config => {
config
.withBaseUrl("WebServices.asmx/")
.withDefaults({
headers: {
'Accept': 'application/json'
}
});
});
this.http = http;
this.auth = AuthService;
this.clientusertasks = BpoClientUserTasks;
}
OpenDetailsDiv(myObject) {
this.clientusertasks.CallBPOClientUserService(this.freq, this.period, this.filterVal, myObject.TrueClient, myObject.Client);
}
}
All good so far. The "child" view-model has this function CallBPOClientUserService which looks like the following:
child.js
import { inject } from 'aurelia-framework';
import { HttpClient } from 'aurelia-fetch-client';
import 'fetch';
import AuthService from 'AuthService';
#inject(HttpClient, AuthService)
export class Child {
smallDivObj = {};
constructor(http, AuthService) {
http.configure(config => {
config
.withBaseUrl("WebServices.asmx/")
.withDefaults({
headers: {
'Accept': 'application/json'
}
});
});
this.http = http;
this.auth = AuthService;
}
attached() {
}
CallBPOClientUserService(freq, period, filterVal, client, displayClient) {
$('#TasksByClientByUserDiv').addClass("fade");
this.freq = freq;
this.period = period;
this.filterVal = filterVal;
this.client = client;
var mymethod = {
method: 'post',
body: JSON.stringify({
"session": this.auth.session,
"Client": client,
"FreqFilter": freq,
"FilterVal": filterVal
}),
headers: {
'content-type': 'application/json'
}
};
//alert(JSON.stringify(mymethod));
this.http.fetch('GetBPOTasksByClientByUserDiv', mymethod)
.then(response => response.json())
.then(info => {
this.tasksByClientByUser = JSON.parse(info.d);
//setTimeout("$('#TasksByClientByUserTable').tablesorter();", 100);
});
}
}
Notice that in the function CallBPOClientUserService we wish to call a tablesorter sort function to sort our table in the view AFTER the DOM has been rendered.
Usually I would call upon this function in the "attached" component lifecycle of the view-model. But you can see that the manner in which we are populating this view is from the view-model.ref of the "parent" page which renders the "attached" component for "child" useless for this case (it's only called once after all when the parent is loaded).
So to my question:
Is there an equivalent attached-like component that I tap into to call this tablesorter function?
I have a cheap work-around where I can use a setTimeout which I have commented in the function, but I'd rather do this correctly in Aurelia events and have a guarantee that the DOM has finished.
I believe I have 2 solutions to this problem which I'm satisfied with and will post them here.
The first is the recommendation above by Fabio to use the microTaskQueue.
Another solution is to use a custom bindable event to invoke the function on completion of the repeat.for on the table here...
<template>
<require from='../tablesorter-bind'></require>
<section id="TasksByClientDiv" class="SmallDivPanel ui-draggable BIBulletinSection100 SmallDivSection hellfire">
<small-div-header smalldivinfo.bind="smallDivObj"></small-div-header>
<div id="TasksByClientBox">
<div style="margin-top: 10px;font-size: 20px;">Frequency: ${freq} / Period: ${filterVal}</div>
<div id="TasksByClientTableDiv" class="SmallDivMainPanel">
<table id="TasksByClientTable" >
<thead class="tablesorter">
<tr>
<th>Client</th>
<th>Received</th>
<th>Prepped</th>
<th>Loaded</th>
<th>Doc Loaded</th>
</tr>
</thead>
<tbody>
<tr click.trigger="OpenDetailsDiv(x)" repeat.for="x of tasksByClient" table-id.bind="tableId">
<td>${x.Client}</td>
<td>${x.totLoaded}</td>
<td>${x.totLoaded}</td>
<td>${x.totPrepped}</td>
<td>${x.numDocLoaded}</td>
</tr>
</tbody>
</table>
</div>
</div>
</section>
</template>
where tableId is defined in the View-Model as my tableID
I then setup the custom element like so:
tablesorter-bind.js
import {inject, customAttribute, TaskQueue} from 'aurelia-framework';
#customAttribute('table-id')
#inject(Element, TaskQueue)
export class TablesorterBind {
constructor(element, taskQueue) {
// "element" will be the DOM element rendered from the template
this.element = element;
this.taskQueue = taskQueue;
}
attached() {
}
bind(bindingContext, overridingContext) {
if (overridingContext.$last === true) {
this.taskQueue.queueMicroTask(
() => {
//This is the jQuery update call to the tablesorter function
$('#' + this.value).trigger('update');
}
);
}
}
}

Aurelia - Watch Dependency Value for Change

Suppose you have a class you are injecting into a another class or component. Is there a way to watch for changes on an attributed of the dependency you are injecting and act upon it?
For example, say you have the following app:
app.html
<template>
<input type="text" value.bind="item">
<button click.trigger="addToList()">Add</button>
<h3>Modded</h3>
<ul>
<li repeat.for="it of modded">${it}</li>
</ul>
<h3>Original</h3>
<ul>
<li repeat.for="it of dep.items">${it}</li>
</ul>
</template>
app.js
import {bindable, inject} from 'aurelia-framework';
import {Dep} from './dep';
#inject(Dep)
export class App {
constructor(dep) {
this.dep = dep;
}
attached() {
this.modifyItems();
}
addToList() {
this.dep.addItem(this.item);
}
modifyItems() {
this.modded = [];
for (let item of this.dep.items) {
this.modded.push(item.toUpperCase());
}
}
}
dep.js
export class Dep {
constructor() {
this.items = ['one', 'two', 'three'];
}
addItem(item) {
this.items.push(item);
}
}
Now, let's say that some other component modifies Dep.items. Is there a way to watch for changes in app.js on this.dep.items and then call modifyItems()?
Assume modifyItems() is more complex than this example so maybe a value converter is not the best option. (unless it is the only option I guess)
Here is working plunker with the above example: http://plnkr.co/edit/rEs9UM?p=preview
Someone pointed me to the BindingEngine.collectionObserver and it appears that is what I needed.
app.js:
import {inject} from 'aurelia-framework';
import {BindingEngine} from 'aurelia-binding';
import {Dep} from './dep';
#inject(Dep, BindingEngine)
export class App {
constructor(dep, bindingEngine) {
this.dep = dep;
let subscription = bindingEngine.collectionObserver(this.dep.items)
.subscribe((newVal, oldVal) => {
console.debug(newVal, oldVal);
this.modifyItems();
});
}
attached() {
this.modifyItems();
}
addToList() {
this.dep.addItem(this.item);
this.item = '';
}
modifyItems() {
this.modded = [];
for (let item of this.dep.items) {
this.modded.push(item.toUpperCase());
}
}
}
Here is the working pluker: http://plnkr.co/edit/Pcyxrh?p=preview