Add "Remember me" checkbox to the login page - spartacus-storefront

How to add to the Login Form new field like "Remember me". Which is not supported out-of-the-box?
Now login form provides just "email" and "password" fields, I extended form with new FormControl remember in ngOnInit method, but I can't pass received value to the auth.authorize method, because this method doesn't expect new value.
import { Component, OnInit } from '#angular/core';
import {FormBuilder, FormControl, Validators} from '#angular/forms';
import {ActivatedRoute} from '#angular/router';
import {AuthRedirectService, AuthService, GlobalMessageService, WindowRef} from '#spartacus/core';
import {CheckoutConfigService, LoginFormComponent} from '#spartacus/storefront';
#Component({
selector: 'app-app-login-form',
templateUrl: './app-login-form.component.html',
styleUrls: ['./app-login-form.component.scss']
})
export class AppLoginFormComponent extends LoginFormComponent implements OnInit {
constructor(
auth: AuthService,
globalMessageService: GlobalMessageService,
fb: FormBuilder,
authRedirectService: AuthRedirectService,
winRef: WindowRef,
activatedRoute: ActivatedRoute,
checkoutConfigService: CheckoutConfigService,
) {
super(auth, globalMessageService, fb, authRedirectService, winRef, activatedRoute, checkoutConfigService);
auth.authorize('email.email.com', '123', true);
}
ngOnInit(): void {
super.ngOnInit();
this.loginForm.addControl('remember', new FormControl('', Validators.required));
}
}
Environment:
Spartacus 3.0
Screenshot was given from Spartacus 2, but I'm sure you that is the same contract/problem for Spartacus 3.

Need to override AuthService and add internal variable and then read it.

Related

Set value in service from AuthGuard before service is initiated with Angular2 and Firebase

I'm trying to get the user ID from the currently logged in user to customize the data loaded from my DataService.
My goal is that:
The AuthGuard should be called before the InboxComponent is loaded
This AuthGuard should set the user variable in the AuthService
I should then be able to use the authService.user in the DataService
However, the console.log(this.authService.user) yields undefined although the console.log(authState) in the AuthGuard correctly logs the user information.
Any clues on what could be wrong?
Authentication Service
export class AuthService {
public user: any;
constructor(private af: AngularFire, public auth$: FirebaseAuth) {
console.log("Auth service state:", this.authState);
}
AuthGuard
#Injectable()
export class AuthGuard implements CanActivate {
constructor(private authService: AuthService, private router: Router) {}
canActivate(): Observable<boolean> {
return this.authService.auth$
.take(1)
.map(authState => {
console.log(authState)
this.authService.setUser(authState);
return !!authState })
.do(authenticated => {
if (!authenticated) {
this.router.navigate(['/error']);
}
});
}
}
Dataservice
export class DataService {
private userPath: string;
constructor(private af: AngularFire, private authService: AuthService) {
console.log(this.authService.user);
}
Router
const routes: Routes = [
{ path: 'inbox', component: InboxComponent, canActivate: [AuthGuard] }
App Module
#NgModule({
declarations: [
InboxComponent
],
imports: [
EmailsModule
],
providers: [
AuthService,
AuthGuard
],
bootstrap: [AppComponent]
})
export class AppModule { }
I finally resolved this. I had a call to my DataService in my app.component.ts file to get some data in my navigation. This is loaded outside the router-module and thus called before the AuthService is called. This in turn caused the DataService before the AuthGuard was called.

Access property from component in provider in angular2

So I'm new to OOP and trying out ionic 2 with angular 2 with typescript.
Say I have an input in the home.html file that is coupled to username in home.ts like this:
export class HomePage {
public username: string;
public newusername: string;
...
constructor(public users: UserService) {
...
Now I want a service (userService.ts) to take username from the input or home.ts and modify it and store the result as newusername.
Do I have to make a constructor in the service/provider like in Homepage which instantiates a new object of home though I already made an object of this in home.ts?
I imported HomePage in userServices but I cant access newusername because I didnt make an object of it.
I don't know what exactly you want but take a look at this if its good for you. (I'd use newusername in service itself)
NOTE: its has nothing to do with Ionic2 as I don't know Ionic2.
Working demo: https://plnkr.co/edit/03oXUTZYwRRo8PTfDFlA?p=preview
import { Component } from '#angular/core';
import {service} from './service';
#Component({
selector: 'my-app',
template: `
New User : {{s.newusername}}<br>
<input type="text" [(ngModel)]="username">
<button (click)="click(username)">Add User</button>
`
})
export class AppComponent {
constructor(private s:service){
}
click(username){
this.s.addUserName(username);
console.log(this.s.newusername)
}
}
service.ts
import {Injectable} from '#angular/core';
#Injectable()
export class service{
newusername:string;
addUserName(str){
this.newusername=str;
}
}
You would need to call a service from code in the component, or pass the component to the service.
constructor(public users: UserService) {}
#Input() public username: string;
// called when an input was updated
ngOnChanges() {
this.newusername = this.users.convertUserName(this.username);
}
or
constructor(public users: UserService) {
users.component = this;
}
but this would still need some way to notify the service about changes to the input like in the above example.

Autoinjected API

i am developing an application using Angular2 (actually, ionic framework). Application itself contains a login form that should work via API.
Structure:
form.ts
Contains logic related to login form
import {Component, Injectable} from '#angular/core';
import { Http } from '#angular/http';
import {User} from '../../../base/user';
import {API} from '../../../base/API';
#Component({
templateUrl: 'build/pages/account/loginForm/form.html',
selector: 'login-form',
providers: [Http, API]
})
export class AccountForm {
constructor() {
...
}
submitLogin($event) {
var username = this.username.value;
var password = this.password.value;
this.user = new User(username, password);
this.user.authenticate()
}
}
user.ts
Class that contains some user information (username, password hash)
import { Inject } from '#angular/core';
import { Hash } from "./hash";
import { API } from "./API";
export class User {
public username: string;
public password: string;
public pwdhash: string;
constructor(
username: string,
password: string,
private api: API ///// problem is here
) {
let hash = new Hash();
this.username = username;
this.password = password;
this.pwdhash = hash.hash(username, password);
}
authenticate() {
var promise = this.api.loginUser({username: this.username, pwdhash: this.pwdhash});
console.log(promise);
}
}
API.ts
Class with API request to the backed
import { Http, Response, Headers, RequestOptions } from '#angular/http';
import { Injectable, Inject } from '#angular/core';
import { Hash } from './hash';
#Injectable()
export class API {
private http: Http;
constructor(#Inject(Http) http: Http) {
}
loginUser (user) {
return this.http.post(url, body, options);
}
}
What i want to do is use API class in a User.authenticate() call, but i don't want to pass it as a parameter to the User.constructor(), as this is a bad style.
Another option is to create a User.API member in a constructor, which looks ugly too.
Looks like i need just a function that makes API requests. However, i am not sure this is a good idea for Object-Oriented Programming.
Is there any way to inject API into User class without creating a new API object of this class?
Thanks

LoggedInOutlet angular2 authentication - Router v3.0.0-alpha8 - Where is ComponentInstruction?

I am using code like this to extend RouterOutlet and create app wide authentication and route protection
import {Directive, Attribute, ViewContainerRef, DynamicComponentLoader} from '#angular/core';
import {Router, ComponentInstruction} from '#angular/router';
import {Router} from '#angular/router';
import {RouterOutletMap} from '#angular/router/src/router_outlet_map';
import {RouterOutlet} from '#angular/router/src/directives/router_outlet';
import {Authentication} from '../common/authentication.service';
#Directive({
selector: 'router-outlet'
})
export class LoggedInRouterOutlet extends RouterOutlet {
publicRoutes:any;
isAuthenticated:boolean;
//private router: any;
constructor(public _elementRef: ElementRef, public _loader: DynamicComponentLoader,
public _parentRouter: Router, #Attribute('name') nameAttr: string, public authService:Authentication) {
super(_elementRef, _loader, _parentRouter, nameAttr);
this.isAuthenticated = authService.isLoggedIn();
//this.router = _parentRouter;
/**
* DEFINE PUBLIC ROUTES
*
* The Boolean following each route below denotes whether the route requires authentication to view.
*
* Format: key/value pair
* - key is the /route url "/login", "/signup", etc
* - value is a boolean true/false
* `true` means it's a publicly available route. No authentication required
* `false` means it's a protected route which is hidden until user is authenticated
*
*/
this.publicRoutes = {
'login': true,
'signup': true,
'404': true
};
} // end constructor
routeIsActive(routePath:string) {
return this.router.url == routePath;
}
activate(instruction: ComponentInstruction) {
// let url = instruction.urlPath;
let url = this.router.url;
// If the url doesn't match publicRoutes and they are not authenticated...
if (!this.publicRoutes[url] && !this.isAuthenticated) {
// todo: redirect to Login, may be there a better way?
this.router.navigateByUrl('/login');
}
return super.activate(instruction);
}
}
Problem is that ComponentInstruction does not exist in the new v3.0.0-alpha8 router, and the super method signature has changed. How do I update this to work in the new router? I cannot find any documentation explaining the changes.
ComponentInstruction has been deprecated. In the current RC4 version of Angular2, this class has been listed under reouter-deprecated. With RC5 coming in, this package would be dropped.
RouterOutlet has changed a lot over time and to make your class LoggedInRouterOultet work, you have to use CanActivate interface.
You can do something like this:
Have an injectable service like LoggedInActivator shown here:
import { Injectable } from '#angular/core';
import { Router, CanActivate } from '#angular/router';
import { LogInService } from './login.service';
#Injectable()
export class LoggedInActivator implements CanActivate {
constructor(private loginService: LogInService) {}
canActivate() {
return this.loginService.isLoggedIn();
}
}
Add canActivate and map it to LoggedInActivator on component while defining route:
{ path: 'home', component: HomeComponent, canActivate: [LoggedInActivator] }
I hope this helps!
because in new router, it uses CanActivate

angular 2 testing componnet with directives and got error router loading

everyone. I try to test angular 2 application and got some interesting error when I try to test component with directives (and in those directive-components - router is included). Got error from Karma:
Error loading http://localhost:9876/angular2/router as "angular2/router" from D:built/application/breadcrumbs/breadcrumbs.component.js .
I don`t know what to do with this issue. Can anybody help me please?
There is my header component test (via jasmine and Karma):
import { beforeEach,
beforeEachProviders,
describe,
expect,
it,
inject,
injectAsync} from 'angular2/testing';
import {HeaderComponent} from './header.component';
import {BreadcrumbsComponent} from '../../breadcrumbs/breadcrumbs.component';
describe('HeaderComponent Tests', () => {
//let HeaderComponent: HeaderComponent;
beforeEachProviders(() => [HeaderComponent,
BreadcrumbsComponent,
ROUTER_PROVIDERS]);
it('Should contains title property - "Header"', inject([HeaderComponent],
(headerComponent: HeaderComponent) => {
expect(headerComponent.title).toBe('Header');
}));
});
There is header component that I try to test.
import {Component} from 'angular2/core';
import {HeaderDataInterface} from './header.component.interfaces';
import {BreadcrumbsComponent} from '../../breadcrumbs/breadcrumbs.component';
import {SearchComponent} from '../../../modules/search/search.component';
// module path. Created for avoid copy/paste
const BUILT_MODULE_PATH: string = '/built/application/partials/header/';
#Component({
selector: 'cgm_header',
templateUrl: `${BUILT_MODULE_PATH}header.component.html`,
directives: [BreadcrumbsComponent, SearchComponent],
styleUrls: [`..${BUILT_MODULE_PATH}header.component.css`],
})
export class HeaderComponent {
public title: string = 'Header';
// contains header data
public headerData: HeaderDataInterface = {
'searchPlaceholder': 'Search for Patient Name, MRN or MPID...',
'logOutLabel': 'Log out'
};
}
There is breadcrumb component
import {ROUTER_DIRECTIVES, Router} from 'angular2/router';
const builtModulePath: string = '/built/application/breadcrumbs/';
#Component({
selector: 'sgm_breadcrumbs',
templateUrl: `${builtModulePath}breadcrumbs.component.html`,
styleUrls: [`..${builtModulePath}breadcrumbs.component.css`],
directives: [ROUTER_DIRECTIVES]
})
export class BreadcrumbsComponent implements OnInit {
private staticData = {
'title': 'Breadcrumbs',
'homeName': 'Home',
'dashboardName': 'Dashboard'
}
constructor(private _router: Router, private _injector: Injector) { }
}
ngOnInit() {
this._router.subscribe((value) => {
let instructions = [];
//console.log(this._router);
this._router.recognize(value).then(instruction => {
this.handleRouterRecognize(instruction);
});
update
<script src="https://code.angularjs.org/2.0.0-beta.14/router.dev.js"></script>
is missing in index.html Plunker example
original
Try without templateUrl (use template instead). There were some related issues especially with async tests.
To set up tests use
// Somewhere in the test setup
import {setBaseTestProviders} from 'angular2/testing';
import {
TEST_BROWSER_PLATFORM_PROVIDERS,
TEST_BROWSER_APPLICATION_PROVIDERS
} from 'angular2/platform/testing/browser';
setBaseTestProviders(TEST_BROWSER_PLATFORM_PROVIDERS,
TEST_BROWSER_APPLICATION_PROVIDERS);
See also https://github.com/angular/angular/blob/master/CHANGELOG.md#200-beta2-2016-01-28