How to manipulate a variable in ngxs? - javascript

Here is how my page is represented.
There are 2 two components:
1st component is the header -> this is the online.component component
2nd component is page -> locking.component
My goal is that when I click the blocking button, the status changes to being blocked.
Here is the example
I want the same result
In summary status 1 = active and status 4 = blocked.
My problem is that when I click blocked, the status doesn't change until I log back in or reselect the account.
It's a real problem, I would like the status to change instantly.
I'm stuck I don't know how to solve this problem. I can share my codes with you:
online.component.html
<span *ngIf="(currentPortfolio$ | async)" class="title">
<span class="t1">
<!-- Account -->
{{ ((currentPortfolio$ | async)?.DEPO | accountDash) }}
<!-- Account active or blocked (texte) -->
<p class="text1">({{ ((currentPortfolio$ | async)?.ACTIF_LABEL) }})</p>
</span>
<span class="t2">
<!-- Status 1 = active, 4 = blocked-->
Status ==> {{ ((currentPortfolio$ | async)?.ACT_PTF) }}
</span>
</span>
profile.state
const defaultValue: ProfileModel = {
currentPortfolio: undefined,
}
#State < ProfileModel > ({
name: 'profile',
defaults: defaultValue
})
#Injectable()
export class ProfileState {
constructor() {}
#Selector()
static currentPortfolio(state: ProfileModel): Portfolio {
return state.currentPortfolio!;
}
#Selector()
static currentPortfolioId(state: ProfileModel): string {
return state.currentPortfolio!.NO_PTF;
}
#Selector()
static hasAccess(state: ProfileModel): boolean {
return true;
}
#Selector()
static customer(state: ProfileModel): ApiCustomer {
return {
REFERENCE: state.currentPortfolio!.NO_PTF,
ID: "",
INTITULE1: "",
INTITULE2: "",
ACCESS: 0,
SERVICE: 0,
DEFAULTPTF: 0
}
}
#Action(ResetProfileStateAction)
resetProfileState(ctx: StateContext < ProfileModel > ): void {
ctx.setState(defaultValue);
}
#Action(SetCurrentPortfolioAction)
setCurrentPortfolio(ctx: StateContext < ProfileModel > , action: SetCurrentPortfolioAction): void {
const state = ctx.getState();
ctx.patchState({
...state,
currentPortfolio: action.portfolio
});
}
}
profile.model.ts
export interface ProfileModel {
currentPortfolio?: Portfolio;
}
profile.actions.ts
export class ResetProfileStateAction {
static readonly type = '[Profile] Reset Profile State';
}
export class SetCurrentPortfolioAction {
static readonly type = '[Profile] Set Current Portfolio';
constructor(public portfolio: Portfolio) { }
}
portfolio.ts
export class Portfolio {
NO_PTF: string; /* REFERENCE */
INT_PTF: string; /* INTITULE */
GES_SERVICE: number; /* SERVICE */
COIN: number; /* COIN */
ACT_PTF: number; /* ACTIF */
COD_SRV: number; /* SURV */
COD_TIT_LIB: string; /* COIN LABEL*/
ACTIF_LABEL: string; /* ACTIF LABEL */
SERVICE_LABEL: string;/* SERVICE LABEL */
DEPO: any; /* DEPO */
constructor() {
this.NO_PTF = ''; /* REFERENCE */
this.INT_PTF = ''; /* INTITULE */
this.GES_SERVICE = 0; /* SERVICE */
this.COIN = 0; /* COIN */
this.ACT_PTF = 0; /* ACTIF */
this.COD_SRV = 0; /* SURV */
this.COD_TIT_LIB = ''; /* COIN LABEL*/
this.ACTIF_LABEL = ''; /* ACTIF_LABEL*/
this.SERVICE_LABEL = ''; /* SERVICE_LABEL*/
this.DEPO = ''; /* DEPO */
}
}
I think the problem is in the locking component... :S
In the locking() method, I retrieve the status value.
Now I click on the blocked button
It's always the value 1...
Normally it should display 4. :(
The code is represented like this:
export class LockingComponent implements OnInit {
private unsubscribe$ = new Subject < void > ();
#Select(ProfileState.currentPortfolio) currentPortfolio$!: Observable < Portfolio > ;
#Select(AuthState.user) user$!: Observable < string > ;
constructor(private service: LockingService, private store: Store, private router: Router, ) {}
ngOnInit(): void {
this.locking();
}
locking(): void {
let tmpStatus = this.store.selectSnapshot(ProfileState.currentPortfolio).ACT_PTF;
this.service.getLocking().pipe(
takeUntil(this.unsubscribe$)
).subscribe(res => {
if (res.RETURNCODE === ApiResponseCodeEnum.Ok) {
console.log("Status => " + tmpStatus);
}
});
}
}

Related

angular virtual scroll doesn't re-render the list when list item added

i have a problem... with angular virtual scroll.
i tried too many solutions. but i can't resolve the problem.
when i added new item to the favoriteList, i pushed the new item to the front of the favoriteList. but there are no changes to the list of the rendered view. how can i change the view when new item added?
my problem:
https://stackblitz.com/edit/angular-cdk-scroll-bug-vifffd?file=src/app/app.component.ts
Angular Input sees the changes when the value changes, but in our case the input is not of primitive type then he will only know the reference of the array.
This is the virtual scroll input:
/** The DataSource to display. */
#Input()
get cdkVirtualForOf(): DataSource<T> | Observable<T[]> | NgIterable<T> | null | undefined {
return this._cdkVirtualForOf;
}
set cdkVirtualForOf(value: DataSource<T> | Observable<T[]> | NgIterable<T> | null | undefined) {
this._cdkVirtualForOf = value;
if (isDataSource(value)) {
this._dataSourceChanges.next(value);
} else {
// If value is an an NgIterable, convert it to an array.
this._dataSourceChanges.next(
new ArrayDataSource<T>(isObservable(value) ? value : Array.from(value || [])),
);
}
}
_cdkVirtualForOf: DataSource<T> | Observable<T[]> | NgIterable<T> | null | undefined;
In your case, it would be best to create a new class and implement DataSource
something like that:
export class CustomDataSource<T extends { id: number }> extends DataSource<T> {
private _dataSource: BehaviorSubject<T[]>;
constructor() {
super();
this._dataSource = new BehaviorSubject<T[]>([]);
}
connect(): Observable<readonly T[]> {
return this._dataSource.asObservable();
}
disconnect(): void {}
add(item: T): void;
add(item: T[]): void;
add(item: T | T[]): void {
const currentValue = this._dataSource.value;
const items = Array.isArray(item) ? item : [item];
const nextValue = currentValue.concat(items);
this._dataSource.next(nextValue);
}
remove(id: T['id']): void {
const currentValue = this._dataSource.value;
const nextValue = currentValue.filter(item => item.id !== id);
this._dataSource.next(nextValue);
}
}
stackblitz implementation

How to remember or keep the current tab when the page is refreshed?

How do we keep the current tab when a page is refreshed? I have a component which is TransactionsDetailsComponent which renders the tabs I want and when the page is refreshed it should keep the current selected tab.
I have put my HTML and TS code below if someone is interested.
Any idea how to made this possible in angular?
#html code
<div headerTabs>
<div style="margin-top: -49px;">
<mat-tab-group animationDuration="0ms" [(selectedIndex)]="transactionTabIndex"
(selectedTabChange)="setTransactionTabIndex($event)">
<mat-tab label="{{tab}}" *ngFor="let tab of tabs">
<ng-template matTabContent>
<div class="mat-tab-shadow-container">
<div class="mat-tab-shadow"></div>
</div>
<div class="tab-content">
<app-transaction-overview *ngIf="tab === 'Overview' && transaction != null" [transaction]="transaction"
(teamAndUsers)="teamAndUsersEvent($event)" #transactionOverView
(saveTransactionEvent)="saveTransactionEvent($event)"></app-transaction-overview>
<app-deals-transaction *ngIf="tab === 'Deals' && transaction != null" [transaction]="transaction">
</app-deals-transaction>
<app-transaction-activity *ngIf="tab === 'Activity' && transaction != null" [transactionId]="transactionId" [isLocked]="transaction.isLocked">
</app-transaction-activity>
<app-document-management-list #DocumentManagementList *ngIf="tab === 'Documents' && transaction != null"
[dto]="transaction" [documentType]="documentType" [isLocked]="transaction.isLocked"></app-document-management-list>
</div>
</ng-template>
</mat-tab>
</mat-tab-group>
</div>
</div>
</app-page-header>
</div>
#tscode
export class TransactionsDetailsComponent implements OnInit {
documentType = EnumDocumentManagementType.TRANSACTION;
selectedIndex = 0;
transactionId: number;
propertyId: string;
#ViewChild('transactionOverView') transactionOverView: any;
isInProgress = false;
isEdit = false;
accountId: number;
accountRole: string;
tabs = ['Overview', 'Documents', 'Deals', 'Activity'];
transaction: any = null;
partialTransaction: any = null;
transactionTabIndex: number = 0;
/*page header component Inputs*/
// pageHeaderTitleData = {
// title: {
// primary: null
// }
// }
pageHeaderTitleData = {
title: {
main: "",
sub: ""
},
status: {
text: 'in progress',
},
otherInfo: []
}
breadCrumbsData = {
paths: [
{
text: "My Transactions",
link: "/transactions"
}
],
currentPage: ''
}
constructor(
private _notificationService: NotificationService,
private formBuilder: FormBuilder,
private _activatedRoute: ActivatedRoute,
private _transactionService: TransactionsService,
ngOnInit(): void {
this._activatedRoute.queryParams
.subscribe(
params => {
if (params.tab) {
this.transactionTabIndex = params.tab;
}
}
)
}
setTransactionTabIndex(e: any) {
this.setIsEdit(false);
this.transactionTabIndex = e.index;
}
}
You can use localStorage for this purpose, it will persist across multiple sessions until the localStorage is cleared.
Change setTransactionTabIndex to store the selection to localStorage
setTransactionTabIndex(e: any) {
this.setIsEdit(false);
this.transactionTabIndex = e.index;
localStorage.setItem('transactionTabIndex', e.index);
}
and then in the ngOnInit, check if you have transactionTabIndex set in localStorage and set it:
ngOnInit(): void {
this._activatedRoute.queryParams
.subscribe(
params => {
if (params.tab) {
this.transactionTabIndex = params.tab;
}
}
);
this.transactionTabIndex = +localStorage.getItem('transactionTabIndex') || 0
}

How can I access certain element's key in local storage?

I have an array of objects like this and when I click the Remove Favorite button I want to delete the certain element from local storage. I'm deleting from the page with the removeLocal() function but it only deletes from the page, not from local storage. I want to delete it both. I'm generating random number when assigning local storage key. Is there way to access this key and delete the item?
html:
<input type="text" [(ngModel)]="profile" (ngModelChange)="detectChange($event)" (keyup)="findProfile()"
placeholder="Enter the username..." class="input">
<div style="background-color: lightslategrey;">
<ng-template [ngIf]="profile !== '' && user">
<img [src]="user.avatar_url" alt="" class="userAvatar">
<p>Username: {{user.login}}</p>
<p>Location: {{user.location}}</p>
<p>E-mail: {{user.email}}</p>
<p>Blog Link: {{user.blog}}</p>
<p>Member Since: {{user.created_at}}</p>
<button [routerLink]="['', user.login.toLowerCase(), user.id ]" class="viewProfileButton" a>View
Profile</button><br>
<button (click)="localStorage()" class="viewProfileButton">Add to Favorite</button>
</ng-template>
</div>
<div *ngIf="closeDiv">
<div style="background-color: rgb(106, 106, 170);" *ngFor="let item of display">
<p>Username: {{item.login}}</p>
<p>Location: {{item.location}}</p>
<p>ID: {{item.id}}</p>
<button (click)="removeLocal(item.id)" class="viewProfileButton">Remove Favorite</button>
</div>
</div>
<button (click)="consoleLog()" class="viewProfileButton">Console Log</button>
<router-outlet></router-outlet>
ts:
#Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.scss'],
})
export class HomeComponent implements OnInit {
user: any;
profile: any;
display: any;
local: any;
randomNumber: any;
randomString: any;
idString: any;
keys: any;
closeDiv: boolean = true;
constructor(private userData: HttpService) {}
ngOnInit() {
this.display = Object.values(localStorage).map((val: any) => JSON.parse(val));
console.log('ngOnInit Works', this.display);
}
findProfile() {
this.userData.updateProfile(this.profile);
this.userData.getUser().subscribe((result) => {
this.user = result;
});
}
localStorage(id: any) {
this.randomNumber = Math.floor(Math.random() * 10000);
this.randomString = this.randomNumber.toString();
localStorage.setItem(this.randomString, JSON.stringify(this.user));
this.display = Object.values(localStorage).map((val: any) => JSON.parse(val));
console.log(this.display);
}
removeLocal(id: any) {
for (let i = 0; i < this.display.length; i++) {
if (this.display[i].id === id) {
this.display.splice(i, 1);
}
}
}
detectChange(ev: any) {
ev.length > 0 ? (this.closeDiv = false) : (this.closeDiv = true);
}
}
Add the call localStorage.removeItem(key) to your removeLocal function. Granted, you need to store your random keys somewhere, otherwise you will have to integrate this solution to parse through them.
removeLocal(id: any, key: string) {
for (let i = 0; i < this.display.length; i++) {
if (this.display[i].id === id) {
this.display.splice(i, 1);
localStorage.removeItem(key); // here
}
}
}
EDIT: After a conversation in the comments, this solution can be simplified to remove a variable from the function header by storing a storageKey variable within display.
removeLocal(id: any) {
for (let i = 0; i < this.display.length; i++) {
if (this.display[i].id === id) {
localStorage.removeItem(this.display[i].storageKey);
this.display.splice(i, 1);
}
}
}

Angular #ngrx/store dispatch method concatenates an object property with itself

The app is written using Ionic. I have a shopping cart where i'm adding products. The product is an object with a note and quantity property. After i use the this.store.dispatch(new PushProductAction({ product })); the note property is concatenated with itself, i.e. i'm adding 3 products to cart with a note 'cold', in the cart this product will have the note property equal to 'coldcoldcold'.
app-state.ts
export class AppState {
categories: Category[];
shopcart: ShopCart;
profile: Profile;
userdata: UserData;
}
product-info.ts
constructor(
private events: Events,
public store: Store<AppState>,
}
pushToCart(product: Product) {
product.quantity = product.quantity ? ++product.quantity : 1;
product.withHalf = this.halfProductStatus;
this.store.dispatch(new PushProductAction({ product }));
}
After the product is added :
goToConfirm(event, desktop = false) {
event.preventDefault();
event.stopPropagation();
jQuery.fancybox.close();
jQuery('.fancybox-close-small').trigger('click');
for (let index = 0; index < this.count; index++) {
this.pushToCart(this.product);
}
this.fixDesign.CreateToast('Product has been added to cart successfuly', 'successToast');
}
actions.ts
export class PushProductAction implements Action {
readonly type = ActionTypes.PUSH_CART;
constructor(public payload: { product: Product; half?: boolean }) {
console.log('PushProductAction');
}
}
P.S. I'm a beginner in angular, if you need more code snippets please let me know.

Change a property of a component from another component and render it in the html in angular 2

I have 3 components 'starter-left-side', 'starter-content', 'camera'. 1 service 'generalParameters'. In the generalParameters, I have 2 properties; 'contentHeader' & contentDescription which has default string values respectively.
Upon initialization of the starter-content, I get these values from the generalParameters and render it in starter-content.html. When I want to go to the camera.component, I just click on the link to the camera.component via the starter-left-side also, I have a method in the starter-left-side that sets the property value of the generalProperties as soon as the link is clicked so it can be used by the starter-content again.
I can successfully change the values in the generalProperties but the problem is, it is not rendered in the starter-component anymore. I do not know on which time of the life cycle hooks should I get the values from the generalProperties again so it can be rendered in the starter-content.html.
generaParameters.service.ts
contentHeader: string;
contentDescription: string;
constructor() {
this.contentHeader = "Dashboard";
this.contentDescription = "This is your dashboard";
}
starter-content.component.html
<h1>
{{pageHeader}}
<small>{{description}}</small>
</h1>
starter-content.component.ts
pageHeader: string;
description: string;
constructor(
private gp: GeneralparametersService
) { }
ngOnInit() {
this.pageHeader = this.gp.contentHeader;
this.description = this.gp.contentDescription;
}
starter-left-side.component.ts
setContent(header, description) {
this.gp.contentHeader = header;
this.gp.contentDescription = description;
}
starter-left-side.component.html
<li class="active"><i class="fa fa-link"></i> <span>Camera</span></li>
Thank you very much for your help.
Since you are communicating using a service you can propagate your changes using an Subject
When you make changes to your subject via the gp.setContent since your other component is observing the changes they will be automatically updated.
I used pluck so that we can only take the properties we need and render them separately.
See my implementation. Hope it helps!!!
starter-left-side.component.html
<li class="active"><i class="fa fa-link"></i> <span>Camera</span></li>
generaParameters.service.ts
import { Subject } from 'rxjs';
private mycontent$ = new Subject();
public content$ = this.mycontent$.asObservable();
setContent(header, description) {
this.content$.next({header, description});
}
starter-content.component.ts
import { pluck } from 'rxjs/operators';
ngOnInit(): void {
this.pageHeader$ = this.gp.content$.pipe(pluck('header'));
this.pageDescription$ = this.gp.content$.pipe(pluck('description'));
}
starter-content.component.html
<h1>
{{pageHeader$ | async }}
<small>{{pageDescription$ | async}}</small>
</h1>
Use a Subject or BehaviorSubject in your Service. Thus, all components get updated when the value changes:
generaParameters.service.ts
import {BehaviorSubject, Observable} from 'rxjs';
contentHeader: BehaviorSubject<string> = new BehaviorSubject('Dashboard');
contentDescription: BehaviorSubject<string> = new BehaviorSubject('This is your dashboard');
constructor() {}
public getContentHeader(): Observable<string> {
return this.contentHeader.asObservable();
}
public setContentHeader(value: string): void {
this.contentHeader.next(value);
}
public getContentDescription(): Observable<string> {
return this.contentDescription.asObservable();
}
public setContentDescription(value: string): void {
this.contentDescription.next(value);
}
starter-content.component.html
<h1>
{{pageHeader}}
<small>{{description}}</small>
</h1>
starter-content.component.ts
pageHeader: string;
description: string;
constructor(
private gp: GeneralparametersService
) { }
ngOnInit() {
this.gp.getContentHeader().subscribe(value => {
this.pageHeader = value;
});
this.gp.getContentDescription().subscribe(value => {
this.contentDescription = value;
});
}
starter-left-side.component.ts
ngOnInit() {
this.gp.getContentHeader().subscribe(value => {
this.pageHeader = value;
});
this.gp.getContentDescription().subscribe(value => {
this.contentDescription = value;
});
}
setContent(header, description) {
this.gp.setContentHeader(header);
this.gp.setContentDescription(description);
}
starter-left-side.component.html
<li class="active"><i class="fa fa-link"></i> <span>Camera</span></li>

Categories

Resources