I am trying to create a form in angular that takes a name, passes it to a URL, and returns a portion of a .json file. I can't figure out why the url is not getting updated though.
The HTML:
<form (ngSubmit)="processForm($engineer)">
<div class="form-group">
<label for="engineerselectform">Engineer Name</label>
<select class="form-control" id="engineerselectform" name="engineer" [(ngModel)]="engineer">
<option></option>
<option>Smith</option>
<option>Jones</option>
<option>Clark</option>
</select>
</div>
<input class="btn btn-primary" type="submit" value="submit" aria-pressed="true">
</form>
The Component:
import { Component, OnInit } from '#angular/core';
import { ScheduleService } from '../schedule.service';
import { ActivatedRoute } from '#angular/router';
#Component({
selector: 'app-schedule',
templateUrl: './schedule.component.html',
styleUrls: ['./schedule.component.scss']
})
export class ScheduleComponent implements OnInit {
engineer;
constructor(
private scheduleService: ScheduleService,
private route: ActivatedRoute
) { }
ngOnInit() {}
processForm(engineer: string) {
this.route.params.subscribe(params=> { const engineer = params["engineer"];
this.scheduleService.getschedule(engineer).subscribe(engineer => this.engineer = engineer);
});
}
}
The Service:
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
#Injectable({
providedIn: 'root'
})
export class ScheduleService {
apiUrl ='http://127.0.0.1:5000/schedule'
engineer;
constructor(private http: HttpClient) { }
getschedule(engineer: string){
return this.http.get(`${this.apiUrl}?engineer=${this.engineer}`);
}
}
The Flask API backend:
#app.route('/schedule', methods = ['GET'])
def engineer_location_api():
if "engineer" in request.args:
print ('did this')
engineer_name = request.args["engineer"]
print ("engineer name:", engineer_name)
else:
return "not found, sorry"
answer = {}
with open(LOC1, "r") as file:
check_loc1 = json.load(file)
for item in check_loc1["LOC1"]:
if engineer_name in item["Engineer"]:
answer.update(item)
else:
continue
with open(LOC2, "r") as file:
check_loc2 = json.load(file)
for item in check_loc2:
if engineer_name in item:
answer.update(item)
else:
continue
if answer:
return answer
else:
return 'engineer not found'
app.run()
the error:
ERROR
Object { headers: {…}, status: 200, statusText: "OK", url: "http://127.0.0.1:5000/schedule?engineer=undefined", ok: false, name: "HttpErrorResponse", message: "Http failure during parsing for http://127.0.0.1:5000/schedule?engineer=undefined", error: {…} }
core.js:6014:19
As I understand it, when I hit submit the process form function should send the engineer variable to the component where it sets it as a parameter that it provides to the service which should fill out the URL. But regardless of how I play around with it, the engineer always comes back as undefined. Clearly I'm missing something core to passing the variable.
Also, I'm super new and therefore there are probably other things in this code that are ugly or not best practice, feel free to rip into it, I figure my understanding can only go up.
You don't have to subscribe to activated url if your data is coming from form. You have to remove the $event from processForm because we will add the global variable in your service function. Please have a look on below example
<form (ngSubmit)="processForm()">
<div class="form-group">
<label for="engineerselectform">Engineer Name</label>
<select class="form-control" id="engineerselectform" name="engineer" [(ngModel)]="engineer">
<option></option>
<option value="smith">Smith</option>
<option value="jones">Jones</option>
<option value="clark">Clark</option>
</select>
</div>
<input class="btn btn-primary" type="submit" value="submit" aria-pressed="true">
</form>
import { Component, OnInit } from '#angular/core';
import { ScheduleService } from '../schedule.service';
import { ActivatedRoute } from '#angular/router';
#Component({
selector: 'app-schedule',
templateUrl: './schedule.component.html',
styleUrls: ['./schedule.component.scss']
})
export class ScheduleComponent implements OnInit {
engineer;
receivedEngineers;
constructor(
private scheduleService: ScheduleService,
private route: ActivatedRoute
) { }
ngOnInit() {}
processForm() {
this.scheduleService.getschedule(this.engineer).subscribe(engineer => this.receivedEngineers = engineer);
});
}
}
getschedule(engineer: string){
return this.http.get(`${this.apiUrl}?engineer=${engineer}`);
}
The engineer is now accessed from parameter of getSchedule() function.
Related
I created a class named alert, and I use it to display alerts whenever new post is created or deleted or changed.
but there is one issue, when I put the setAlert inside a DELETE/POST/PUT function, if the latter is located inside a service component, it gives me an error saying: ERROR
but when I move the function into its component.ts file, it works properly without any issues. So why is that happening and what can I do to make it work in a service?
Here is my Alert.ts:
export class alert{
"status" : boolean;
"text": string;
constructor(){
this.status=false;
this.text="";
}
public setAlert(text){
this.status = true;
this.text = text;
}
public close(){
this.status = false;
}
}
Here is my html file:
<div class="forms container">
<form #postForm="ngForm">
<div class="form-group">
<label for="title">Title</label>
<input [(ngModel)]="formService.form.title"
name="title"
id="title"
type="text"
class="form-control"
>
</div>
<div class="form-group">
<label for="body">Body</label>
<textarea [(ngModel)]="formService.form.body"
name= "body"
id="body"
cols="30"
rows="10"
class="form-control"
></textarea>
</div>
<button class="btn btn-success" (click) = "formService.editForm()">Save</button>
<button class="btn btn-danger pull-right" (click) = "formService.deleteForm()">Delete</button>
<div class="container mt-4">
<div class="row">
<div class="col">
<div *ngIf = "alert.status" class="alert alert-success
alert-dismissible fade show" role="alert">
<button type="button" class="close" data-dismiss="alert" aria-label="Close"
(click) = "alert.close()">
<span aria-hidden="true">×</span>
</button>
{{alert.text}}
</div>
</div>
</div>
</div>
</form>
</div>
Here is component.ts file:
import { Component, OnInit, OnDestroy } from '#angular/core';
import { ActivatedRoute, Router } from '#angular/router';
import { FormService } from './forms.service';
import { HttpClient } from '#angular/common/http';
import { alert } from './alert';
#Component({
selector: 'app-forms',
templateUrl: './forms.component.html',
styleUrls: ['./forms.component.css']
})
export class FormsComponent implements OnInit {
alert: alert;
id: any;
posts: any;
constructor(public formService: FormService ,private route: ActivatedRoute,
private router: Router, private http: HttpClient) { }
ngOnInit() {
this.id=this.route.snapshot.params['id'];
this.alert = new alert();
this.posts = this.formService.getForms(this.id).subscribe(
(forms: any) => {
this.formService.form = forms[0];
}
);
}
}
And here is service.ts file:
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { form } from './form-interface';
import { alert } from './alert';
#Injectable({
providedIn: 'root'
})
export class FormService {
formsUrl = "https://jsonplaceholder.typicode.com/posts";
form: form = {
id: 0,
userId: 0,
title: '',
body: ''
};
alert: alert;
constructor(private http: HttpClient) { }
ngOnInit() {
this.alert = new alert();
}
getForms(id) {
return this.http.get('https://jsonplaceholder.typicode.com/posts'
+ "?id=" + id)
}
editForm() {
fetch(this.formsUrl + "/" + this.form.id, {
method: 'PUT',
body: JSON.stringify(this.form),
headers: {
"Content-type": "application/json; charset=UTF-8"
}
})
.then(response => response.json())
this.alert.setAlert("Post has been successfully saved !");
}
deleteForm() {
this.http.delete(this.formsUrl + "/" + this.form.id)
.subscribe(
data => {
console.log("DELETE Request is successful ", data);
this.alert.setAlert("Post has been successfully deleted !");
},
error => {
console.log("Error", error);
}
);
}
}
Services don't have ngOnInit life cycle, change your code from ngOnInit to constructor.
constructor(private http: HttpClient) {
this.alert = new alert();
}
Only components and directives have life cycle hooks:
A Component has a lifecycle managed by Angular itself. Angular creates it, >renders it, creates and renders its children, checks it when its data-bound >properties change and destroy it before removing it from the DOM.
Directive and component instances have a lifecycle as Angular creates, updates, >and destroys them.
I have completely reworded this question and included a complete code sample.
I have an intermittent issue where clicking the button sometimes shows the validation error message, instead of executing the router.nagivate command. Then, I have to click it a second to work. As I said, this is intermittent. The solution needs to include the focus behavior of the sample below, or an alternative way to focus on input html tags. Sometimes, I only have to click once. Why? And, how can I control this behavior so that it is not random?
I am posting two test components to demonstrate the issue. Any help would be greatly appreciated.
test.component.html
<form novalidate #f="ngForm">
<h2>Scan Part</h2>
<input id="partNum" type="number" class="form-control" required [correctPart]="orderShipDetail?.UPC" name="partNum" [(ngModel)]="model.partNum" #partNum="ngModel" #partNumRef />
<div *ngIf="partNum.invalid && (partNum.dirty || partNum.touched)" class="text-danger">
<p *ngIf="partNum.errors.required">PartNum is required.</p>
<p *ngIf="partNum.errors.correctPart">Please scan the correct part. </p>
</div>
<button type="button" (click)="onClickCartonPartButton()">Carton Parts</button>
</form>
test.component.ts
import { Component, OnInit, AfterViewChecked, ViewChild, ElementRef } from '#angular/core';
import { Router } from '#angular/router';
class TestForm {
constructor(
public partNum: string = '') {
}
}
#Component({
selector: 'test',
templateUrl: './test.component.html',
styleUrls: ['./test.component.scss']
})
export class TestComponent implements OnInit, AfterViewChecked {
#ViewChild('partNumRef') partNumRef: ElementRef;
model: TestForm = new TestForm();
public focusedElement: ElementRef;
constructor(
private router: Router,
private route: ActivatedRoute
) { }
ngAfterViewChecked() {
this.focusedElement.nativeElement.focus();
}
ngOnInit() {
this.focusedElement = this.partNumRef;
}
onClickCartonPartButton() {
try {
this.router.navigate(['/test2', 1006, 1248273, 1234]);
} catch (ex) {
console.log(ex);
}
}
}
test2.component.html
<a [routerLink]="['/test', 1006, 1248273, 1234, 5 ]">click this</a>
test2.component.ts
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'test2',
templateUrl: './test2.component.html',
styleUrls: ['./test2.component.scss']
})
export class Test2Component implements OnInit {
constructor() { }
ngOnInit() {
}
}
Add these routes to the app.module.ts
{ path: 'test/:empId/:orderNumber/:licensePlate/:orderLine', component: TestComponent },
{ path: 'test2/:empId/:orderNumber/:licensePlate', component: Test2Component },
Set type="button" on the two hyperlinks to avoid submit
A button element with no type attribute specified represents the same
thing as a button element with its type attribute set to "submit".
Or put the two hyperlinks outside of the form
Remove partNum.touched from *ngIf in the validation message div, like this...
<div *ngIf="partNum.invalid && partNum.dirty" class="text-danger">
<p *ngIf="partNum.errors.required">PartNum is required.</p>
<p *ngIf="partNum.errors.correctPart">Please scan the correct part.</p>
</div>
Hey Guys i wrote a little backend which returns some data. Now i want to fetch this data with Angular Http and show new values when i post them in the backend. So the first thing that came to my mind were Observables but currently i can fetch the data onInit but when Posting new Data to the Backend (currently just via Postman) the Fetched data wont update. So if this is the wrong approach tell me how to do this please. Below is my code i used so far:
App Component:
import { Component, OnInit } from '#angular/core';
import { FormBuilder, FormGroup, Validators } from '#angular/forms';
import 'rxjs/add/operator/map';
import { Observable } from 'rxjs/Observable';
import { Subscription } from 'rxjs/Subscription';
import {WeaponServiceService} from './weapon-service.service';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
weaponTypesarr: IweaponsTypes [] = [
{name: 'Nahkampf', value: 'melee'},
{name: 'Fernkampf', value: 'ranged'},
{name: 'Spezial', value: 'special'},
];
meleeTypesarr: IweaponsTypes [] = [
{name: 'Klingenwaffen', value: 'klinge'},
{name: 'Messer', value: 'messer'},
{name: 'Dolche', value: 'dolch'},
{name: 'Äxte/Beile', value: 'axt'},
{name: 'Speere/Stäbe', value: 'speer'},
{name: 'Stumpfe Hiebwaffen', value: 'stumpf'}
];
rangedTypesarr: IweaponsTypes [] = [
{name: 'Bogen', value: 'bogen'},
{name: 'Armbrust', value: 'armbrust'},
{name: 'Wurfwaffe', value: 'wurfwaffe'},
{name: 'kleine Schusswaffe', value: 'gun-litte'},
{name: 'große Schusswaffe', value: 'gun-big'}
];
specialTypesarr: IweaponsTypes [] = [
{name: 'Exotische Waffen', value: 'exotics'},
{name: 'Granaten und Exoplosive', value: 'grenade'}
];
rForm: FormGroup;
post: any;
weaponName = '';
weaponType= '';
impairment= '';
special= '';
results: Observable<any>;
constructor(private fb: FormBuilder , private weaponService: WeaponServiceService) {
this.rForm = fb.group({
'weaponName' : [null, Validators.required],
'weaponType': [null, Validators.required],
'impairment': [null, Validators.required],
'special': [null, Validators.required]
});
}
ngOnInit() {
this.results = this.weaponService.getWeapons();
this.results.subscribe(data => {console.log(data); });
}
generateWeapon(weaponData) {
this.weaponName = weaponData.weaponName;
this.weaponType = weaponData.weaponType;
this.impairment = weaponData.impairment;
this.special = weaponData.special;
console.log(weaponData);
}
}
export interface IweaponsTypes {
name: string;
value: string;
}
WeaponServiceService (didnt knew it calls it service by its own :D):
import { Injectable } from '#angular/core';
import {HttpClient} from '#angular/common/http';
import { Observable } from 'rxjs/Observable';
#Injectable()
export class WeaponServiceService {
constructor( private http: HttpClient) { }
getWeapons() {
return this.http.get('http://192.168.178.48:3000/getWeapons').map(data => {
return(data);
},
err => {
console.log(err);
}
);
}
createWeapon(weaponData2: any) {
return this.http.post('http://192.168.178.48:3000/createWeapon', weaponData2)
.map(
res => {
console.log(res);
},
err => {
console.log(err);
}
);
}
}
Module:
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import { FormsModule, ReactiveFormsModule } from '#angular/forms';
import {NgbModule} from '#ng-bootstrap/ng-bootstrap';
import { AppComponent } from './app.component';
import { HttpClientModule } from '#angular/common/http';
import {WeaponServiceService} from './weapon-service.service';
#NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
FormsModule,
HttpClientModule,
ReactiveFormsModule,
NgbModule.forRoot()
],
providers: [WeaponServiceService],
bootstrap: [AppComponent]
})
export class AppModule { }
and last but not least the corresponding HTML but currently i just try to log all the values.
<div *ngIf="!name; else forminfo">
<form [formGroup]="rForm" (ngSubmit)="generateWeapon(rForm.value)">
<h1>Generate Weapon</h1>
<label for="WeaponName">WeaponName</label>
<input class="form-control" type="text" name="weaponName" formControlName="weaponName" id="WeaponName">
<div class="form-group">
<label for="WeaponGroup">Weapon Group</label>
<select class="form-control" #weaponTypeSelektor formControlName="weaponType" id="WeaponGroup">
<option> Select a Type</option>
<option *ngFor="let types of weaponTypesarr" [value]="types.value">{{types.name}}</option>
</select>
</div>
<div class="form-group" *ngIf="weaponTypeSelektor.value == 'melee'">
<label for="WeaponTypeMelee">Weapon Type</label>
<select class="form-control" formControlName="weaponType" id="WeaponTypeMelee">
<option *ngFor="let types of meleeTypesarr" [value]="types.value">{{types.name}}</option>
</select>
</div>
<div class="form-group" *ngIf="weaponTypeSelektor.value == 'ranged'">
<label for="WeaponTypeRanged">Weapon Type</label>
<select class="form-control" formControlName="weaponType" id="WeaponTypeRanged">
<option *ngFor="let types of rangedTypesarr" [value]="types.value">{{types.name}}</option>
</select>
</div>
<div class="form-group" *ngIf="weaponTypeSelektor.value == 'special'">
<label for="WeaponTypeSpecial">Weapon Type</label>
<select class="form-control" formControlName="weaponType" id="WeaponTypeSpecial">
<option *ngFor="let types of specialTypesarr" [value]="types.value">{{types.name}}</option>
</select>
</div>
<label for="impairment">Beeinträchtigung</label>
<input class="form-control" type="text" name="Beeinträchtigung" formControlName="impairment" value="" id="impairment">
<label for="special">Spezial</label>
<input class="form-control" type="text" name="Spezial" formControlName="special" value="" id="special">
<br><br>
<input type="submit" class="btn btn-primary" value="Submit Form" [disabled]="!rForm.valid">
</form>
<div *ngFor="let item of results | async"> {{item.weaponName}} </div>
</div>
<ng-template #forminfo>
<div class="form-container">
<div class="row columns">
<h1>{{ name }}</h1>
<p>{{ weaponType }}</p>
</div>
</div>
</ng-template>
So just to be clear. AppComponent starts and fetched initial data. I post Data into the Db with postman. App Component doesn't recognize new Value.
Change these lines in the Service.
getWeapons() {
return this.http.get('http://192.168.178.48:3000/getWeapons').map(data => {
return data.json();
}
And Change these lines in the AppComponent
ngOnInit() {
this.results = this.weaponService.getWeapons();
//delete this line ---> this.results.subscribe(data => {console.log(data); });
}
since you are using the async pipe you dont need to subscribe.
Hope this helps.
Tested on:
Angular CLI: 13.1.4
Node: 17.3.0
Package Manager: npm 8.3.0
I know I don't have the best answer but one which works (at least).
Maybe it helps someone to continue further ;-)
I fetched the data once in the component's ngOnInit as well as in a function which pulls the database data after a defined interval/time has passed.
data: any;
baseUrl = 'foo_URL';
fetchInterval: 3000; // 3 Seconds
constructor(private http: HttpClient) {
}
// First Fetch
ngOnInit(): void {
this.http.get(this.baseUrl)
.pipe(takeUntil(this.destroy$))
.subscribe((fooData) => {
this.data = fooData;
})
}
// Interval Fetch
setInterval: any = setInterval(() => {
this.http.get(this.baseUrl)
.pipe(takeUntil(this.destroy$))
.subscribe((fooData) => {
// Compare for view update
if (JSON.stringify(fooData) !== JSON.stringify(this.data)) {
console.log('New stuff -> update view')
this.data = fooData;
}
});
}, fetchInterval)
// Shield Memory Leakeage after Component is deleted
ngOnDestroy(): void {
this.destroy$.next();
this.destroy$.complete();
}
This is generally a bad approach as ..
.. data is pulled although there is no update the data.
.. data may be pushed towards the view without any need (fixed).
.. the interval is (mostly) barely adjustable to fit the need of both sides, Client & Server.
It is recommended to at least check changes in the data before updating the view with the same data.
Maybe even offer an API which only serves a checksum before pulling the whole dataset.
Last:
The more advanced solution would be a two-way-binding.
Once an API is called which changes the data, angular gets an update for the backend. For this kind of solution you might want to take a look at socket.io ... ;-)
Okay so I have been facing the dreadful:
TypeError: Cannot read property 'Id' of undefined
Before we get started:
#angular/cli: 1.4.4
node: 6.10.3
npm: 3.10.10
Just to give more context, I am trying to perform one way data binding to edit a component by taking the Id from its component class and flow in a single direction to display the view template. That's all.
Below is the following that will hopefully try reproduce the problem and in turn figure out a solution.
SQL Table Definition:
CREATE TABLE [ExampleTable]
(
[Id] [int] IDENTITY(1,1) NOT NULL,
[Col2] [nvarchar](50) NULL,
[Col3] [int] NULL,
[Col4] [int] NULL
)
ExampleTable.ts
export interface ExampleTable {
Id;
Col2;
Col3;
Col4;
}
export class CreateExampleTableModel {
SomeForeignKey?: number;
Col2: string;
Col2: number;
Col2: number;
}
export class EditExampleTable {
}
empty-tables.component.ts
import {
Component
} from '#angular/core';
import {
Router
} from "#angular/router";
import {
EmptyTableServiceService
} from "../../services/empty-table.service";
import {
EmptyTable
} from "../../models/outModels/EmptyTable";
#Component({
selector: 'app-empty-tables',
templateUrl: './empty-tables.component.html',
styleUrls: ['./empty-tables.component.css']
})
export class EmptyTablesComponent {
//Table data
emptyTable: EmptyTable[];
constructor(
private router: Router,
private emptyTableServiceService: EmptyTableServiceService) {
}
edit(emptyTable: EmptyTable) {
this.router.navigate(['emptyTables/edit', emptyTable.Id]);
}
}
EmptyTableService:
import {
Injectable
} from '#angular/core';
import {
Http
} from '#angular/http';
import 'rxjs/add/operator/toPromise';
import {
EmptyTable,
CreateExampleTableModel
} from "../models/outModels/EmptyTable";
#Injectable()
export class EmptyTableService {
constructor(private http: Http, ) {}
getEmptyTable(Id: string): Promise<EmptyTable> {
return this.http.get(`${this.auth.apiUrl}/api/emptyTables/get/${Id}`, { headers: this.auth.header })
.toPromise()
.then(response => response.json() as EmptyTable)
.catch(error => this.logging.handleError(error));
}
update(emptyTable: EmptyTable): Promise < EmptyTable > {
return this.http.post(`${this.auth.apiUrl}/api/emptyTables/update`, JSON.stringify(emptyTable), {
headers: this.auth.header
})
.toPromise()
.then(response => response.json() as EmptyTable)
.catch(error => this.logging.handleError(error));
}
}
EmptyTableEditComponent:
import {
Component,
OnInit
} from '#angular/core';
import {
ActivatedRoute,
ParamMap,
Router
} from '#angular/router';
import {
EmptyTableService
} from "../../../services/empty-table.service";
import {
EmptyTable
} from "../../../models/outModels/EmptyTable";
export class EmptyTableEditComponent implements OnInit {
model: EmptyTable;
constructor(
private route: ActivatedRoute,
private router: Router,
private emptyTableService: EmptyTableService
) {}
ngOnInit() {
this.loading = true;
this.route.paramMap
.switchMap((params: ParamMap) => this.emptyTableService.getEmptyTable(params.get('Id')))
.subscribe(emptyTable => {
this.model = emptyTable;
});
}
goBack(): void {
this.router.navigate(['/emptyTables']);
}
save(): void {
this.loading = true;
this.emptyTableService.update(this.model).then(
emptyTable => {
this.model = emptyTable;
},
error => {
console.log(error);
}
);
}
}
My suspicion is that in my getEmptyTable(Id: string) which returns a Promise of EmptyTables is that I am passing in my Id parameter as a string value whereas in my table definition from my DB it is an integer however according to my understanding, url parameters are always in string format. I tried the following:
i. Setting my Id to a number data type and I call the toString() on the Idparameter in the apiUrl like so:
getEmptyTable(Id: number): Promise<EmptyTable> {
return this.http.get(`${this.auth.apiUrl}/api/emptyTables/get/${Id.toString()}`, { headers: this.auth.header })
.toPromise()
.then(response => response.json() as EmptyTable)
.catch(error => this.logging.handleError(error));
}
But this does not make much of a difference. Lastly, please find the view template which I render:
<div class="container">
<p-messages [(value)]="messages"></p-messages>
<p-panel *ngIf="model">
<p-header>
Edit EmptyTable {{model.Name}}
</p-header>
<form name="form" (ngSubmit)="save()">
<div class="form-group">
<label>Col 2</label>
<input type="text" class="form-control" name="col2" [(ngModel)]="model.Col2" required />
</div>
<div class="form-group">
<label>Col 3</label>
<input type="text" class="form-control" name="col3" [(ngModel)]="model.Col3" required />
</div>
<div class="form-group">
<button pButton type="button" class="ui-button-secondary" (click)="goBack()" label="Back" icon="fa-chevron-left"></button>
<button pButton class="ui-button-success pull-right" label="Save" icon="fa-save"></button>
<app-loader *ngIf="loading"></app-loader>
</div>
</form>
</p-panel>
</div>
To wrap this up, it complains in the following function:
edit(emptyTable: EmptyTable) {
this.router.navigate(['emptyTables/edit', emptyTable.Id]);
}
Note: Please don't run the snippets as there is no output to them. This was the quickest way to format my code. Manual indentation was not cutting it.
The problem was found below:
<ng-template let-user="rowData" pTemplate="body">
<button type="button" pButton (click)="edit(distributor)" icon="fa-edit"></button>
</ng-template>
let-user should have been changed to let-distributor and all works.
I am trying to display an alert after a user is registered. I have tried debugging and understood that it is going to error function always ( When a user is registered successfully and a user already exists).
Below is my code. I am not able to understood why is it always going into error.
Any help is appreciated since I am stuck with this from long time. Thanks in advance.
1)Alert Component
import { AlertService } from './../../shared/services/alert.service';
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-alert',
templateUrl: './alert.component.html',
styleUrls: ['./alert.component.css']
})
export class AlertComponent {
private _alertService;
private message: any;
constructor(alertService: AlertService) {
this._alertService = alertService;
}
ngOnInit() {
this._alertService.getMessage().subscribe(message => { this.message = message; });
}
}
2.Alert Template
<div *ngIf="message" [ngClass]="{ 'alert': message, 'alert-success': message.type === 'success',
'alert-danger': message.type === 'error' }">{{message.text}}</div>
3)Register Template
<div class="container">
<h2>Register</h2>
<form name="form" (ngSubmit)="f.form.valid && register()" #f="ngForm" novalidate>
<div class="form-group" [ngClass]="{ 'has-error': f.submitted && !username.valid }">
<label for="username">Username</label>
<input type="text" class="form-control" name="username" [(ngModel)]="model.username" #username="ngModel" required />
<div *ngIf="f.submitted && !username.valid" class="help-block">Username is required</div>
</div>
<div class="form-group" [ngClass]="{ 'has-error': f.submitted && !password.valid }">
<label for="password">Password</label>
<input type="password" class="form-control" name="password" [(ngModel)]="model.password" #password="ngModel" required minlength="10" />
<div *ngIf="f.submitted && !password.valid" class="help-block"> Password is required (minimum 10 characters)</div>
</div>
<div class="form-group">
<button class="btn btn-primary" (click)="registerUser()">Register</button>
<app-alert></app-alert>
<a [routerLink]="['']" class="btn btn-link">Cancel</a>
</div>
</form>
</div>
4)Register Component
import { AlertService } from './../../shared/services/alert.service';
import { RegisterService } from './../../shared/services/register.service';
import { Observable } from 'rxjs/Observable';
import { Component, OnInit } from '#angular/core';
import { Router, ActivatedRoute } from '#angular/router';
import { AuthService } from '../../shared/services/index';
import { Http, Request, RequestMethod, RequestOptions, Headers, Response } from '#angular/http';
#Component({
selector: 'app-register',
templateUrl: './register.component.html',
styleUrls: ['./register.component.css']
})
export class RegisterComponent implements OnInit {
private _authService: AuthService;
private _alertService: AlertService;
private _regsiterService: RegisterService;
private appContent = 'application/json';
private _router: Router;
private baseUrl = 'http://localhost:5000/api/v1/';
model: any = {};
username: string;
password: string;
constructor(authService: AuthService, http: Http, router: Router, registerService: RegisterService, alertService: AlertService) {
this._authService = authService;
this._regsiterService = registerService;
this._router = router;
this._alertService = alertService;
}
ngOnInit() {
}
registerUser() {
this._regsiterService.registerUser(this.model.username, this.model.password)
.subscribe(
data => {
console.log('Calling alert');
this._alertService.success('Registration Successful');
this._router.navigate(['/login']);
},
error => {
console.log('Calling alert');
// this._alertService.error(error);
});
}
}
5)Alert Service
import { Injectable } from '#angular/core';
import { Observable } from 'rxjs/Observable';
import {Subject} from 'rxjs/Subject';
#Injectable()
// Checks if a user is a authenticated user and has the valid token without expiration.
export class AlertService {
private subject = new Subject<any>();
success(message: string) {
console.log('Registration Successful');
this.subject.next({ type: 'success', text: message });
}
// error(message: string) {
// console.log('Registration Failed');
// this.subject.next({ type: 'error', text: message });
// }
getMessage(): Observable<any> { return this.subject.asObservable(); }
}
Below is the Error Screenshot
In your html you have:
(ngSubmit)="f.form.valid && register()"
But your method is:
registerUser() {
// ..
}
So the angular parser cannot find the register method that is defined in your html.
Unexpected end of json input
This error normally happens when you have a http call that gets failed for whatever reason ( wrong url, server is down, port is closed, ) and the returned response from the server is not a JSON.
Have a look at your network tab and see the http cal that you're making, what is that you're getting in the response tab.
Basically this error generally means, Javascript hasn't been able to parse something that it was meant to be JSON
If I were you I would check for typos in the template and ts file.
Also, you can try to just import the services at the top of the file and just add them in the constructor like this :
constructor(private authService: AuthService, private http: Http, private router: Router, private registerService: RegisterService, private alertService: AlertService) { }
I think TS will do the assignment for you.
Then onInit() or any other place you can write this.authService.someMethod() etc.
For sure the "not a function" error indicates misspelling/typo.
As it is mentioned already register() exist in your html template but not in the ts file. I would rename the properties of the RegisterComponent also to make sure that possible typos and bugs would be avoided in the future.
The Unexpected end of json input might be due to the fact that you are not providing a valid json from your server.
I haven't seen the code inside this._regsiterService.registerUser . But I believe there's a response.json() call that causes the issue.