ABP: How to get the current user id? - html

I managed to display of the current user email, but how do I get the user id?
Template:
<div *ngIf="!hasLoggedIn">
{{ (profile$ | async)?.email }}
</div>
TypeScript:
import { Profile, GetProfile, ProfileState, } from '#abp/ng.core';
export class Component implements OnInit {
#Select(ProfileState.getProfile) //State
profile$: Observable<Profile.Response>; //Model
get hasLoggedIn(): boolean {
return this.oAuthService.hasValidAccessToken();
}
constructor(private oAuthService: OAuthService) {}
ngOnInit() {
this.store.dispatch(new GetProfile()).subscribe(); //Action
}
}
Inside app-routing.module.ts there is import ofApplicationLayoutComponent and inside there is a declaration of the variable currentUser $: Observable <ApplicationConfiguration.CurrentUser>; which is being used to display the user name in the navbar, and inside the ApplicationConfiguration models there is an Id, but I couldn't implement it as I did with email
Ps: Sorry for my English 😂

you can use GetCurrentLoginInformations() which resides in SessionServiceProxy.
It returns an object which contains UserLoginInfoDto which contains email, name etc

public async Task LinkToUser(LinkToUserInput input)
{
var loginResult = await _logInManager.LoginAsync(input.UsernameOrEmailAddress, input.Password, input.TenancyName);
if (loginResult.Result != AbpLoginResultType.Success)
{
throw _abpLoginResultTypeHelper.CreateExceptionForFailedLoginAttempt(loginResult.Result, input.UsernameOrEmailAddress, input.TenancyName);
}
if (AbpSession.IsUser(loginResult.User))
{
throw new UserFriendlyException(L("YouCannotLinkToSameAccount"));
}
if (loginResult.User.ShouldChangePasswordOnNextLogin)
{
throw new UserFriendlyException(L("ChangePasswordBeforeLinkToAnAccount"));
}
await _userLinkManager.Link(GetCurrentUser(), loginResult.User);
}

Related

change url of HttpClient in angular when the language is changed

im trying to make a portfolio where when if someone wants changes the language in the menu the components change what json load for getting all data. I try to use BehaviourSubject and subject but i cant understand them so it difficult to use them. sorry for any mistake in english im learning
this is my service
export class PortfolioService {
language: string = 'espaniol';
constructor(private http: HttpClient) {}
obtenerDatos(): Observable<any> {
if (this.language === 'espaniol') {
return this.http.get('./assets/i18n/espaniol.json');
} else {
return this.http.get('./assets/i18n/english.json');
}
}
changeLang(value: string) {
this.language = value;
}
}
this is my header
export class HeaderComponent {
#Input() currentSection = 'section1';
siteLanguage = 'english';
languageList = [
{ code: 'english', label: 'English' },
{ code: 'espaniol', label: 'Español' },
];
constructor(private portfolioService: PortfolioService) {}
changeLang(localeCode: string) {
this.portfolioService.changeLang(localeCode);
}
scrollTo(section: string) {
document.querySelector('#' + section)!.scrollIntoView();
}
}
my template
<ng-container *ngFor="let language of languageList">
<li role="menuitem">
<a class="dropdown-item" (click)="changeLang(language.code)">
{{ language.label }}
</a>
</li>
</ng-container>
and my component that load the data
export class HomeComponent {
constructor(private datosPortfolio: PortfolioService) {}
miPortfolio: any;
ngOnInit(): void {
this.datosPortfolio.obtenerDatos().subscribe((data) => {
this.miPortfolio = data;
});
}
}
i tried to make a portfolio where i could change the language with a service that picked up when a changed happened in the header. the changed get picked up but the language is not changed in other components.
you need to wrap your data source observable with observable that changes when language changes. for that, the best is to use the BehaviorSubject.
take a look at this:
export class PortfolioService {
language = new BehaviorSubject<string>('espaniol');
constructor(private http: HttpClient) {}
obtenerDatos(): Observable<any> {
return this.language.asObservable().pipe(
switchMap(lang => this.http.get(`./assets/i18n/${lang}.json`))
)
}
changeLang(value: string) {
// update the value of this BehaviorSubject, and all
// subscribers notify about it
this.language.next(value);
}
}
this way every time language changed, new source emit in this.language BehaviorSubject and subscribe function fires again because of the new value, and them switch to other observable that makes the HTTP request with the language as a parameter that goes into the URL of the request.
hope it helps :)

Angular updating values across views

I have an Angular app that has the following:
One component has a text input and a button. The user fills in the text input and clicks the button. This updates a the URL for a router link.
The router link loads a component called view and it in turn reads the URL parameter from the router link and places that value in a service and displays it on the component so I know it worked.
So if the user type 'abc' in the text input then the router link URL would be /view/abc. So 'abc' will be displayed in the view component. Sometimes users will paste a router link like /view/def. This works to update the view component.
The part I can't get to work is to update the text input box in the other component to reflect the current value of the pasted link.
I tried using 'AfterViewChecked' to read the value from the service but that executes before the service value is updated so it is always incorrect.
These cannot bind to the same variable because this will eventually turn into a web service call and I don't want the service to be updated while the user is typing into the text input box, only when they click the button.
I'm not sure where else to look. Any searching I do just brings up data binding, but that is not my problem.
The relevant files are below but the full test sample code is on StackBlitz at https://stackblitz.com/edit/github-jwr6wj.
If you change the URL in the text input and click the button the URL display below will update. But if you paste in the pseudo URL https://github-jwr6wj.stackblitz.io/view/http%253A%252F%252Fwww.ebay.com%252F the URL displayed below will update correctly but I can't figure out how to update the text input to reflect what came in with the URL.
update.service.ts contains the URL that is the current one. This service will also load the data from a web service.
import { Injectable } from '#angular/core';
#Injectable({
providedIn: 'root'
})
export class UpdateService {
url: string = "http://www.google.com/";
constructor() { }
}
view.component.ts is where the data selected by the user will be displayed. It parses the URL parameter for the data and updates the service with it.
import { ActivatedRoute, ParamMap } from '#angular/router';
import { UpdateService } from '../update.service';
#Component({
selector: 'app-view',
templateUrl: './view.component.html',
styleUrls: ['./view.component.css']
})
export class ViewComponent implements OnInit {
constructor(public activatedRoute:ActivatedRoute, public updateService: UpdateService) { }
ngOnInit(): void {
this.activatedRoute.paramMap.subscribe((paramMap: ParamMap) =>{
this.getUrl(paramMap);
});
}
getUrl(paramMap: ParamMap): void {
const incomingUrl = paramMap.get("url");
if (incomingUrl == null) {
this.updateService.url = "http://www.google.com/";
} else {
this.updateService.url = decodeURIComponent(incomingUrl);
}
}
}
view.component.html
<p>URL: {{updateService.url}}</p>
toolbar.component.ts is where the user will enter they request. sourceUrl is the variable that will be updated when the user types. However I also want it to update when the page is visited via the browser URL with the correct data as part of that URL. I can send data to the view component via the router but I can't find out how to send data back to the toolbar component.
import { UpdateService } from '../update.service';
#Component({
selector: 'app-toolbar',
templateUrl: './toolbar.component.html',
styleUrls: ['./toolbar.component.css'],
})
export class ToolbarComponent implements OnInit {
sourceUrl: string = '';
constructor(private updateService: UpdateService) {}
ngOnInit(): void {
this.sourceUrl = this.updateService.url;
}
getViewUrl(): string {
return '/view/' + encodeURIComponent(this.sourceUrl);
}
}
toolbar.component.html
<div class="col-sm-12">
<input type="text" [(ngModel)]="sourceUrl" />
<a class="btn btn-primary" [routerLink]="getViewUrl()">
<span class="fa fa-eye"></span>
</a>
</div>
One way to share data between components is using a Service and Observables. Change your url in the Service to be BehaviorSubject with an initial value.
The way BehaviorSubject works is that you emit values from components to update the Observable in the Service. The BehaviorSubject behaves both as an Observer and Observable.
Essentially, an Observer is an object that listens to events, in this case, updating the URL. An Observable is an object that components listen to for updates or changes. In this case, the View Component listens to the BehaviorSubject for this update to the URL.
Service
export class UpdateService {
private url$ = new BehaviorSubject<string>('www.google.com');
public readonly url: Observable<string> = this.url$.asObservable();
constructor() {}
}
Toolbar Component
export class ToolbarComponent implements OnInit {
sourceUrl: string = '';
constructor(private updateService: UpdateService) {}
ngOnInit(): void {
this.updateService.url.subscribe((str) => {
this.sourceUrl = str;
});
}
getViewUrl(): string {
return '/view/' + encodeURIComponent(this.sourceUrl);
}
}
View Component
export class ViewComponent implements OnInit {
constructor(
public activatedRoute: ActivatedRoute,
public updateService: UpdateService
) {}
ngOnInit(): void {
this.activatedRoute.paramMap.subscribe((paramMap: ParamMap) => {
this.getUrl(paramMap);
});
}
getUrl(paramMap: ParamMap): void {
const incomingUrl = paramMap.get('url');
if (incomingUrl == null) {
this.updateService.url.next('http://www.google.com/');
} else {
this.updateService.url.next(decodeURIComponent(incomingUrl));
}
}
}
View Component HTML
<p>URL: {{ updateService.url | async }}</p>
You are right to try with AfterViewChecked because it's just a timing issue. What you could do is have url inside updateService defined as a BehaviourSubject, so that at the moment it's updated in your view component, you see the change in the toolbar component.
Inside the service :
public url$: BehaviorSubject<string> = new BehaviorSubject("http://www.google.com/");
Inside the view component ts :
getUrl(paramMap: ParamMap): void {
const incomingUrl = paramMap.get("url");
if (incomingUrl == null) {
this.updateService.url$.next("http://www.google.com/");
} else {
this.updateService.url$.next(decodeURIComponent(incomingUrl));
}
}
And inside the view component HTML : (you can also subscribe to the Behaviour Subject directly inside the ts)
<p>URL: {{updateService.url$ | async}}</p>
And you will also have to deal with the fact that the url is a Subject inside the toolbar component ts!
Good luck, let me know if this is not clear!

How do I bold a String that I'm passing in through a message service?

My service looks as follows:
import { Injectable } from '#angular/core';
#Injectable({
providedIn: 'root',
})
export class MessageService {
messages: string[] = [];
add(message: string) {
this.messages.push(message);
}
clear() {
this.messages = [];
}
}
The HTML for the associated component looks like this:
<div>
<h4>Status Messages:</h4>
<div *ngFor='let message of messageService.messages'> {{message}} </div>
</div>
I normally call it in other components like this:
this.messageService.add('Completed all current actions.')
Say I wanted to just bold the word "Completed". Any ideas on how to do that?
You just need to changed your data model.
You can define Message, which represents single sentence with array of words, which need to be highlighted.
export interface Message {
text: string;
wordsToHighlight: string[];
}
Then during iteration over the messages array, create html string and use HTML element's innerHTML or outerHTML property to render it.
Pay attention on getHighlightedText method below.
Your component may look like this:
#Component({
selector: 'app-demo',
template: `
<div *ngFor="let message of messages" [outerHTML]="getHighlightedText(message)"></div>
`
})
export class DemoComponent implements OnInit {
messages: Message[];
constructor(private readonly messageService: MessageService) {}
ngOnInit(): void {
this.messages = this.messageService.messages;
this.messageService.add({ text: 'Completed all current actions', wordsToHighlight: ['all', 'actions'] })
}
getHighlightedText(message: Message): string {
const words = message.text.split(' ');
return words.map((word) => {
const highlight = message.wordsToHighlight.some((wordToHighlight) => word.toLowerCase() === wordToHighlight.toLowerCase());
if (highlight) {
return `<b>${word}</b>`;
} else {
return word;
}
}).join(' ');
}
}
Message service:
#Injectable({
providedIn: 'root',
})
export class MessageService {
messages: Message[] = [];
add(message: Message) {
this.messages.push(message);
}
clear() {
this.messages = [];
}
}

Using service.ts variables on multiple components

I've set up next.service.ts with 3 variables (user, action, rest) and made setters(updateNext()) and getters (getUser, getAction, getRest). I've got to use the setter to change the variables in one component (stock-management component) and retrieved these variables in another component (inventory-record component) but I can't seem to retrieve them from another component (inventory-record-filled component).
I've tried returning a string ("TEST") in the getter and it worked, but when I tried returning a variable, it just returned nothing/empty string.
export class NextService {
private action: string;
private user: string;
private restraunt: string;
constructor() { }
updateNext(actions, users, restraunts) {
this.action = actions;
this.user = users;
this.restraunt = restraunts;
}
getAction(): string {
return this.action;
}
getUser(): string {
return this.user;
}
getRest(): string {
return this.restraunt;
}
export class InventoryRecordComponent implements OnInit {
name = '';
rest = '';
action = '';
constructor(private next: NextService) {
this.name = this.next.getUser();
this.action = this.next.getAction();
this.rest = this.next.getRest();
}
ngOnInit() {
document.getElementById('dne').style.display = 'none';
}
onSubmit(f: NgForm) {
const x = document.getElementById('dne');
if (!this.next.updateCode(this.code)) {
x.style.display = 'block';
f.resetForm();
} else {
this.next.updateCode(this.code);
location.replace('inventory-record/qty');
}
}
}
export class InventoryRecordFilledComponent implements OnInit {
name: string;
action: string;
rest: string;
constructor(private next: NextService) {
this.name = this.next.getUser();
this.action = this.next.getAction();
this.rest = this.next.getRest();
}
ngOnInit() {
}
}
Each component have its respective html files with {{ name }} {{ action }} {{ rest }}
If you need your component to behave as a Simpleton (where it contains the same values regardless of where in the application it is used) you must set its providedIn value to "root", like so:
import { Injectable } from '#angular/core';
#Injectable({
providedIn: 'root',
})
export class NextService {
// The rest of the code stays the same
}
The description for that can be found here: https://angular.io/guide/singleton-services#providing-a-singleton-service
If you don't do that, each component that imports NextService will have it's own instance of NextService, with its own isolated values. If you want the values of a service to be available everywhere that the service is used in, then you want the service to be a Simpleton, so you must follow the steps.
Following the steps above is not the only way to make your component a Simpleton, but as the link mentions, it is the preferred way to do that.
Hope that helps!

Angular 2 edit cart total after remove a product

i'm stucked on a problem and i don't know how to get out of it.
I have two component sibiling:
One that show a list of products with a button for each product that delete from the cart the single product with a POST call at one REST API.
And another component that simple call a REST API for get the totals of the cart and show it.
The problem is that when i delete correctly the item from the cart, obviously the cart total doesn't update itself.
So, i've searched on the communities and i think that there are two different solutions:
Use a shared service;
Use #Input and #Output
I've tried using the first option, but without success, i tried also with #input and #Output but i don't think that i really understand how to use it between two components that aren't Parent > Child or opposite.
What i need is to call the function GetTotals inside the CARTTOTAL.COMPONENT from the CARTITEMS.COMPONENT for updating the prices.
I've tried to inject the same service in both components and call the function from the first one, but seems doesn't work.
Here the code:
cartitems.component.ts
import { Component, OnInit, Inject, Output } from '#angular/core';
import { ManageGuestCartService } from '../manageCartServices/addtoguestcart.service';
//import { CarttotalComponent } from '../carttotal/carttotal.component';
// Service for guest total cart
import { TotalguestcartService } from '../manageCartServices/totalguestcart.service';
#Component({
selector: 'app-cartitems',
templateUrl: './cartitems.component.html',
styleUrls: ['./cartitems.component.css'],
providers: [ManageGuestCartService, TotalguestcartService]
})
export class CartitemsComponent implements OnInit {
itemofcart:any[];
constructor(private _guestcartservice: ManageGuestCartService, private _totalguestcart: TotalguestcartService) { }
ngOnInit() {
this.listCartItems();
}
listCartItems() {
return this._guestcartservice.getCartDetails()
.subscribe(data => {
this.itemofcart = data;
//console.log(this.itemofcart);
},
(err) => {
//alert('vuoto');
});
}
removeProductFromCart(itemid) {
return this._guestcartservice.deleteProductFromCart(itemid)
.subscribe(data => {
// this.itemofcart = data;
// console.log(this.itemofcart);
this.listCartItems();
this._totalguestcart.getTotals();
},
(err) => {
alert('errore');
});
}
}
carttotals.component.ts
import { Component, OnInit, Input} from '#angular/core';
// Service for guest total cart
import { TotalguestcartService } from '../manageCartServices/totalguestcart.service';
#Component({
selector: 'app-carttotal',
templateUrl: './carttotal.component.html',
styleUrls: ['./carttotal.component.css'],
providers: [TotalguestcartService]
})
export class CarttotalComponent implements OnInit {
constructor(private _totalguestcart: TotalguestcartService) { }
totals:any[];
ngOnInit() {
this.retrieveTotals();
}
retrieveTotals() {
return this._totalguestcart.getTotals()
.subscribe(data => {
this.totals = data;
console.log(this.totals);
},
(err) => {
alert(err);
});
}
}
totalguestcart.service.ts
import { Injectable } from '#angular/core';
import { Http, Headers, RequestOptions} from '#angular/http';
#Injectable()
export class TotalguestcartService {
constructor(public http: Http) { }
public getTotals() {
let cartid;
cartid = localStorage.getItem("guestCartId");
let contentHeaders = new Headers();
contentHeaders.append('Accept', 'application/json');
contentHeaders.append('Content-Type', 'application/json');
return this.http.get(URL, { headers: contentHeaders})
//.map(res => res.json())
.map((res) => {
if(res.status == 404) {
return res.status;
} else {
return res.json();
}
});
}
}
Can someone give me the correct way to find a solution to this issue? all the feeds are accepted :)
Thanks in advance!
As mentioned, you need to mark your providers in the module, so that you share the same service between your components.
Shared Service would be best here. From my understanding you want to fire an event in the carttotals component, when deleting an item in the cartitems component.
Well we can set up Observable which will fire that event. So in your totalguestcart service add this:
private fireEvent = new Subject<boolean>();
event = this.fireEvent.asObservable();
emitEvent(bool: boolean) {
this.fireEvent.next(bool);
}
Here we are just using boolean values, as you do not need to pass any specific values, but only fire an event.
Then when you are performing the deletion, let's notify the other component, which subscribes to this, that the method should be fired.
removeProductFromCart(itemid) {
return this._guestcartservice.deleteProductFromCart(itemid)
.subscribe(data => {
this.itemofcart = data;
this.listCartItems();
this._totalguestcart.emitEvent(true); // add this!!
},
(err) => {
alert('error');
});
}
And in your cart totals, subscribe to this in your constructor, and execute the getTotals method:
constructor(private _totalguestcart: TotalguestcartService) {
_totalguestcart.event.subscribe(res => {
this.retrieveTotals();
})
}
this.retrieveTotals will then be fired each time you are deleting an item. Of course this can be used in other methods as well, like adding and updating (if you need it).
Hope this helps! :)
Throw out the service TotalguestcartService out of the providers of your components and put it into the providers of the app-module: What is happening: each component is getting a local copy of the service, so they cannot exchange information, as there are TWO services injected. Putting it global (app.module) provides it for every component as long as the component doesn't do an own provider.