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);
}
}
}
Related
I have this array...
public incidents: any[] = [
{
id: 1,
name: "Default Case Set",
type: "CASEWORK",
str: 34,
mtdna: 0,
ystr: 0,
xstr: 0,
snps: 0
}
]
I'm passing it into a modal like this...
public openEditModal(id: number): void {
this.incidentToBeEdited = this.incidents.filter(result => result.id == id).pop();
const initialState: ModalOptions = {
initialState: {
items: this.incidentToBeEdited,
title: 'Edit Incident'
}
};
// Close modal
this.bsModalRef = this.modalService.show(EditModalComponent, initialState);
}
The problem is that the keys in the object in the incidents array are automatically alphabetized.
When I console the "this.incidentToBeEdited" variable, I get this...
{
mtdna: 0
name: "Default Case Set"
snps: 0
str: 34
type: "CASEWORK"
xstr: 0
ystr: 0
}
So the object that gets sent to the modal (for display purposes) is automatically alphabetized.
I don't want this because I want the fields to appear as they do in the table, which is how they are in the original incidents array.
Is there anyway I can override Angular's need to alphabetize an object?
Here is the code for EditModalComponent...
export class EditModalComponent implements OnInit {
constructor(
public bsModalRef: BsModalRef,
private http: HttpClient,
private formBuilder: FormBuilder) {
this.items = this.items;
this.bsModalRef = this.bsModalRef;
this.editModal = this.formBuilder.group({});
}
// Page loading properties
public httpRequestInProgress: boolean = false;
public pageLoaded: boolean = false;
public pageLoadError: string = '';
public pageLoading: boolean = true;
// Properties
public editModal: FormGroup;
public items?: any;
public title?: string;
// Methods
ngOnInit(): void {
this.editModal = this.formBuilder.group(
this.items
)
console.log("this.items", this.items);
// Remove id from list of items
const itemsInAnArray = [this.items];
itemsInAnArray.forEach((item: any) => delete item.id);
this.pageLoading = false;
this.pageLoaded = true;
}
}
Here is the HTML for EditModalComponent...
<form [formGroup]="editModal" *ngIf="this.items">
<div class="row">
<div class="col-sm-12">
<div *ngFor="let item of this.items | keyvalue">
<div class="col-sm-12 mb-3">
<label class="text-capitalize" for="firstName">{{item.key}}</label>
<input class="form-control"
id="{{item.key}}"
value="{{item.value}}"
formControlName="{{item.key}}">
</div>
</div>
</div>
<div class="mt-3">
<button class="btn btn-primary float-start"
type="button"
(click)="saveAsync()">
Save
</button>
<button class="btn btn-secondary me-1 float-start"
type="button"
(click)="bsModalRef.hide()">
Cancel
</button>
</div>
</div>
</form>
```
I'm working on building a set of filters, so I'm just trying to make use of the salesChannels array content in my view, which only gets populated when clicking the button with the test() function. The log in ngOnInit outputs an empty array the first time, but works correctly after pressing the button.
The getOrganisationChannels returns an observable.
What causes this behavior and how do I handle it properly? I tried using an eventEmitter to try and trigger the populating but that doesn't work.
TYPESCRIPT
export class SalesChannelFilterComponent implements OnInit {
constructor(
public organizationService: OrganizationService
) { }
#Input() organizationId: any;
salesChannels: Array<any> = [];
selectedChannels: Array<any> = [];
allSelected: Array<any> = [];
ngOnInit() {
this.getChannels();
console.log(this.salesChannels);
}
getChannels() {
this.organizationService.getOrganizationChannels(this.organizationId).subscribe(
salesChannels => {
this.salesChannels = salesChannels;
})
}
test() {
console.log(this.salesChannels);
}
}
HTML
<div>
{{ salesChannels | json }}
</div>
<button (click)="test()">test</button>
<div *ngFor="let channel of salesChannels; let i = index;" class="checkbox c-checkbox">
<label>
<input type="checkbox">
<span class="fa fa-check"></span>{{channel.name}}
</label>
</div>
This is expected behaviour since you are populating the salesChannel in the subscription of an Observable. It's recommended that you use aysnc pipe to let angular check for changes and update the view accordingly.
Component.ts :
export class SalesChannelFilterComponent implements OnInit {
constructor(
public organizationService: OrganizationService
) { }
#Input() organizationId: any;
salesChannels$!: Observable<Array<any>>;
selectedChannels: Array<any> = [];
allSelected: Array<any> = [];
ngOnInit() {
this.getChannels();
console.log(this.salesChannels);
}
getChannels() {
this.salesChannels$ = this.this.organizationService.getOrganizationChannels(this.organizationId);
}
test() {
console.log(this.salesChannels);
}
}
In your template:
<button (click)="test()">test</button>
<div *ngFor="let channel of salesChannels$ | async; let i = index;" class="checkbox c-checkbox">
<label>
<input type="checkbox">
<span class="fa fa-check"></span>{{channel.name}}
</label>
</div>
More details: https://angular.io/api/common/AsyncPipe
I recommend using AsyncPipe here:
<div>{{ salesChannels | async}}</div>
and in .ts:
salesChannels = this.organizationService.getOrganizationChannels(this.organizationId)
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
}
I'm trying to work with localstorage in angular 2. I'm using angular cli.
app.component.ts
export class AppComponent implements OnInit {
currentItem: string;
newTodo: string;
todos: any;
constructor(){
this.currentItem = (localStorage.getItem('currentItem')!==null) ? JSON.parse(localStorage.getItem('currentItem')) : [ ];
localStorage.setItem('currentItem', JSON.stringify(this.currentItem));
this.newTodo = '';
this.todos = [];
}
addTodo() {
this.todos.push({
newTodo: this.newTodo,
done: false
});
this.newTodo = '';
localStorage.setItem('currentItem', JSON.stringify(this.todos));
}
ngOnInit(): void {}
}
app.component.html
<div>
<form (submit)="addTodo()">
<label>Name:</label>
<input [(ngModel)]="newTodo" class="textfield" name="newTodo">
<button type="submit">Add Todo</button>
</form>
</div>
<ul class="heroes">
<li *ngFor="let todo of todos; let i=index ">
<input type="checkbox" class="checkbox" [(ngModel)]="todo.done" />
<span [ngClass]="{'checked': todo.done}">{{ todo.newTodo }}</span>
<span (click)="deleteTodo(i)" class="delete-icon">x</span>
</li>
</ul>
<div>
<button (click)="deleteSelectedTodos()">Delete Selected</button>
</div>
It's a simple ToDo list, but it doesn't persist the data when I reload page.
In chrome inspect > Application > Local Storage I see the data. when I reload page, the data still appears, but it doesn't appears on view and when I add a new todo item, the Local Storage delete old items and update with a new todo.
Does anyone know how to fix it?
use your code like this
constructor(){
this.currentItem = (localStorage.getItem('currentItem')!==null) ? JSON.parse(localStorage.getItem('currentItem')) : [ ];
this.todos = this.currentItem;
}
addTodo() {
let local_items = localStorage.getItem('currentItem')
local_items.push({
newTodo: this.newTodo,
done: false
});
localStorage.setItem('currentItem', JSON.stringify(local_items));
this.newTodo = '';
}
Reason:
at the time of adding you set array in localStorage which has only latest object not old objects.
on refreshing page you are not assigning localStorage objects to todo variable
I modified a little the code provided for Pardeep Jain, and woked!
export class AppComponent implements OnInit {
currentItem: string;
newTodo: string;
todos: any;
constructor(){
this.currentItem = (localStorage.getItem('currentItem')!==null) ? JSON.parse(localStorage.getItem('currentItem')) : [ ];
this.todos = this.currentItem;
}
addTodo() {
this.todos.push({
newTodo: this.newTodo,
done: false
});
this.newTodo = '';
localStorage.setItem('currentItem', JSON.stringify(this.todos));
}
ngOnInit(): void {}
}
Working on an application and the framework I am using has rows and I would like to iterate over an array of devices and input them into rows, 3 devices per row.
I was pointed in the direction of using a getter function to split the array, I am just not sure how to implmenet this in my component.ts file.
Below is the function I am attempting to implement
get deviceRows() {
let arrRows = [];
let deviceTriple = [];
for (let i = 1; i <= this.devices.length; i++) {
deviceTriple.push(this.devices[i - 1]);
if (i % 3 === 0) {
arrRows.push(triple);
deviceTriple= [];
}
}
return arrRows;
}
And this is the file I would like to implement this.
import { Component } from '#angular/core';
import { DeviceService } from '../../services/device.service';
import { Device } from '../../../Device';
#Component({
moduleId: module.id,
selector: 'devices',
templateUrl: 'devices.component.html'
})
export class DevicesComponent {
devices: Device[];
name: string;
constructor(private deviceService:DeviceService) {
this.deviceService.getDevices()
.subscribe(devices => {
this.devices = devices;
});
}
addDevice(event) {
event.preventDefault();
var newDevice = {
name: this.name,
onStatus: false
}
this.deviceService.addDevice(newDevice)
.subscribe(device => {
this.devices.push(device);
this.name = '';
});
}
deleteDevice(id) {
var devices = this.devices;
this.deviceService.deleteDevice(id)
.subscribe(data => {
if(data.n == 1){
for(var i = 0; i < devices.length; i++) {
if(devices[i]._id == id){
devices.splice(i, 1);
}
}
}
});
}
toggleDevice(device){
var updatedStatus = {
_id: device._id,
name: device.name,
onStatus: !device.onStatus
};
this.deviceService.toggleDevice(updatedStatus)
.subscribe(data => {
device.onStatus = !device.onStatus
updatedStatus = {};
});
}
}
Inside the view I would like to use something like this
<div *ngFor="let DeviceTriple of deviceRows">
<div class="uk-child-width-expand#s uk-text-center" uk-grid>
<div *ngFor="let device of DeviceTriple">
<h2 class="uk-h2">{{ device.name }}</h2>
<button class="uk-button uk-button-default" (click)="toggleDevice(device)" [disabled]="device.onStatus">On</button>
<button class="uk-button uk-button-danger" (click)="toggleDevice(device)" [disabled]="!device.onStatus">Off</button>
</div>
</div>
</div>
Below is how it I currently added devices to the DOM.
<div class="uk-child-width-expand#s uk-text-center uk-grid">
<div *ngFor="let device of devices">
<div class="uk-card uk-card-secondary uk-card-hover uk-card-body uk-transform-origin-bottom-right uk-animation-scale-up">
<h2 class="uk-h2">
<a href="api/device/{{device._id}}">
{{ device.name }}
</a>
</h2>
<button class="uk-button uk-button-default" (click)="toggleDevice(device)" [disabled]="device.onStatus">On</button>
<button class="uk-button uk-button-danger" (click)="toggleDevice(device)" [disabled]="!device.onStatus">Off</button>
</div>
</div>
</div>
I am new to Angular and I am not sure this is the most effient way of doing this, I have seen suggestions about using a custom pipe to do this, but I am lost when looking at examples of implementing this.
Any guidance would be greatly received. If I insert the function anywhere outside of the export class DevicesComponent I get the error 'get is not defined'. If I place it after name: string; I get the error cannot get .length of undefined.