Using service.ts variables on multiple components - html

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!

Related

Type error Cannot find properties of undefined (reading id)

I'm at a lost here. I have a couple of services, one has been working for month and the newer one for some weeks, then all of a sudden a couple of days ago I start to get two console errors "Cannot read properties of undefined(reading id). I have not changed anything.
If I can fix one then I can understand the other because they both have the same error. When I did my research it talks about initializing.
This is an e-commerce site, when the user clicks on the heart it gets added to wishlistitems in my json file. The user should have the ability to go to favorites and it shows all of the wishlist items. As I stated it was working now I get errors. I have a two models(class) I have two components wishlist-list and wishlistitems the html will display the url for the images and I have a serive.
Here is the wish Model
import { Product } from './product';
export class Wish {
id:number;
productId: number;
productName: string;
description: string;
qty:number;
price: number;
imageUrl: string;
constructor(id:number, product:Product, qty=1, ){
this.id = id;
this.productId = product.id;
this.price = product.price;
this.productName = product.name;
this.qty = qty;
this.imageUrl = product.imageUrl;
this.description = product.description;
}
}
Here is the Product Model
export class Product {
id:number;
name: string;
description: string;
price: number;
imageUrl: string;
constructor(id:number, name, description="", price=0, imageUrl="" ){
this.id=id
this.name = name
this.description = description
this.price= price
this.imageUrl = imageUrl
}
}
Here is my Wishlist component
import { Component, OnInit, Input } from '#angular/core';
import {ProductService} from 'src/app/services/product.service'
import { MessengerService } from 'src/app/services/messenger.service';
import { WishlistService } from 'src/app/services/wishlist.service';
import { WishlistItemService } from '#app/services/wishlist-item.service';
import { Wish} from 'src/app/models/wish';
import {Product} from 'src/app/models/product';
#Component({
selector: 'app-wishlist-list',
templateUrl: './wishlist-list.component.html',
styleUrls: ['./wishlist-list.component.scss']
})
export class WishlistListComponent implements OnInit {
#Input() product: any;
productList: Product[]= [];
wishitemList: Wish[]= [];
wishItems = [];
constructor( private msg: MessengerService, private productService: ProductService,
private wishlistService: WishlistService,
private _wishlistitemService: WishlistItemService ) { }
ngOnInit(): void {
this.loadwishlistList()
}
loadwishlistList(){
alert("Loading wish list item");
this._wishlistitemService.getWishlistitem().subscribe((items: Wish[]) => {
console.log("A wish List Item" + items);
this.wishItems=items;
})
}
}
Here is my service
#Injectable({
providedIn: 'root'
})
export class WishlistItemService {
product:any;
id:number;
wishlistitemUrl = 'http://localhost:3000/wishlistitem'; //I have this in a api file
constructor(private http: HttpClient) { }
getWishlistitem(): Observable<Wish[]>{
return this.http.get<Wish[]>(wishlistitemUrl).pipe(
map((result: any[]) => {
let wishItems: Wish[] =[];
for(let item of result) {
let productExists = false
for(let i in wishItems){
if(wishItems[i].productId === item.product.id){ //this is line I get error on
wishItems[i].qty++
productExists = true
break;
}
}
if (!productExists){
wishItems.push(new Wish(item.id,item.product, item.name));
}
}
return wishItems;
})
);
}
}
I am at a lost here for it to work then stop working. I'm pulling my hair out, I tried making adjustments but nothing work. I read something about initializing, I'm in need of help.
Thanking You Advance
PH

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 = [];
}
}

ABP: How to get the current user id?

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);
}

Object inside function not getting executed when calling function from another component

Apologies for not being able to title my question properly.
Let me explain my issue properly.
I have 2 Components say A and B.
In B I have a function saveIndCustData which emits and saves data.
export class CustomerformComponent implements OnInit {
#Output()
savedIndCustomer: EventEmitter<any> = new EventEmitter<any>();
saveIndCustData() {
const savedIndCustomer = {
prefix: this.prefix,
nameType: this.indCustNameType,
firstName: this.firstName,
middleNAme: this.middleName,
lastName: this.lastName,
gender: this.gender,
dateOfBirth: this.parseDate(this.dateOfBirth.toString()),
citizenship: this.citizenship
};
this.savedIndCustomer.emit(savedIndCustomer);
this.snackbar.open('Customer Info Saved,Click on Next', 'Close', {
duration: 5000
});
}
}
I am now calling the function from component A.
import { CustomerformComponent } from './forms/customerform/customerform.component';
constructor(private custComp: CustomerformComponent) {}
saveCustomerForm(): void {
this.custComp.saveIndCustData();
}
I emit the data into a service class
#Output()
savedIndCustomer: EventEmitter<any> = new EventEmitter<any>();
Service Class
public addDynamiIndCustomerComponent() {
const factory = this.factoryResolver.resolveComponentFactory(CustomerformComponent);
const component = factory.create(this.rootViewContainer.parentInjector);
component.instance.savedIndCustomer.subscribe(data => {
console.log(data);
// Insert Individual Customer Type
this.custFullDetails.customerType = 'individual';
this.custFullDetails.individualCustomer.dateOfBirth = data.dateOfBirth;
this.custFullDetails.individualCustomer.citizenship = data.citizenship;
this.custFullDetails.individualCustomer.gender = data.gender;
this.custFullDetails.individualCustomer.individualName.push({
prefix: data.prefix,
firstName: data.firstName,
middleName: data.middleName,
lastName: data.lastName,
agreementId: data.agreementId,
nameType: data.nameType
});
console.log(this.custFullDetails.individualCustomer);
});
this.rootViewContainer.insert(component.hostView);
}
My issue is if I invoke the saveIndCustData function from component B it pushes data into array const savedIndCustomer{ ... } and calls the service class.
However when I invoke the same function from component A it doesn't invoke the const savedIndCustomer{ ... } method inside saveIndCustData() function and service class method does not save data in array but it simply shows the snakbar.
What is the issue?
Suppose you put the component B inside the html of component A, so you should make a reference for the component B like this
A.component.html:
...
<B #bcmp></B>
...
and inject it in A.component.ts using #ViewChild like this
A.component.ts:
#Component({
selector: 'A',
templateUrl: './A.component.html',
styleUrls: ['./A.component.scss']
})
export class AComponent implements OnInit {
#ViewChild("bcmp") bcmp : B
ngOnInit(): void {
// by this way you can use any method existant in B component
this.bcmp.saveIndCustData();
}
}

Storing Objects inside Object in Arrays in Angular 2

I'm trying to store this data, given from a Wordpress Backend with HTTP Get Request in Ionic 2 (Angular 2).
I'm receiving this data structure,
Console Log of data response-
I'm trying to store this data like the menus (menu_1 and menu_2) in array of menus, the categories in array of categories, dishes in array of dishes...
How can I do that?
I don't want to show or iterate using Pipes, I only want to storage in Arrays to work easier with them.
My code at the moment is like:
home.ts:
I have a injectable class (Globals) to call the http get, but I do the subscribe in the getMenus function on my home.ts component:
import { Component } from '#angular/core';
import { NavController } from 'ionic-angular';
import { Globals } from '../../providers/globals';
#Component({
selector: 'page-home',
providers: [Globals],
templateUrl: 'home.html'
})
export class HomePage {
menus: any;
constructor(public navCtrl: NavController, public globals: Globals) {
this.getMenus();
}
getMenus() {
this.globals.getMenus().subscribe(
data => {
console.log(data);
this.menus = data;
},
err => { console.log(err) }
);
}
}
And I have created a class, called Menu, at the moment is very simple:
import { Injectable } from '#angular/core';
import 'rxjs/add/operator/map';
#Injectable()
export class Menu {
name: any;
categories: any;
constructor() {
this.name = this.name;
this.categories = this.categories;
}
}
Where name is basic field of the object (key: name, value: "Today's menu" and categories is cat_1, cat_2 (two objects inside menu_1 object, which each contains more objects (dish_1, dish_2...).
My idea is create a class for every one of them, class Menu, class Category and class Dish. But I have any idea of how can I start store this objects in this classes. :S
Greetings!
The first thing to do is to create an interface for the data that you receive from the server, something like:
interface Dish {
Name: string;
Description: string;
Thumbnail: string;
}
interface Category {
[name: string]: Dish;
}
type ServerResponse = {
[name: string]: { [name: string]: Category; } & { name: string };
}
If you want to create classes from this data you can then:
class Menu {
name: string;
categories: { [name: string]: Category };
constructor(data: { [name: string]: Category; } & { name: string }) {
this.name = data.name;
this.categories = {};
Object.keys(data).forEach(name => {
if (name !== "name") {
this.categories[name] = new Category(data[name]);
}
});
}
}
(data: ServerResponse) => {
this.menus = {};
Object.keys(data).forEach(name => {
this.menus[name] = new Menu(data[name]);
});
}
You should also create the Category class and all, but that's the idea.
What are you trying to do ?
I think what you're trying to do is to normalize your data.
(Are you using a Redux pattern ? Maybe Ngrx ? If so, this is a great idea to normalize !)
Here's how a normalized state looks like : http://redux.js.org/docs/recipes/reducers/NormalizingStateShape.html
How should you do it ?
You can either do it by hand, which will become quite hard if you have many other requests to deal with, or you can describe your data in schema and use normalizr to do this job (normalizing data) for you.
If you don't know where to start. You can try this approach. First, create a model:
export class DummyModel {
menu: any;
cat: any;
dish: any;
...
//you can replace any with the type expected (string, number, etc)
}
In your component, you import your dummyModel and you set the data
import { DummyModel } from '../dummy.model';
/...
dummyModel: DummyModel = dummyData;
Also, consider #Nitzan Tomer advise, try to write your code and people here can help if you are facing an issue