Access property from component in provider in angular2 - oop

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.

Related

How can I access ngOffline directive in a component instead of html

I'm using this npm library https://www.npmjs.com/package/ng-offline to alert end user when offline.
<div class="alert alert-danger" ngOffline>You're offline. Check your connection!</div>
stackblitz here: https://stackblitz.com/edit/angular-ngoffline-npm?file=src%2Fapp%2Fapp.component.html
Works great - BUT I want to open a modal with this ngOffline directive, so I'm trying to access the directive from my angular 11 component but not sure how to approach this, any help on this would be greatly appreciated.
Is there away for me to open a ngx-bootstrap modal from the html with this directive?
Because the ng-offline module isn't exporting things as you might expect (i.e. you can't inject a standalone NgOfflineDirective for you to use without having it in your html file), you could add a block like this (where you've used #trigger to identify your ngOnline element):
import { AfterContentChecked, Component, ElementRef, OnDestroy, ViewChild } from '#angular/core';
import { BehaviorSubject, Subscription } from 'rxjs';
import { distinctUntilChanged, filter } from 'rxjs/operators';
#Component({ ... })
export class YourClass implements AfterContentChecked, OnDestroy {
offline$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>();
subscription: Subscription;
#ViewChild('trigger') trigger: ElementRef;
constructor() {
this.subscription = this.offline$.pipe(
distinctUntilChanged(),
filter((offline: boolean) => offline),
).subscribe(() => this.showModal());
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
ngAfterContentChecked() {
if (
this.trigger &&
this.trigger.nativeElement
) {
this.offline$.next(this.trigger.nativeElement.style.display === "none");
}
}
showModal() {
console.log('Show your modal here.');
}
}

Add "Remember me" checkbox to the login page

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.

Angular2 ng-book-2 simple sample chapter 1 app , it works fine in the browser , but why do I get this error?

On Mac OS X El Capitan, I follow all the steps from Page 1 to page 18 of this simple app, but at the screen where I run "ng serve" I get this error:
ERROR in [default]
/Users/bob/angular2_hello_world/src/app/user-item/user-item.component.ts:11:8
Property 'name' does not exist on type 'UserItemComponent'.
From Page 1 :
Writing your First Angular 2 Web Application
Simple Reddit Clone
TO
Page 18:
Try it out
"After making these changes reload the page and the page should display Hello Felipe""
The error is that you use a "name" variable inside the component template but it's not defined inside the component. Define and use it like this in your component:
import { Component } from '#angular/core';
#Component({
selector: 'app-user-item-component',
template: `
<h1>{{name}}</h1>
`,
styles: []
})
export class AppComponent {
name: string = "Hello Felipe"
}
I had the same problem, just reading ng-book2-r49, you need to define that name property in class as names: string[]; so it looks like this
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-user-item',
templateUrl: './user-item.component.html',
styleUrls: ['./user-item.component.css']
})
export class UserItemComponent implements OnInit {
name: string;
constructor() {
this.name = 'Felipe'; // set the name
}
ngOnInit() {
}
}

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