0

I am trying to dynamically display the sum of selected column data through SelectionModel on the selected rows below my table. The data displayed should change when I select/deselected the rows.

I thought ngOnInit() would allow me to achieve that, however the sum of selected column data is not changing.

totalWeight = 0;

  ngOnInit(): void{
    this.selection.selected.forEach((element) => {
      this.totalWeight += element.weight;
    });
  }

Here's the DEMO on Stackblitz.

1
  • That's because that code is only executed once in that lifecycle hook. You should use the changed event such that that portion of your code will be executed each time the selection is modified. Commented Oct 20, 2019 at 9:30

4 Answers 4

2

You need to calculate the total each time when the checkedbox value is changed,

 calculate(row?: PeriodicElement)
  {
    this.totalWeight = 0;
    this.selection.selected.forEach((element) => {
      this.totalWeight += element.weight;
    });
  }

STACKBLITZ DEMO

Sign up to request clarification or add additional context in comments.

1 Comment

I'm using {{totalWeight}} in the html file, the changes are being displayed side by side instead of the sum of weight (e.g. if I select rows with weight 2.00 and 5.00, it's showing 2.005.00 instead of 7.00 as the sum). Any idea why is this happening?
1

You should use the changed event of the SelectionModel API which returns a SelectionChange event emitted when the selection is changed, instead of the selected variable of the SelectionModel API.

The SelectionChange interface has the following properties (taken from the source code):

/**
 * Event emitted when the value of a MatSelectionModel has changed.
 * @docs-private
 */
export interface SelectionChange<T> {
  /** Model that dispatched the event. */
  source: SelectionModel<T>;
  /** Options that were added to the model. */
  added: T[];
  /** Options that were removed from the model. */
  removed: T[];
}

You can then add or remove the weight from the totalWeight property as follows:

totalWeight = 0;

ngOnInit(): void{
  this.selection.changed.subscribe(change => {
      console.log('Added items:', change.added);
      console.log('Removed items:', change.removed);
      console.log('Source selection model:', change.source);
      change.added.forEach(element => {
          this.totalWeight += element.weight;
      })
      change.removed.forEach(element => {
          this.totalWeight -= element.weight;
      })
  });
}

Updated demo

2 Comments

I can't open your updated demo and did you make any changes to the html?? I'm using {{totalWeight}}, the changes are being displayed side by side instead of the sum of weight (e.g. 2.005.00 instead of 7.00 as the sum)
Oops - that's because I've made it private. I've just toggled the setting.
1

Although people have already explained what the real problem was and the question has already been answered, I want to show you how you can do this with a reactive approach:

TS:

readonly totalWeights$ = this.selection.changed.pipe(
  map(() => this.selection.selected.reduce((acc, value) => acc + value.weight, 0)),
  startWith(0)
);

HTML:

<p>Total selected weight: {{ totalWeights$ | async }}</p>

WORKING DEMO

Comments

0

First of all, define a handler to calculate sum of the each weight(named changeEvent):

<mat-checkbox (click)="$event.stopPropagation()"
                (change)="$event ? selection.toggle(row) : null;changeEvent(row)"
                [checked]="selection.isSelected(row)"
                [aria-label]="checkboxLabel(row)">

Then in your ts using reduce you can do:

public changeEvent(row?: PeriodicElement){
  this.totalWeight = 0;
  this.totalWeight = this.selection.selected.reduce((prev, cur)=>{
   return prev + cur.weight;
  }, 0);
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.