I try to decrement a value in my array, but I can't get it to work.
My array data contains attributes and everytime a method gets clicked, I call that value from a service and increment it in the array object. The getter is equal to amountCounter.
My main problem is that whenever I try to remove an array object, my amountCounter won't also decrement the value which it had before, but the array object gets removed.
I also put two pictures to better clarify my problem, thank you so much for every help.
app.component.html
<h2>Add values of my service into array:</h2>
<p>Array:</p>
<p>Total: {{amountCounter}}</p>
<div *ngFor="let item of data, let i = index;">
<span>ID: {{item.id}}</span>
<span>Title: {{item.title}}</span>
<span (click)="removeElement(i, item.amountCounter)" class="material-icons">
close
</span>
</div>
app.component.ts
export class AppComponent {
clickEventsubscription: Subscription
ngOnInit() {
}
id: number;
title: String;
amountCounter: number;
data: any = [];
constructor(private share: ShareDataService) {
this.clickEventsubscription = this.share.getClickEvent().subscribe(() => {
this.initialize();
})
}
removeElement(id: number, counter: number) {
this.data.splice(id, 1);
this.amountCounter -= counter //In that line I can't get it to work that my attribute decrements
console.log("before" + this.amountCounter);
console.log("after:" + counter);
}
initialize() {
this.id = this.share.getId();
this.title = this.share.getTitle();
this.amountCounter = this.share.getAmountCounter();
const newData = {
id: this.id,
title: this.title,
amountCounter: this.amountCounter
};
this.data.push(newData);
console.log(this.data);
}
}
share-data.service.ts
export class ShareDataService {
private subject = new Subject<any>();
title: String;
id: number;
amountCounter: number;
getId() {
return this.id;
}
getTitle() {
return this.title;
}
getAmountCounter(){
return this.amountCounter;
}
sendClickEvent() {
this.subject.next();
}
getClickEvent(): Observable<any> {
return this.subject.asObservable();
}
}
That is how my array looks before ID 1 is clicked
That is how my array looks after I clicked at "X", but it decrements wrong
Thank you so much!
Not sure if this is the behavior you are after but generally this method will calculate the sum of the array values
getTotalAmount(): number {
return this.data.reduce((acc, item) => acc + item.amount, 0);
}
The main issue I found very difficult to figure out is that you have amountCounter in [share-data.service, dialog.component, app.component]
I suppose you want to add new items using dialog.component with different amount values.
Here you add new item to your 'data' array, the values for single item comes from share service which was updated in your dialog.component
initialize() {
console.log("initialize");
const id = this.share.getId();
const title = this.share.getTitle();
const amount = this.share.getAmount();
const newData = {
id,
title,
amount
};
this.data.push(newData);
}
To summarize the flow:
in dialog.component you update field values in share-data.service clickMe() method
that method will trigger a method in app.component called initialize which will add the new item to the this.data array.
if you click on item (to remove it) splice will do it, and Angular will refresh the Total calling the getTotalAmount method
Working Stackblitz.
Related
I want to push a new key and corresponding value to an already existing object. My object is returned after subscribing to a WEB API endpoint. Within the object returned, I want to add a "QuantityOnHand" key and value. I have attempted the following, however, it is not as I want it.
branchProduct: BranchProduct;
getProductByName() {
const productName = this.addProductForm.get('product')?.value;
const quantity = this.addProductForm.get('quantity')?.value;
this.branchService.getProductByName(productName).subscribe((resp: any) => {
this.branchProduct = resp;
this.branchProduct.QuantityOnHand = quantity;
console.log(this.branchProduct);
})
}
The "branchProduct" interface class is as follows:
export interface BranchProduct {
BranchId: number;
ProductId: number;
ProductTypeName: string;
ProductName: string;
QuantityOnHand: number;
BaselineQuantity: number;
}
After assigning a value to the QuantityOnHand attribute, the object is logged as follows:
Would it be possible to set the QuantityOnHand as an actual additional attribute of the aforementioned object after the object is created? I have tried setting "branchProduct" as an array and pushing the value of the quantity through to it, however, I had no success doing so.
Any help is appreciated.
In the picture it's showing that branchProduct data is in 0 index of array. If branchProduct data always be one record on 0 index then you can fix it like.
getProductByName() {
const productName = this.addProductForm.get('product')?.value;
const quantity = this.addProductForm.get('quantity')?.value;
this.branchService.getProductByName(productName).subscribe((resp: any) => {
this.branchProduct = resp;
this.branchProduct[0].QuantityOnHand = quantity;
console.log(this.branchProduct);
})
}
Other wise you need to a implement a loop to modify the data.
const branchProductArray = []
branchProductObj.map((product, index) => {
let productObject = {... product };
productObject.QuantityOnHand = quantity;
branchProductArray.push(productObject)
})
console.log(branchProductArray). //will be desire result.
this.branchProduct is an array.
this.branchProduct[0].QuantityOnHand = quantity;
should work
Use spread operator
this.branchProduct = {...resp, quantityonHand:quantity}
Getting error 'Cannot read property 'length' of undefined at HelperService.addCommasToArray' when trying to loop through an array that has been passed as a paramter in a helperService class [Typescript]
I'm really not sure why this is not working - I believe it should be straightforward - all I'm trying to do is pass in an array as a parameter and add a ',' to every value in the array (except the last value)
Here is my HelperService Class method:
export class HelperService {
constructor() { }
/*
* Add commas to every value in the array except for the last value
*/
addCommasToArray(array: Array<any>) : Array<any> {
for (let i = 0; array.length; i++){
array[i] += ", ";
}
return array;
}
}
I then call this method within the ngInit of another ts class
this.helperService.addCommasToArray(this.previousClubs);
Here is the ngInit method
public previousClubs: Array<any>;
constructor(private playersService: PlayersService,private
helperService: HelperService, private route: ActivatedRoute) { }
ngOnInit() {
const playerId: string = this.route.snapshot.paramMap.get('id');
this.playersService.getPlayerDetails(playerId).get()
.then(playerDetailsSnapshot=> {
this.currentPlayerDetails = playerDetailsSnapshot.data();
this.currentPlayerDetails.id = playerDetailsSnapshot.id;
});
/*
* Return Previous Clubs
*/
this.playersService.getPreviousClubs(playerId).get().then(
previousClubsSnapshot =>{
this.previousClubs = [];
previousClubsSnapshot.forEach(snap => {
this.previousClubs.push({
id: snap.id,
name: snap.data().name,
});
return false;
});
});
this.helperService.addCommasToArray(this.previousClubs);
}
so here:
this.playersService.getPreviousClubs(playerId).get().then(
previousClubsSnapshot =>{
this.previousClubs = [];
previousClubsSnapshot.forEach(snap => {
this.previousClubs.push({
id: snap.id,
name: snap.data().name,
});
return false;
});
});
// this line executes without awaiting for .then enclosed scope
this.helperService.addCommasToArray(this.previousClubs);
Basically you call addCommasToArray even before your previousClubs var gets array assigned to it and then gets all its items pushed in. To fix since your method is (.then) async you need to call for this method inside the .then execution scope:
ngOnInit() {
const playerId: string = this.route.snapshot.paramMap.get('id');
this.playersService.getPlayerDetails(playerId).get()
.then(playerDetailsSnapshot=> {
this.currentPlayerDetails = playerDetailsSnapshot.data();
this.currentPlayerDetails.id = playerDetailsSnapshot.id;
});
/*
* Return Previous Clubs
*/
this.playersService.getPreviousClubs(playerId).get().then(
previousClubsSnapshot =>{
this.previousClubs = [];
previousClubsSnapshot.forEach(snap => {
this.previousClubs.push({
id: snap.id,
name: snap.data().name,
});
return false;
});
});
this.helperService.addCommasToArray(this.previousClubs);
}
i have angular 7 component which is tied to a model and there is an array inside that model, the array was populated from a service. and it's populated.
the problem is i can't map over the array although it has elements there.
when i console it it shows the array has element. then i tried to console typeOf(array) it always gives object although it is an array !!.
i tried using this soluation but it didn't help either.
any help please?
export class FooModel {
foo : Foo
bars: Bar[];
}
export class SomeComponent implements OnInit {
model: FooModel;
constructor(private service: ProjectService) {
this.model = new FooModel();
this.model.bars = [];
}
ngOnInit() {
this.service.getFoos().subscribe((result: any) => {
// data is populated fine
this.model= <FooModel>result.data;
});
Console.log(this.model); // the model has data at this point
const arr = this.model.bars.map(a=> {
// never comes here
return a;
});
console.log(arr); // nothing is displayed here
// this works why ??
const arr2 = [1,2,3].map(s=> {
return s;
}
console.log(arr2); // it displays [1,2,3]
}
}
As the request is asynchronous, you might need to place the logic within the subscribe,
this.service.getFoos().subscribe((result: any) => {
// data is populated fine
this.model= <FooModel>result.data;
const arr = this.model.bars.map(a=> {
// never comes here
return a;
});
console.log(arr);
});
subscription is asynchronous so while it is still working the next line operation in the execution stack will be performed in this case the map you have after the subscription meanwhile it is still being populated in the background. You can try mapping in another life cycle hook say viewChecked hopefully it works. #cheers
Please look at the comments
export class FooModel {
foo : Foo
bars: Bar[];
}
export class SomeComponent implements OnInit {
model: FooModel;
constructor(private service: ProjectService) {
this.model = new FooModel();
this.model.bars = [];
}
ngOnInit() {
this.service.getFoos().subscribe((result: any) => {
// data is populated fine
this.model= <FooModel>result.data;
});
// the following starts to execute even before the model is populated above.
const arr = this.model.bars.map(a=> {
// never comes here because this.model.bars is empty at here and the length is 0 and nothing inside map executes
return a;
});
console.log(arr); // nothing is displayed here because it has nothing inside
// this works why ?? because you are using on an array which has some items.
const arr2 = [1,2,3].map(s=> {
return s;
}
console.log(arr2); // it displays [1,2,3]
}
}
So as Sajeetharan suggested, you have keep it inside subscribe()
I am attempting to manage an array within an Angular service like so:
import { TodoItem } from '../models/todo-item.model';
#Injectable()
export class TodoService {
//local storage key name
private readonly lsKey = 'pi-todo';
private _todos: Array<TodoItem>;
//Gets the todo items from local storage
public fetchTodos(): Array<TodoItem> {
//Either get the items if they exist, or get an empty array
this.todos = (JSON.parse(localStorage.getItem(this.lsKey)) as Array<TodoItem>) || [];
return this.todos;
}
//Adds the todo item to local storage
public addTodo(todo: TodoItem): Array<TodoItem> {
if (todo) {
//Better way to do this?
let tempTodos = this.todos;
tempTodos.push(
Object.assign(
{
completed: false
},
todo
)
);
this.todos = tempTodos;
return this.todos;
}
}
private get todos(): Array<TodoItem> {
return this._todos || [];
}
private set todos(todos: Array<TodoItem>) {
this._todos = todos;
localStorage.setItem(this.lsKey, JSON.stringify(this._todos));
}
}
When adding a todo item to the todos array, I tried doing this.todos.push(...); but then that doesn't trigger the setter. How can I do this without using a temp array?
I'd suggest moving the "save to local storage" code to a separate method called by both the setter and the add.
//Adds the todo item to local storage
public addTodo(todo: TodoItem): Array<TodoItem> {
if (todo) {
this.todos.push(
Object.assign(
{
completed: false
},
todo
)
);
this.save();
return this.todos;
}
}
private set todos(todos: Array<TodoItem>) {
this._todos = todos;
this.save();
}
private save() {
localStorage.setItem(this.lsKey, JSON.stringify(this._todos));
}
Yes, because you aren't setting it a new value. A work around would be this: instead of pushing into the array, grab the current array, assign it to a temp variable, then replace with new array. Like so:
triggerSet(newValue) {
const tempArray = this.todos;
tempArray.push(newValue);
this.todos = tempArray;
}
I have an array (checkeduserslist) which contains pairs of userid and username values. It is displayed as the image below
My requirement is that when i unselect a check box , those value is to be stored in another array, say "unselectedUsersList"
Below is a dummy funnction that im trying to implement.
unselectExistingUser(usr: any, event: any) {
if (event.target.checked == false) {
this.unselectedUsersList.push(usr);
}
else if (event.target.checked) {
var indx = this.unselectedUsersList.findIndex(usr);
this.unselectedUsersList.splice(indx, 1);
}
console.log('unselected users :', this.unselectedUsersList);
}
The argument usr contains the userid/password values that is to be inserted or deleted. Insertion is taking place in this, but no idea how to spice the value of when checked.
Thanks in advance.
I would take a different path. Instead of using two arrays I would use one single array and a flag isSelected:
interface User {
id: number;
}
interface SelectableUser extends User {
isSelected: boolean;
}
class Something {
users: SelectableUser[];
unselectExistingUser(usr: SelectableUser, event: any) {
this.users.map((currentUser) => {
if (usr.id === currentUser.id) {
currentUser.isSelected = event.target.checked;
}
return currentUser;
});;
}
}