How to match and validate with the provided API in Ionic? - api

I have created login function accordingly but the login function is not working. Whenever I enter the sample input (phoneNumber and password) it did not directing me to the HomePage. Details about API has been provided in the pictures below. Is there anything I am missing out? Please HELP me to solve this out.
API details:
HTML CODE:
<ion-header>
<ion-navbar>
<ion-title>
Login
</ion-title>
</ion-navbar>
</ion-header>
<ion-content padding>
<ion-list>
<form name="form"(ngSubmit)="login()" novalidate>
<ion-item>
<ion-label fixed>Phone Number</ion-label>
<ion-input type="number" name="phoneNumber" value="" [(ngModel)]="model.phoneNumber" required></ion-input>
</ion-item>
<ion-item>
<ion-label fixed>Password</ion-label>
<ion-input type="password" name="password" value="" [(ngModel)]="model.password" required></ion-input>
</ion-item>
<ion-item>
<button ion-button>Enter</button>
</ion-item>
</form>
</ion-list>
</ion-content>
.TS CODE:
import { Component } from '#angular/core';
import { NavController, AlertController, LoadingController, ToastController } from 'ionic-angular';
import { HomePage } from '../home/home';
import { apiService } from '../../providers/api-service.service';
import { AuthService } from '../../providers/auth-service.service';
#Component({
selector: 'page-login',
templateUrl: 'login.html'
})
export class LoginPage {
model : any = {};
response: any[] = [];
constructor(public navCtrl: NavController, public apiService: apiService, public toastCtrl: ToastController, public alertCtrl: AlertController, public loadingCtrl: LoadingController, public AuthService: AuthService){}
loginUser(){
this.AuthService.login();
}
logoutUser(){
this.AuthService.logout();
}
nextPage(data){
this.navCtrl.push(HomePage,data).catch(err => {
let alert = this.alertCtrl.create({
title: 'Something',
subTitle: 'something something',
buttons: ['OK']
});
alert.present();
});
}
errorToast(){
let toast = this.toastCtrl.create({
message: 'Cannot login',
duration: 3000
});
toast.present();
}
logoutout(){
let loader = this.loadingCtrl.create({
content: "Loging out.....",
duration: 1000
})
loader.present();
this.loginUser();
}
login(){
this.apiService.apiCall(this.model.phoneNumber, this.model.password)
.then(data => {
this.logoutout();
this.nextPage(data);
})
.catch(error => {
this.errorToast();
})
}
}
PROVIDERS CODE:
api-service.service.ts
import {Injectable} from '#angular/core';
import {Http, Headers, RequestOptions} from '#angular/http';
import 'rxjs/add/operator/map'
#Injectable()
export class apiService{
constructor(private http: Http){}
apiCall(phoneNumber, password){
let headers = new Headers({
"X-Auth-PhoneNumber": '',
"X-Auth-Password": '',
"SW-Version": '',
"Device-Id": '',
"Device-Model": ''
})
let options = new RequestOptions({
headers: headers
});
return this.http.get('https://api.keyway.com.my/client/mobile/verification'+ phoneNumber + password, options)
.map(res => res.json())
.toPromise();
}
}
auth-service.service.ts
import {Injectable} from '#angular/core';
#Injectable()
export class AuthService{
private isLoggedIn = false;
constructor(){}
login(): void{
this.isLoggedIn = true;
}
logout(): void{
this.isLoggedIn = false;
}
authenticated():boolean{
return this.isLoggedIn;
}
}

Because you are sending username and password with request URL but as per request defination you need to send in headers so,please made some changes like below -
apiCall(phoneNumber, password){
let headers = new Headers({
"X-Auth-PhoneNumber": phoneNumber',
"X-Auth-Password": password,
"SW-Version": '',
"Device-Id": '',
"Device-Model": ''
})
let options = new RequestOptions({
headers: headers
});
return this.http.get('https://api.keyway.com.my/client/mobile/verification', options)
.map(res => res.json())
.toPromise();
}
Also try to console output after request.
login(){
this.apiService.apiCall(this.model.phoneNumber, this.model.password)
.then(data => {
console.log(data); // Console Output
this.logoutout();
this.nextPage(data);
})
.catch(error => {
console.log(error); // Console Error output
this.errorToast();
})
}

Related

How can I password protect every page in NextJS and Supabase, using the Supabase default auth helpers and UI?

I'm trying to add user authentication to every page in my NextJS project (pages, not app.) This tutorial was very helpful (and is exactly what I want to do) - https://alexsidorenko.com/blog/next-js-protected-routes/ - but I'm having trouble integrating Supabase's default auth UI and capabilities into that model (https://supabase.com/docs/guides/auth/auth-helpers/nextjs).
My basic goal is to move authentication branching into _app.tsx, rather than on each page:
// _app.tsx
import { useEffect, useState } from "react";
import { createBrowserSupabaseClient } from '#supabase/auth-helpers-nextjs'
import { SessionContextProvider, useUser, useSession, useSupabaseClient, Session } from '#supabase/auth-helpers-react'
import { Auth, ThemeSupa } from '#supabase/auth-ui-react'
import { AppProps } from 'next/app'
import { UserContext } from "#components/user"
function MyApp({Component, pageProps}: AppProps<{ initialSession: Session }>) {
const [supabase] = useState(() => createBrowserSupabaseClient())
const session = useSession()
const user = useUser()
console.log("session:" + session);
console.log("user:" + user);
useEffect(() => {
if (
pageProps.protected
) {
return <Auth supabaseClient={supabase} appearance={{ theme: ThemeSupa }} theme="dark" />
}
}, [])
return (
<SessionContextProvider supabaseClient={supabase} session={session} initialSession={pageProps.initialSession}>
<Component {...pageProps} />
</SessionContextProvider>
)
}
export default MyApp
A page I want to protect (for example, the index page) looks like this:
// index.tsx
import Account from "#components/account";
const Home = () => {
return (
<div>
<Account session={session} />
</div>
)
}
export async function getStaticProps(context) {
return {
props: {
protected: true,
},
}
}
export default Home
And then the Account component that's included on the index page is the Supabase out of the box profile panel, although it could be any content:
// #components/account.tsx
import { useState, useEffect } from 'react'
import { useUser, useSupabaseClient, Session } from '#supabase/auth-helpers-react'
import { Database } from '#utils/database.types'
type Profiles = Database['public']['Tables']['profiles']['Row']
export default function Account({ session }: { session: Session }) {
const supabase = useSupabaseClient<Database>()
const user = useUser()
const [loading, setLoading] = useState(true)
const [username, setUsername] = useState<Profiles['username']>(null)
useEffect(() => {
getProfile()
}, [session])
async function getProfile() {
try {
setLoading(true)
if (!user) throw new Error('No user')
let { data, error, status } = await supabase
.from('profiles')
.select(`username`)
.eq('id', user.id)
.single()
if (error && status !== 406) {
throw error
}
if (data) {
setUsername(data.username)
}
} catch (error) {
alert('Error loading user data!')
console.log(error)
} finally {
setLoading(false)
}
}
async function updateProfile({
username,
}: {
username: Profiles['username']
}) {
try {
setLoading(true)
if (!user) throw new Error('No user')
const updates = {
id: user.id,
username,
updated_at: new Date().toISOString(),
}
let { error } = await supabase.from('profiles').upsert(updates)
if (error) throw error
alert('Profile updated!')
} catch (error) {
alert('Error updating the data!')
console.log(error)
} finally {
setLoading(false)
}
}
return (
<div>
<div>
<label htmlFor="email">Email</label>
<input id="email" type="text" value={session.user.email} disabled />
</div>
<div>
<label htmlFor="username">Username</label>
<input id="username" type="text" value={username || ''} onChange={(e) => setUsername(e.target.value)} />
</div>
<div>
<button onClick={() => updateProfile({ username })} disabled={loading} >
{loading ? 'Loading ...' : 'Update'}
</button>
</div>
<div>
<button onClick={() => supabase.auth.signOut()}>
Sign Out
</button>
</div>
</div>
)
}
I think I have a fundamental misunderstanding of the relationship between protected routes and Supabase's use of session and user.
Any help would be very much appreciated.
I'd recommend using Next.js middleware for this: https://supabase.com/docs/guides/auth/auth-helpers/nextjs#auth-with-nextjs-middleware
import { createMiddlewareSupabaseClient } from '#supabase/auth-helpers-nextjs'
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
export async function middleware(req: NextRequest) {
// We need to create a response and hand it to the supabase client to be able to modify the response headers.
const res = NextResponse.next()
// Create authenticated Supabase Client.
const supabase = createMiddlewareSupabaseClient({ req, res })
// Check if we have a session
const {
data: { session },
} = await supabase.auth.getSession()
// Check auth condition
if (session?.user.email?.endsWith('#gmail.com')) {
// Authentication successful, forward request to protected route.
return res
}
// Auth condition not met, redirect to home page.
const redirectUrl = req.nextUrl.clone()
redirectUrl.pathname = '/'
redirectUrl.searchParams.set(`redirectedFrom`, req.nextUrl.pathname)
return NextResponse.redirect(redirectUrl)
}
export const config = {
matcher: '/middleware-protected/:path*',
}

Vuejs & Auth0 : I need to reload page to be Authenticated

I'm a beginner in Vue, and I implemented Auth0 to my Web App using Vue3.
My issue: after logging in, my API call to retrieve data get an unauthorized error 403. If I reload the page, everything is working fine.
What should I do to avoid reloading the page to get authenticated directly?
Here are my scripts:
Main.js
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import './index.css'
import dayjs from 'dayjs'
import Datepicker from 'vue3-date-time-picker'
import 'vue3-date-time-picker/dist/main.css'
import { setupAuth } from './auth/index.js'
import authConfig from './auth/config.js'
function callbackRedirect(appState) {
router.push(appState && appState.targetUrl ? appState.targetUrl : '/' );
}
setupAuth(authConfig, callbackRedirect).then((auth) => {
let app = createApp(App).use(router);
app.config.globalProperties.$dayjs = dayjs;
app.component('Datepicker', Datepicker);
app.use(auth).mount('#app');
})
My App.vue script:
<template>
<div v-if="isAuthenticated">
<NavBar />
<router-view/>
</div>
</template>
<script>
import NavBar from './components/NavBar.vue'
export default {
components: { NavBar },
data(){
return {
isAuthenticated: false,
}
},
async mounted(){
await this.getAccessToken()
},
methods: {
async getAccessToken(){
try {
const accessToken = await this.$auth.getTokenSilently()
localStorage.setItem('accessToken', accessToken)
this.isAuthenticated = true
} catch (error) {
console.log('Error occured while trying to retrieve Access Token...', error)
}
},
},
}
</script>
and my Home.vue loading the data:
<template>
<div class="home">
<div class="py-10">
<header>
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<h1 class="text-3xl font-bold leading-tight text-gray-900">Monitoring Dashboard</h1>
</div>
</header>
<main>
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
<h3 class="m-5 text-lg leading-6 font-medium text-gray-900">Main KPIs</h3>
<div class="md:grid md:grid-cols-3 md:gap-6">
<div v-for="(item, index) in stats" :key="index" class="md:col-span-1">
<div class="bg-white p-5 border-gray-50 rounded-lg shadow-lg mb-5">
<span class="text-sm font-medium text-gray-500 truncate">{{ item.name }}</span>
<p class="mt-1 text-3xl font-bold text-gray-900">{{ parseFloat(item.stat.toFixed(2)) }}</p>
</div>
</div>
</div>
</div>
</main>
</div>
</div>
</template>
<script>
import _ from 'lodash'
import ProductsService from '../services/products.service'
export default {
name: 'Home',
data(){
return{
user: '',
products: '',
stats: '',
}
},
async mounted(){
await this.readProducts()
await this.buildStats()
},
methods: {
async readProducts(){
let temp = null
try {
temp = await ProductsService.readProducts()
this.products = temp.data
} catch (error) {
console.log('Error: cannot retrieve all products...')
}
},
async buildStats(){
//Nb products
const nbProducts = this.products.length
//Nb offers & Uniq NbRetailers
let nbOffers = 0
let retailers = []
for(let product of this.products){
for(let offer of product.offers){
retailers.push(offer.retailer)
nbOffers += 1
}
}
const nbRetailers = _.uniq(retailers).length
this.stats = [
{ name: 'Number of Retailers', stat: nbRetailers },
{ name: 'Number of Products', stat: nbProducts },
{ name: 'Number of Offers', stat: nbOffers },
]
},
},
watch: {
products: function(){
this.buildStats()
}
}
}
</script>
My ./auth/index.js file:
import createAuth0Client from '#auth0/auth0-spa-js'
import { computed, reactive, watchEffect } from 'vue'
let client
const state = reactive({
loading: true,
isAuthenticated: false,
user: {},
popupOpen: false,
error: null,
})
async function loginWithPopup() {
state.popupOpen = true
try {
await client.loginWithPopup(0)
} catch (e) {
console.error(e)
} finally {
state.popupOpen = false
}
state.user = await client.getUser()
state.isAuthenticated = true
}
async function handleRedirectCallback() {
state.loading = true
try {
await client.handleRedirectCallback()
state.user = await client.getUser()
state.isAuthenticated = true
} catch (e) {
state.error = e
} finally {
state.loading = false
}
}
function loginWithRedirect(o) {
return client.loginWithRedirect(o)
}
function getIdTokenClaims(o) {
return client.getIdTokenClaims(o)
}
function getTokenSilently(o) {
return client.getTokenSilently(o)
}
function getTokenWithPopup(o) {
return client.getTokenWithPopup(o)
}
function logout(o) {
return client.logout(o)
}
export const authPlugin = {
isAuthenticated: computed(() => state.isAuthenticated),
loading: computed(() => state.loading),
user: computed(() => state.user),
getIdTokenClaims,
getTokenSilently,
getTokenWithPopup,
handleRedirectCallback,
loginWithRedirect,
loginWithPopup,
logout,
}
export const routeGuard = (to, from, next) => {
const { isAuthenticated, loading, loginWithRedirect } = authPlugin
const verify = () => {
// If the user is authenticated, continue with the route
if (isAuthenticated.value) {
return next()
}
// Otherwise, log in
loginWithRedirect({ appState: { targetUrl: to.fullPath } })
}
// If loading has already finished, check our auth state using `fn()`
if (!loading.value) {
return verify()
}
// Watch for the loading property to change before we check isAuthenticated
watchEffect(() => {
if (loading.value === false) {
return verify()
}
})
}
export const setupAuth = async (options, callbackRedirect) => {
client = await createAuth0Client({
...options,
})
try {
// If the user is returning to the app after authentication
if (
window.location.search.includes('code=') &&
window.location.search.includes('state=')
) {
// handle the redirect and retrieve tokens
const { appState } = await client.handleRedirectCallback()
// Notify subscribers that the redirect callback has happened, passing the appState
// (useful for retrieving any pre-authentication state)
callbackRedirect(appState)
}
} catch (e) {
state.error = e
} finally {
// Initialize our internal authentication state
state.isAuthenticated = await client.isAuthenticated()
state.user = await client.getUser()
state.loading = false
}
return {
install: (app) => {
app.config.globalProperties.$auth = authPlugin
},
}
}

Progress bar with Vue and Axios object

I would like to create an upload progress bar with Axios.
Everything is working fine with server sending and response.
The problem is that I don't know how to capture the progress percentage (which is correctly calculated) from my exported object.
My file upload.js:
import axios from 'axios'
const baseUrl = 'http://localhost:80/upload.php'
const config = {
Headers: {'Content-Type': 'multipart/form-data'},
onUploadProgress: progressEvent => {
return parseInt(Math.round((progressEvent.loaded / progressEvent.total) * 100))
}
}
export default {
send (data) {
return axios.post(baseUrl, data, config)
}
}
My Vue component:
<template>
<div>
<label>File:</label>
<input type="file" id="file" ref="file" #change="changeFile()" />
<button #click="submit()">Upload</button>
<br />
<progress max="100" :value.prop="uploadPercentage"></progress>
</div>
</template>
<script>
import upload from '../services/upload.js'
export default {
name: 'Upload',
data: () => ({
file: null,
uploadPercentage: 0
}),
methods: {
submit () {
const formData = new FormData()
formData.append('file', this.file)
upload.send(formData)
.then(res => {
console.log(res.data)
})
.catch(() => {
console.log('Failure')
})
},
changeFile () {
this.file = this.$refs.file.files[0]
}
}
}
</script>
How to retreive, from the component submit method, the info sent by the onUploadProgress in order to update the data uploadPercentage?
Thanks.
Regards.
You need to pass a function to your send operation that will be called later.
See example below
const config = {
Headers: {'Content-Type': 'multipart/form-data'},
onUploadProgress: progressEvent => {
var progress= parseInt(Math.round((progressEvent.loaded / progressEvent.total) * 100));
if (config.onProgress)
config.onProgress(progress);
}
}
export default {
send (data, onProgress) {
config.onProgress= onProgress;
return axios.post(baseUrl, data, config)
}
}
Then you upload code will be
upload.send(formData,(pogress)=>{
// Update your uploadPercentage here
})
.then(res => {
console.log(res.data)
})
.catch(() => {
console.log('Failure')
})

I want to display a single hymn song details

Hymn-home code:
<ion-header>
<ion-toolbar>
<ion-title>
<ion-buttons>
<img src="./assets/icon/logo.png" id="logo2">
Enyimba Z'Omutukirivu
</ion-buttons>
</ion-title>
<ion-buttons slot="end">
<ion-button href="/searh-hymn">
<ion-icon name="search" slot="icon-only">
</ion-icon></ion-button>
<ion-button><ion-icon name="ellipsis-vertical-outline" slot="icon-only"></ion-icon></ion-button>
</ion-buttons>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-virtual-scroll [items]= "hymn">
<ion-item
*virtualItem="let song"
button
detail
[routerLink]="['/', 'hymn-detail', song.id]"
>
<ion-label>{{ song.title }}</ion-label>
</ion-item>
</ion-virtual-scroll>
</ion-content>
hymn-home.ts code
import { Component, OnInit } from '#angular/core';
import { HymnServiceService } from '../hymn-service.service';
import { NavController } from '#ionic/angular';
import { Router } from '#angular/router';
import { Hymn } from '../hymn.model';
import { Subscription } from 'rxjs';
#Component({
selector: 'app-hymn-home',
templateUrl: './hymn-home.page.html',
styleUrls: ['./hymn-home.page.scss']
})
export class HymnHomePage implements OnInit {
hymn: Hymn[];
public hymnsub: Subscription;
constructor(public HymnService: HymnServiceService,
private router: Router,
public navCtrl: NavController) { }
ngOnInit() {
}
ionViewWillEnter() {
this.HymnService.fetchHymns().subscribe(data => {
console.dir(data)
this.hymn = data;
});
}
}
hymn-detail html code
<ion-header>
<ion-toolbar>
<ion-buttons slot="start">
<ion-back-button defaultHref="/hymn-home" icon="chevron-back-outline"></ion-back-button>
</ion-buttons>
<ion-buttons>
<img src="./assets/icon/logo.png" id="logo2">
</ion-buttons>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-grid>
<ion-row>
<ion-col size="12" size-sm="8" offset-sm="2">
<ion-item>{{ hymn?.title }}</ion-item>
<ion-item>
{{ hymn?.details }}
</ion-item>
</ion-col>
</ion-row>
</ion-grid>
</ion-content>
Hymn detail.ts
import { Component, OnInit } from '#angular/core';
import { HymnServiceService } from '../hymn-service.service';
import { Router, ActivatedRoute } from '#angular/router';
import { Hymn } from '../hymn.model';
import { Subscription } from 'rxjs';
import { NavController } from '#ionic/angular';
#Component({
selector: 'app-hymn-detail',
templateUrl: './hymn-detail.page.html',
styleUrls: ['./hymn-detail.page.scss'],
})
export class HymnDetailPage implements OnInit {
hymn : Hymn;
hymnId: string;
public hymnsub: Subscription;
constructor(public hymnService: HymnServiceService,
private actroute: ActivatedRoute, private router: Router,
private navCtrl: NavController) { }
ngOnInit() {
this.actroute.paramMap.subscribe(paramMap => {
this.hymnId = paramMap.get('hymnId');
this.hymnsub = this.hymnService
.readHymn(paramMap.get('hymnId')).subscribe(hymn => {
console.log(hymn);
this.hymn = hymn;
})
});
}
}
hymnservice.ts
import { Injectable } from '#angular/core';
import { map, tap, take } from 'rxjs/operators';
import { HttpClient } from '#angular/common/http';
import { BehaviorSubject } from 'rxjs';
import { Hymn } from './hymn.model';
interface hymnData{
id: string;
numb: number;
title: string;
details: string;
}
#Injectable({
providedIn: 'root'
})
export class HymnServiceService {
private _hymns = new BehaviorSubject<Hymn[]>([]);
constructor(public http: HttpClient) { }
fetchHymns() {
let url = "http://localhost/MyApp/php/read.php";
let request = this.http.get<{[key: string] : hymnData}>(url);
return request.pipe(map(resData => {
const hymns = [];
for (const key in resData) {
if (resData.hasOwnProperty(key)) {
hymns.push (
new Hymn(resData[key].id, resData[key].numb,
resData[key].title, resData[key].details)
)
}
}
return hymns;
}),
tap(hymns => {
this._hymns.next(hymns);
}));
}
readHymn(id: string) {
let url = "http://localhost/MyApp/php/read.php";
let request = this.http.get<hymnData>(url);
return request.pipe(map(hymnData => {
return new Hymn(id, hymnData.numb, hymnData.title, hymnData.details);
})
);
}
}
hymn model.ts
export class Hymn {
constructor(
public id: string,
public numb: number,
public title: string,
public details: string
){}
}
and my php file.
<?php
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Credentials: true');
header('Access-Control-Allow-Methods: POST, GET, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-with');
header('Content-Type: application/json; charset=utf-8');
define('DB_NAME', 'hymnsdb');
define('DB_USER', 'root');
define('DB_PASSWORD', '');
define('DB_HOST', 'localhost');
$conn = mysqli_connect(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);
if($conn->connect_error) {
die("Connection failed " . $conn->connect_error);
}
$query = "SELECT * FROM `songs` ";
$result = mysqli_query($conn, $query);
$data = array();
while ($row=mysqli_fetch_object($result)) {
//$output = array();
//$output = $result->fetch_all(MYSQLI_ASSOC);
//echo json_encode($output);
$data[] = $row;
}
echo json_encode($data);
echo mysqli_error($conn);
//else {
//echo json_encode("No Hymns");
//}
$conn->close();`enter code here`
?>
I really need help. In details page console it brings title, numb,id, details = null.

Reference error in angular 5 and .netcore

I'm trying to do a simple form post to my controller but I keep getting the following error : cannot access username of undefined. As far as i can tell i'm initializing the usermodel in my login component but have no idea why it's still erroring.
Does anyone have any ideas?
html
<form #loginForm="ngForm" (ngSubmit) ="OnSubmit(loginForm)">
<div class="form-row">
<div class="form-group col-md-6">
<input type="text" name="username" #username="ngModel" [(ngModel)]="user.username" class="form-control" />
</div>
<div class="form-group col-md-6">
<input type="text" name="password" #password="ngModel" [(ngModel)]="user.password" class="form-control" />
</div>
</div>
<div class="form-group">
<button type="submit" class="btn btn-block btn-lg">login</button>
</div>
user.model.ts
export class UserModel {
username: string;
password: string;
}
user.service.ts
import { HttpClient, HttpHeaders } from '#angular/common/http';
import { UserModel } from './user.model';
import { Inject, Injectable } from '#angular/core';
#Injectable()
export class UserService {
constructor(private http: HttpClient) { }
postUser(user: UserModel, #Inject('BASE_URL') baseUrl: string) {
return this.http.post(baseUrl + '/Test/Register', new HttpHeaders({ 'username': user.username, 'password': user.password })).subscribe(result => {
console.error(result)
}, error => console.error(error));
}
login.component.ts
import { Component, Inject, OnInit } from '#angular/core';
import { NgForm } from '#angular/forms';
import { UserModel } from './user.model';
import { UserService } from './user.service';
#Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
user: UserModel
constructor(private userService: UserService) { }
ngOnInit() {
this.resetForm();
}
resetForm(form?: NgForm) {
if (form != null) {
form.reset();
this.user = {
username: '',
password: ''
}
}
}
onSubmit(form: NgForm) {
this.userService.postUser(form.value, "https://localhost:44327/");
};
This is caused by that you did not initialize the this.user when loading this page.
Try this:
resetForm(form?: NgForm) {
if (this.user == undefined) {
this.user = new UserModel();
}
if (form != null) {
form.reset();
this.user = {
username: '',
password: ''
}
}
}