Expected 2 arguments, but got 1.ts(2554) - javascript

Good morning friends, sorry for the inconvenience I am doing practices to learn and I was doing a login, but the problem is that I am trying to connect it to an api and it does not make the connection, it gives me a super strange error in the login component
Here I attach the login.component
import { Component, } from '#angular/core';
import { AppserviceService } from '../../services/appservice.service';
import { NgForm } from '#angular/forms';
import { AppsResp } from '../../interfaces/interfaces';
import { FormsModule } from '#angular/forms';
#Component({
selector: 'app-login',
templateUrl: './login.component.html',
})
export class LoginComponent {
email:string ='';
password:string='';
constructor(public AppserviceService: AppserviceService) { }
login() {
const user = {email: this.email, password: this.password};
this.AppserviceService.login(user).subscribe( data => {
console.log(data);
});
}
}
the error that fits is the following_ "Expected 2 arguments, but got 1.ts(2554)
appservice.service.ts(15, 26): An argument for 'password' was not provided."
Here I attach the app services service, which is where the origin of the error marks me
import { HttpClient } from '#angular/common/http';
import { Injectable, Query } from '#angular/core';
import { Observable } from 'rxjs';
import { AppsResp, Registro } from '../interfaces/interfaces';
#Injectable({
providedIn: 'root'
})
export class AppserviceService {
constructor(private http: HttpClient) { }
login ( email: string, password: string ){
const body = {email,password}
return this.http.post <AppsResp>("http://apitest.e-bango.com/api/auth/login" , body );
}
}
Likewise, I can't find the correct logic to insert the registry component in my service, can you help me? and explain in as much detail as possible what I'm doing wrong? Thank you

I think you have 2 ways to resolve this problem
1: Your input to function login is not correct
login() {
const user = {email: this.email, password: this.password};
this.AppserviceService.login(user).subscribe( data => {
console.log(data);
});
}
Change to
login() {
this.AppserviceService.login(email: this.email, password: this.password).subscribe( data => {
console.log(data);
});
}
2: Change the function login
login ( email: string, password: string ){
const body = {email,password}
return this.http.post <AppsResp>("http://apitest.e-bango.com/api/auth/login" , body );
}
to
login ( {email: string, password: string }){
const body = {email,password}
return this.http.post <AppsResp>("http://apitest.e-bango.com/api/auth/login" , body );
}

just change login method in appserviceService
login ( body ){
return this.http.post <AppsResp>("http://apitest.e-bango.com/api/auth/login" , body );
}

its because your .login from AppserviceService is accepts or excepts 2 arguments, this is email and password. But you gonna put there user object
try this
export class LoginComponent {
email:string ='';
password:string='';
constructor(public AppserviceService: AppserviceService) { }
login() {
this.AppserviceService.login(this.email, this.password).subscribe( data => {
console.log(data);
});
}
}

Please check destructuring in the docs
login ({email, password}){
...
}
You can also give values by defect
login ({email="",password=""}){
...
}
And you can indicate the type
login(({email="",password=""}:{email?:string,password?:string}){
...
}
If you use "optional parameters" use ? to indicate is optional
BTW: you can pass the user itself
login(user:{email?:string,password?:string}){
return this.http.post(...,user);
}

Related

SyntaxError: Unexpected token in Angular

I want to add my website a user's profile updater. But when I try to open user's profile in my website, I have that error in Angular:
main.ts:6 ERROR SyntaxError: Unexpected token 'e', "eyJhbGciOi"... is not valid JSON
at JSON.parse (<anonymous>)
at LocalStorageService.getItem (local-storage.service.ts:17:22)
at get getDecodedToken [as getDecodedToken] (auth.service.ts:39:42)
at get getCurrentUserId [as getCurrentUserId] (auth.service.ts:44:29)
at UserComponent.getUserById (user.component.ts:51:51)
at UserComponent.ngOnInit (user.component.ts:28:10)
at callHook (core.mjs:2752:22)
at callHooks (core.mjs:2721:17)
at executeInitAndCheckHooks (core.mjs:2672:9)
at refreshView (core.mjs:12084:21)`
My local-storage.service.ts:
import { Injectable } from '#angular/core';
#Injectable({
providedIn: 'root'
})
export class LocalStorageService {
constructor() { }
setItem(key:string, value:any){
let json = JSON.stringify(value);
localStorage.setItem(key, json);
}
getItem(key:string){
let json = localStorage.getItem(key);
let value = JSON.parse(json);
return value;
}
isSaved(key: string) {
if (localStorage.getItem(key)) {
return true;
}
return false;
}
remove(key: string) {
localStorage.removeItem(key);
}
removeAll() {
localStorage.clear();
}
}
auth.service.ts:
`import { HttpClient } from '#angular/common/http';
import { Injectable } from '#angular/core';
import { LoginModel } from '../models/loginModel';
import { SingleResponseModel } from '../models/singleResponseModel';
import { TokenModel } from '../models/tokenModel';
import { LocalStorageService } from './local-storage.service';
import { UserPasswordModel } from '../models/userPasswordModel';
import { ResponseModel } from '../models/responseModel';
import { JwtHelperService } from '#auth0/angular-jwt';
#Injectable({
providedIn: 'root'
})
export class AuthService {
apiUrl="https://localhost:5001/api/auth/";
public jwtHelperService: JwtHelperService = new JwtHelperService();
constructor(private httpClient:HttpClient,
private localStorageService:LocalStorageService) {}
login(user:LoginModel){
return this.httpClient.post<SingleResponseModel<TokenModel>>(this.apiUrl+"login", user);
}
isAuthenticated(){
if (localStorage.getItem("token")) {
return true;
}else{
return false;
}
}
updatePassword(userPasswordModel:UserPasswordModel){
let newUrl = this.apiUrl + "updatepassword";
return this.httpClient.post<ResponseModel>(newUrl, userPasswordModel)
}
get getDecodedToken() {
let token = this.localStorageService.getItem("token");
return this.jwtHelperService.decodeToken(token);
}
get getCurrentUserId() {
let decodedToken = this.getDecodedToken;
let userIdString = Object.keys(decodedToken).filter((t) =>
t.endsWith('/nameidentifier')
)[0];
let userId: number = decodedToken[userIdString];
return userId;
}
}
user.component.ts:
import { Component, OnInit } from '#angular/core';
import { FormBuilder, FormGroup, Validators } from '#angular/forms';
import { ToastrService } from 'ngx-toastr';
import { User } from 'src/app/models/user';
import { AuthService } from 'src/app/services/auth.service';
import { ProfileService } from 'src/app/services/profile.service';
#Component({
selector: 'app-user',
templateUrl: './user.component.html',
styleUrls: ['./user.component.css']
})
export class UserComponent implements OnInit {
user:User;
profileForm:FormGroup;
passwordForm:FormGroup;
dataLoaded = false;
constructor(
private userService:ProfileService,
private authService:AuthService,
private formBuilder:FormBuilder,
private toastrService:ToastrService
) { }
ngOnInit(): void {
this.getUserById();
this.createProfileForm();
this.createPasswordForm();
}
createProfileForm(){
this.profileForm = this.formBuilder.group({
id:[Number(this.authService.getCurrentUserId)],
firstName: ["",Validators.required],
lastName:["",Validators.required]
})
}
createPasswordForm(){
this.passwordForm = this.formBuilder.group({
userId:[Number(this.authService.getCurrentUserId)],
oldPassword: ["",Validators.required],
newPassword:["",Validators.required],
repeatNewPassword:["",Validators.required]
})
}
getUserById(){
this.userService.getUserById(this.authService.getCurrentUserId)
.subscribe(response=>{
this.user = response.data
this.dataLoaded = true
});
}
updateUserNames(){
if (this.profileForm.valid) {
let userModel = Object.assign({}, this.profileForm.value);
this.userService.updateUserNames(userModel).subscribe(response=>{
this.toastrService.info(response.message, "Bilgiler Güncellendi.");
setTimeout(() => {
window.location.reload();
}, 1000);
}, responseError=>{
console.log(responseError);
this.toastrService.error(responseError.error, "Hata!");
});
} else {
this.toastrService.error("Lütfen tüm alanları doldurunuz.", "Hata!");
}
}
updatePassword(){
if (this.passwordForm.valid) {
let passwordModel = Object.assign({}, this.passwordForm.value);
console.log(passwordModel);
this.authService.updatePassword(passwordModel).subscribe(response=>{
this.toastrService.info(response.message, "Şifre Güncellendi");
}, responseError=>{
this.toastrService.error(responseError.error, "Hata!");
});
} else {
this.toastrService.error("Lütfen tüm alanları doldurunuz.", "Hata!");
}
}
}
How can I fix this error? Thanks. I tried lots of thins, but no-one helped me.
I am trying to add a user's profile updater. But this error...
As the error says; Unexpected token 'e', "eyJhbGciOi"... is not valid JSON. You are trying to parse a plain string represents token itself, not a valid string represents a json object.. Therefore it fails when trying to parse it.
Either update the code where you directly store your token as string on your local storage or just use localStorage.getItem('token') without parsing.

I am getting '[object Object]' from service to component using Angular

Please help on the below issue this is my model class. I tried all the possible ways using .pipe.map() import {map} from rxjs/operators method, but still giving [object Object]
export class AppProfilesDetailsDO {
envName?: string;
envDesc?: string;
envIpAddress?: string;
envProfileName?: string;
envCrDeployed?: string;
envUrl?: string;
envAdminConsoleUrl?: string;
envDbSchema?: string;
envDbUserId?: string;
envGisSchema?: string;
envPortNo?: number;
}
my component class
import { Component, OnInit } from '#angular/core';
import { ProfileserviceService } from './profileservice.service';
import { AppProfilesDetailsDO } from '../models/AppProfilesDetailsDO';
#Component({
selector: 'app-profiledetails',
templateUrl: './profiledetails.component.html',
styleUrls: ['./profiledetails.component.css']
})
export class ProfiledetailsComponent implements OnInit {
appProfileData: AppProfilesDetailsDO[];
constructor(private profileService: ProfileserviceService) { this.appProfileData = [] }
ngOnInit() {
console.log("In profiledetails component");
this.profileService.getProfileSetUpDetails().subscribe(
appProfileData => {
this.appProfileData = appProfileData;
}
);
console.log("Compenent Profile Data: "+this.appProfileData); ==> **in my console it is
printing as ==> [object Object] **
}
}
My service component
import { HttpClient } from "#angular/common/http";
import { Injectable } from "#angular/core";
import { Observable } from "rxjs";
import { AppProfilesDetailsDO } from "../models/AppProfilesDetailsDO";
#Injectable({
providedIn: 'root'
})
export class ProfileserviceService {
BASE_PATH:string = "http://localhost:8080/getProfileSetUpDetails";
constructor(private httpClient: HttpClient) {}
httpOptions = {
headers: new Headers ({
'Content-type': 'application/json'
})
}
appProfileData?: AppProfilesDetailsDO[];
getProfileSetUpDetails() : Observable<AppProfilesDetailsDO[]> {
return this.httpClient.get<AppProfilesDetailsDO[]>(this.BASE_PATH);
}
}
I am not sure where it is wrong. Please help on this issue.
Thanks.
The problem is this line console.log("Compenent Profile Data: "+this.appProfileData);. You are trying to concatenate an object with a string.
Simply change that line to console.log("Compenent Profile Data: ", this.appProfileData);
For more clarity look at this example:
var data = { a: "ali" };
console.log("Compenent Profile Data: " , data); console.log("Compenent Profile Data: " + data);
If you want to see the result it should be like this
console.log("Component Profile Data:", this.appProfileData);
other ways it will try to log the concatenated value of string with the result object which is impossible
You can not impose concatenation in between string and an array of object as you did like this:
console.log("Compenent Profile Data: "+this.appProfileData);
So, just use like this instead and problem will be gone:
console.log(this.appProfileData);

How to add custom unique validator for form values in angular reactive form?

I want to add a custom unique validator that will validate that all label fields values are unique.
(I) When I change the form values, the value of this.form changes after it is passed in CustomValidator.uniqueValidator(this.form). How to fix this?
(II) Is there any way of doing this without using any package?
Note: Forms have default values on load. Here is the screenshot.
this.form = this.fb.group({
fields: this.fb.array([])
});
private addFields(fieldControl?) {
return this.fb.group({
label: [
{value: fieldControl ? fieldControl.label : '', disabled: this.makeComponentReadOnly}, [
Validators.maxLength(30), CustomValidator.uniqueValidator(this.form)
]],
isRequired: [
{value: fieldControl ? fieldControl.isRequired : false, disabled: this.makeComponentReadOnly}],
type: [fieldControl ? fieldControl.type : 'text']
});
}
static uniqueValidator(form: any): ValidatorFn | null {
return (control: AbstractControl): ValidationErrors | null => {
console.log('control..: ', control);
const name = control.value;
if (form.value.fields.filter(v => v.label.toLowerCase() === control.value.toLowerCase()).length > 1) {
return {
notUnique: control.value
};
} else {
return null;
}
};
}
in real life, username or email properties are checked to be unique. This will be very long answer I hope you can follow along. I will show how to check uniqueness of username.
to check the database, you have to create a service to make a request. so this validator will be async validator and it will be written in class. this class will be communicate with the service via the dependency injection technique.
First thing you need to setup HttpClientModule. in app.module.ts
import { HttpClientModule } from '#angular/common/http';
#NgModule({
declarations: [AppComponent],
imports: [BrowserModule, YourOthersModule , HttpClientModule],
providers: [],
bootstrap: [AppComponent],
})
then create a service
ng g service Auth //named it Auth
in this auth.service.ts
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
#Injectable({
providedIn: 'root',
})
export class AuthService {
constructor(private http: HttpClient) {}
userNameAvailable(username: string) {
// avoid type "any". check the response obj and put a clear type
return this.http.post<any>('https://api.angular.com/username', {
username:username,
});
}
}
now create a class ng g class UniqueUsername and in this class:
import { Injectable } from '#angular/core';
import { AsyncValidator, FormControl } from '#angular/forms';
import { map, catchError } from 'rxjs/operators';
import { of } from 'rxjs';
import { AuthService } from './auth.service';
// this class needs to use the dependency injection to reach the http client to make an api request
// we can only access to http client with dependecny injection system
// now we need to decorate this class with Injectable to access to AuthService
#Injectable({
providedIn: 'root',
})
export class UniqueUsername implements AsyncValidator {
constructor(private authService: AuthService) {}
//this will be used by the usernamae FormControl
//we use arrow function cause this function will be called by a
//different context, but we want it to have this class' context
//because this method needs to reach `this.authService`. in other context `this.authService` will be undefined.
// if this validator would be used by the FormGroup, you could use
"FormGroup" type.
//if you are not sure you can use type "control: AbstractControl"
//In this case you use it for a FormControl
validate = (control: FormControl) => {
const { value } = control;
return this.authService.userNameAvailable(value).pipe(
//errors skip the map(). if we return null, means we got 200 response code, our request will indicate that username is available
//catchError will catch the error
map(() => {
return null;
}),
catchError((err) => {
console.log(err);
//you have to console the error to see what the error object is. so u can
// set up your logic based on properties of the error object.
// i set as err.error.username as an example. your api server might return an error object with different properties.
if (err.error.username) {
//catchError has to return a new Observable and "of" is a shortcut
//if err.error.username exists, i will attach `{ nonUniqueUsername: true }` to the formControl's error object.
return of({ nonUniqueUsername: true });
}
return of({ noConnection: true });
})
);
};
}
So far we handled the service and async class validator, now we implement this on the form. I ll have only username field.
import { Component, OnInit } from '#angular/core';
import { FormGroup, FormControl, Validators } from '#angular/forms';
import { UniqueUsername } from '../validators/unique-username';
#Component({
selector: 'app-signup',
templateUrl: './signup.component.html',
styleUrls: ['./signup.component.css'],
})
export class SignupComponent implements OnInit {
authForm = new FormGroup(
{
// async validators are the third arg
username: new FormControl(
'',
[
Validators.required,
Validators.minLength(3),
Validators.maxLength(20),
Validators.pattern(/^[a-z0-9]+$/),
],
// async validators are gonna run after all sync validators
successfully completed running because async operations are
expensive.
this.uniqueUsername.validate
),
},
{ validators: [this.matchPassword.validate] }
);
constructor(
private uniqueUsername: UniqueUsername
) {}
//this is used inside the template file. you will see down below
showErrors() {
const { dirty, touched, errors } = this.control;
return dirty && touched && errors;
}
ngOnInit(): void {}
}
Final step is to show the error to the user: in the form component's template file:
<div class="field">
<input formControl="username" />
<!-- this is where you show the error to the client -->
<!-- showErrors() is a method inside the class -->
<div *ngIf="showErrors()" class="ui pointing red basic label">
<!-- authForm.get('username') you access to the "username" formControl -->
<p *ngIf="authForm.get('username').errors.required">Value is required</p>
<p *ngIf="authForm.get('username').errors.minlength">
Value must be longer
{{ authForm.get('username').errors.minlength.actualLength }} characters
</p>
<p *ngIf="authForm.get('username').errors.maxlength">
Value must be less than {{ authForm.get('username').errors.maxlength.requiredLength }}
</p>
<p *ngIf="authForm.get('username').errors.nonUniqueUsername">Username is taken</p>
<p *ngIf="authForm.get('username').errors.noConnection">Can't tell if username is taken</p>
</div>
</div>
You could create a validator directive that goes on the parent element (an ngModelGroup or the form itself):
import { Directive } from '#angular/core';
import { FormGroup, ValidationErrors, Validator, NG_VALIDATORS } from '#angular/forms';
#Directive({
selector: '[validate-uniqueness]',
providers: [{ provide: NG_VALIDATORS, useExisting: UniquenessValidator, multi: true }]
})
export class UniquenessValidator implements Validator {
validate(formGroup: FormGroup): ValidationErrors | null {
let firstControl = formGroup.controls['first']
let secondControl = formgroup.controls['second']
// If you need to reach outside current group use this syntax:
let thirdControl = (<FormGroup>formGroup.root).controls['third']
// Then validate whatever you want to validate
// To check if they are present and unique:
if ((firstControl && firstControl.value) &&
(secondControl && secondControl.value) &&
(thirdContreol && thirdControl.value) &&
(firstControl.value != secondControl.value) &&
(secondControl.value != thirdControl.value) &&
(thirdControl.value != firstControl.value)) {
return null;
}
return { validateUniqueness: false }
}
}
You can probably simplify that check, but I think you get the point.
I didn't test this code, but I recently did something similar with just 2 fields in this project if you want to take a look:
https://github.com/H3AR7B3A7/EarlyAngularProjects/blob/master/modelForms/src/app/advanced-form/validate-about-or-image.directive.ts
Needless to say, custom validators like this are fairly business specific and hard to make reusable in most cases. Change to the form might need change to the directive. There is other ways to do this, but this does work and it is a fairly simple option.

How to find a specific row from firestorage array values using if & for function

I am fetching an array from FireStorage using typescript. Below is my login.component.ts code . I want to remove the existing code from login:void() function and instead add a code that checks and matches the value of users (usersname and password) from the array "users: User[]" . If the username and password is found then it will proceed otherwise it will go to the else function. The getUsers() function inside ngonInit fetches the users from firestorage
LOGIN.COMPONENT.TS
import { Component, OnInit } from '#angular/core';
import {Router} from '#angular/router';
import {MatDialog} from '#angular/material';
import { UserService } from '../service/user.service';
import { User } from '../models/user';
#Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
users: User[];
constructor(private router: Router, private userService: UserService) { }
username: string;
password: string;
ngOnInit() {
if(localStorage.getItem('logkey')=='1') {
this.router.navigate(["app1"]);
}
this.userService.getUsers().subscribe(users => {
//console.log(users);
this.users = users;
});
}
login() : void {
if(this.username == 'aayush' && this.password == 'demo'){
localStorage.setItem('logkey',"1");
localStorage.setItem('loguser',this.username);
this.router.navigate(["app1"]);
}
else if(this.username == 'admin' && this.password == 'admin'){
localStorage.setItem('logkey',"1");
localStorage.setItem('loguser',this.username);
this.router.navigate(["app1"]);
}
else {
alert("Invalid credentials");
}
}
}
I will not recommend to filter user on ui side(as it clearly a security vulnerability) instead you should filter and fetch records again to check if user exist .Still if you want to do so then You can use Array.find or Array.some method to check if user exist.So your code will be like :-
var userExist=this.users.some(u=> u.username == this.username && u.password==this.password)
if(userExist){
localStorage.setItem('logkey',"1");
localStorage.setItem('loguser',this.username);
this.router.navigate(["app1"]);
}
else {
//your code
here is an example if you want to filter on api side

AngularJS Version 6.* Service method is coming up undefined

So I am simply trying to write a component and service that from one view takes the user input and passes it to an api for validation. The problem is that in my component, it's saying that the service essentially has no method login and is coming up undefined. However I've checked and rechecked following Angular.io's documentation very closely but can't get anything to work.
LoginComponent.ts
import { Component, OnInit } from '#angular/core';
import { UserService } from '../../../services/user.service';
#Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.scss']
})
export class LoginComponent implements OnInit {
constructor(private userService: UserService) {
console.log('userService', userService);
}
ngOnInit() {}
handleSubmit(data) {
// https://api-test.sarahlawrence.edu:82/
this.userService.login(data)
.subscribe(user => console.log('user', user));
}
}
user.service.ts
import { Injectable } from '#angular/core';
import { HttpClient, HttpHeaders } from '#angular/common/http';
import { Observable, of } from 'rxjs/index';
import { catchError, map, tap } from 'rxjs/internal/operators';
const httpOptions = {
headers: new HttpHeaders({ 'Content-Type': 'application/json' })
};
interface CredsInterface {
username: string;
password: string;
};
interface LoggedIn {
token: string;
}
#Injectable({
providedIn: 'root'
})
export class UserService {
private apiUrl = '<apiUrl>';
constructor(
private http: HttpClient
) { }
login (creds: CredsInterface): Observable<any> {
console.log('UserService.login()', creds);
return this.http.post<any>(`${this.apiUrl}/signin`, creds, {})
.pipe(
tap((loggedIn: LoggedIn) => {
console.log(`Login: ${loggedIn}`);
}),
catchError(this.handleError('login()', []))
);
}
/**
* Handle Http operation that failed.
* Let the app continue.
* #param operation - name of the operation that failed
* #param result - optional value to return as the observable result
*/
private handleError<T> (operation = 'operation', result?: T) {
return (error: any): Observable<T> => {
// TODO: send the error to remote logging infrastructure
console.error(error); // log to console instead
// TODO: better job of transforming error for user consumption
console.log(`${operation} failed: ${error.message}`);
// Let the app keep running by returning an empty result.
return of(result as T);
};
}
}
I don't understand why I get this error:
So I logged the service out to see the object and weirdly the method is being placed in the prototype:
I don't get it, am I doing something wrong?
How do you call that handleSubmit method?
The error says that it can't read login property of undefined which means that this.userService is undefined. The fact that login method is inside prototype is okay. Remember that gets are deep and sets are shallow
I think that you call handleSubmit with some tricky way which makes this to refer other object than you think it is.
I've just saw stackblitz. You pass reference to your function using [onHandleSubmit]="handleSubmit" but when it's executed this is not your LoginComponent anymore.
Add this to component constructor
this.handleSubmit = this.handleSubmit.bind(this)
For more details see this post: Angular pass callback function to child component as #Input

Categories