I'm getting the well known error in my Angular app, but not sure why it happens and how to fix it. I was trying a couple of ways including adding setTimeout, delay(0), switching to different hook but any of them seems to work in my case.
Problem description:
I have a list of products and on click single product can be added to the cart with selected products
//product.list.component.ts
addToProductCart(product: IProduct) {
this.productsService.addProductToSelectedProducts(product);
}
The service looks like below:
//product.service.ts
#Injectable({
providedIn: 'root'
})
export class ProductsService {
selectedProducts: BehaviorSubject<IProduct[]> = new BehaviorSubject<IProduct[]>([]);
product = this.selectedProducts.asObservable();
constructor(private http: HttpClient) { }
getProductsList(): Observable<IProduct[]> {
return this.http.get<IProduct[]>(`${environments.environment.baseUrl}/products`);
}
patchProductLikes(id: number, payload: Partial<IProduct>): Observable<number> {
return this.http.patch<number>(`${environments.environment.baseUrl}/products/${id}`, payload);
}
addProductToSelectedProducts(product: IProduct) {
this.selectedProducts.next([...this.selectedProducts.value, product]);
}
clearSelectedProducts(): void {
this.selectedProducts.next([]);
}
removeSelectedProduct(products: IProduct[]): void {
this.selectedProducts.next(products);
}
}
When product is selected on my header the product count is increased and displayed on cart icon:
//header.component.html
<span (click)="openDialog()" #openCartButton>
<mat-icon matBadge="{{selectedProductsCount}}"matBadgePosition="above after">
shopping_cart
</mat-icon>
</span>
//header.component.ts
openDialog() {
this.dialog.open(CartDetailsComponent, {
width: '450px',
height: '650px',
data: {
positionRelativeToElement: this.openCartButton
}
});
}
getSelectedProductsCount(): void {
this.productsService.product.subscribe((products) => {
this.selectedProductsCount = products.length;
});
}
If header cart icon is clicked the dialog with selected product is opened, and if there are no selected products then empty cart placeholder should be displayed:
//cart-details.component.html
<div *ngIf="products.length > 0 else emptyCart">
<h5 mat-dialog-title>Total order</h5>
<div mat-dialog-content class="product" [#loadProducts]="'in'">
<ul>
<li *ngFor="let groupedProducts of selectedProducts | keyvalue" class="product__product-item">
<div *ngFor="let prod of groupedProducts.value | productPipe; let i = index" class="product-details-container">
<div>
<img [src]="prod.image" alt="Product photo" class="product-details-container__product-img">
</div>
<div class="product-info">
<p>{{prod.name}}
<span class="product-info__price">${{prod.price}}</span>
</p>
<p>
{{prod.productMaterial}}
</p>
<p>
{{prod.color}}
</p>
<p #deleteProduct>Amount: {{groupedProducts.value.length}} </p>
<p>Total: ${{prod.price * groupedProducts.value.length}}</p>
<div class="product-actions-container">
<a (click)="deleteProduct(prod)" class="delete-product">Delete</a>
<a (click)="viewProductDetails(prod)" class="view-details">View details</a>
</div>
</div>
</div>
</li>
<span>SUM: ${{totalSum}}</span>
</ul>
</div>
</div>
<ng-template #emptyCart>
<div class="empty-bag-container">
<mat-icon svgIcon="empty-bag" class="empty-bag-container__empty-bag-icon"></mat-icon>
<h4 class="empty-bag-container__empty-bag-heading">
YOUR BAG IS EMPTY
</h4>
<span class="empty-bag-container__empty-bag-details"> Looks like you haven’t made your choice yet.
Check out 100+ styles for everyone!</span>
</div>
</ng-template>
//cart-details.component.ts
export class CartDetailsComponent implements OnInit, OnDestroy {
private positionRelativeToElement: ElementRef;
isOpen = false;
totalSum = 0;
totalPrices: number[] = [];
private destroySubject: Subject<boolean> = new Subject<boolean>();
selectedProductsCount: number;
selectedProducts: Record<string, IProduct[]>;
productSumPrice: number;
products: IProduct[] = [];
constructor(public dialogRef: MatDialogRef<CartDetailsComponent>,
private productsService: ProductsService,
#Inject(MAT_DIALOG_DATA) public data: { positionRelativeToElement: ElementRef }) {
this.positionRelativeToElement = data.positionRelativeToElement;
}
ngOnInit() {
const matDialogConfig = new MatDialogConfig();
const rect: DOMRect = this.positionRelativeToElement.nativeElement.getBoundingClientRect();
matDialogConfig.position = { right: `10px`, top: `${rect.bottom + 2}px` };
this.dialogRef.updatePosition(matDialogConfig.position);
this.getSelectedProducts();
this.calculatePrices();
}
ngOnDestroy() {
this.destroySubject.next(true);
}
close() {
this.dialogRef.close();
}
deleteProduct(product: IProduct) {
const prodId: number = product.id;
this.selectedProducts[prodId] = this.selectedProducts[prodId].slice(0, this.selectedProducts[prodId].length - 1);
const index: number = this.products.map(x => {
return x.id;
}).indexOf(product.id);
this.products.splice(index, 1);
this.productsService.removeSelectedProduct(this.products);
this.calculatePrices();
}
viewProductDetails(product: IProduct): void {
console.log(product);
}
animateCurrentItem(product: IProduct) {
console.log(product, 'animation');
}
calculatePrices() {
if (this.products.length > 0) {
this.totalPrices = [];
Object.values((this.selectedProducts))
.map((prod) => {
if (prod.length > 0) {
(prod as IProduct[]).map((p) => {
this.totalPrices.push(Number(p.price));
});
}
});
if (this.totalPrices.length > 0) {
this.totalSum = this.totalPrices.reduce((prev, cur) => {
return prev + cur;
});
} else {
this.totalSum = 0;
this.productsService.clearSelectedProducts();
}
}
}
getSelectedProducts() {
this.productsService.product
.pipe(
delay(0),
startWith([]),
takeUntil(this.destroySubject),
)
.subscribe((products) => {
if (products.length > 0) {
this.products = products;
this.productSumPrice = _.sumBy(products, (prod) => parseFloat(prod.price));
this.selectedProductsCount = _.sum(Object.values(_.countBy(products, product => product.id)));
this.selectedProducts = _.groupBy(products, 'id');
}
});
}
}
And here the error occurs. If cart is empty (meaning products.length === 0) the <ng-template #emptyCart> is displayed but with the error:
ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'loading-background: false'. Current value: 'loading-background: true'.
The error is about loading-background in ngx-ui-loader lib witch I use in app.module:
//app.module
(...)
import { NgxUiLoaderModule, NgxUiLoaderHttpModule, NgxUiLoaderConfig, SPINNER, POSITION, PB_DIRECTION } from 'ngx-ui-loader';
imports: [
...
NgxUiLoaderModule.forRoot(ngxUiLoaderConfig),
NgxUiLoaderHttpModule,
]
Any idea what cause the issue and how to fix it and avoid in the future?
I was traying to reproduce it on stackblitz but with no luck :). Although maybe it will help understand my issue ;P
https://stackblitz.com/edit/angular-h3xyop?file=src%2Fapp%2Fproduct-list%2Fproduct-list.component.ts
This is because of your view changed after rendering. You need to use changeDetectorRef to detechChanges. add in constructor
construct(private ref: changeDetectorRef)
{}
and after change you add
this.ref.detectChanges();
https://angular.io/api/core/ChangeDetectorRef
Related
Whatever I do, no matter how I change the code, I cannot get hostelid.
The problem with method deleteHostel.
Model:
export class Hostel {
hostelid: string;
name: string;
location: string;
phone?: string;
employees?: Array<Employee>;
}
Service:
export class HostelService {
getHostels(): Observable<Hostel[]>
{
return this.http.get<Hostel[]>(`${this.apiUrl}api/Hostels/`);
}
deleteHostel(id: string): Observable<any>
{
return this.http.delete(`${this.apiUrl}api/Hostels/${id}`);
}
}
Component:
ngOnInit(): void {
this.id = this.route.snapshot.paramMap['id'];
this.isAddMode = !this.id;
this.loadHostels();
if (!this.isAddMode) {
this.hostelService.getHostelById(this.id)
.pipe(first())
.subscribe( hostel => {this.hostel = hostel});
}
else {
this.hostel = new Hostel();
let newid = Guid.New() as string;
this.hostel.hostelid = newid;
}
}
loadHostels(): void
{
this.hostelService.getHostels().subscribe((data:Hostel[])=> {this.hostels = data});
}
deleteHostel(id: number):void{
let hostel = this.hostels[id];
let hostelid = hostel.hostelid;
let res = this.hostelService.deleteHostel(hostelid).subscribe( response => {
this.hostels.forEach((item, index) => {
if(item.hostelid === hostelid){
this.hostels.splice(index,1);
}
}); },
err => {
this.notifSrv.openSnackBar('error');
});
}
html:
<mat-list *ngIf="hostels">
<ng-container *ngFor="let item of hostels; last as last; let index = index;">
<h3 matSubheader>{{item.name}}
<button mat-icon-button color="warn" aria-label="delete" (click)="deleteHostel(index)">
<mat-icon>delete</mat-icon>
</button>
<button mat-icon-button color="accent" aria-label="edit" (click)="updateHostel(index)">
<mat-icon>edit</mat-icon>
</button>
</h3>
<mat-list-item>
<div> <span><span *ngIf="item.phone">{{item.phone}}</span>
{{item.location}}</span>
</div>
</mat-list-item>
<mat-divider *ngIf="!last"></mat-divider>
</ng-container>
</mat-list>
Index return normal data - 0,1,2.
But hostelid always is undefined.
If I change deleteHostel parameter to object param (string), in html
(click)="deleteHostel(item.hostelid)
and in component
deleteHostel(id: string)
id is undefined.
If I change deleteHostel parameter to object , in html
(click)="deleteHostel(item)
and in component
deleteHostel(item: Hostel)
item is undefined.
I googled a lot and tried a lot of options but nothing worked.
Update: console log
If I change deleteHostel parameter to object , in html
(click)="deleteHostel(item)
and in component
deleteHostel(hostel: Hostel)
{
console.log(hostel); <--{hostelId: "4f8be387-bbb0-4bfa-8217-09edca45f7ee", name: "test2", location: "test2", phone: null, employees: null}
console.log(hostel.hostelid); <-- undefined
}
I have vague doubts about hostelId in object, and hostelid in class, how can this be? because the type is the same.
JavaScript property names are case sensitive. Seems like the ID in your model Hostel was defined with the incorrect casing. It should be:
export interface Hostel {
hostelId: string;
// your other properties
}
Don't forget to rename the property in your delete function as well:
deleteHostel(hostel: Hostel) {
console.log(hostel.hostelId);
}
Here's the code:
parent.ts
newInputName = '';
inputName = '';
addName = false;
constructor() {
private modal: NzModalService) { }
ngOnInit() {
this.modal.afterAllClose.subscribe(md => {
console.log(this.addArea)
});
}
addItem(): void {
this.inputName = this.name;
this.newInputName = '';
this.addName = true;
}
parent.html
<div class="modal-body">
<label class="pb-2">Name</label>
<input nz-input class="mr-2" [(ngModel)]="newInputName" placeholder="Type name...">
</div>
<nz-divider></nz-divider>
<section class="form-footer" nz-row>
<div nz-col>
<button class="mr-1" nz-button nzType="primary" type="button" (click)="addItem()"
[disabled]="newInputName.length <= 0">Add Name</button>
<button nz-button class="btn-secondary" type="button" (click)="modalRef.close()"
[textContent]="'Cancel' | translate"></button>
</div>
</section>
child.ts
#Input() addName: boolean;
editLayout(shopFloor?: any, lines?: any) {
this.modalRef = this.modal.create({
......
.....
.....
.......
.......
});
this.modal.afterAllClose.subscribe((x: any) => {
this.addName = false;
});
}
What I'm trying to do here is after submitted, the modal will be closed then the value addArea will be changed to false if the value of addName is true.
cause I'm having trouble when I try to save/submit the value still true when I try to change the value of addArea to true.
I also tried to do like this:
parent.html
<app-child [addNewName]="addName"></app-child>
child.ts
#Input() addName: boolean;
#Output()
addNameChange = new EventEmitter<boolean>();
#Input() addName: boolean;
editLayout(shopFloor?: any, lines?: any) {
this.modalRef = this.modal.create({
......
.....
.....
.......
.......
});
this.modal.afterAllClose.subscribe((x: any) => {
this.addNameChange.emit(!this.addName);
});
}
But still it doesn't work.
You were almost there, on top of what you already tried (adding event emitter and emitting when the modal is done and ready to tell the parent component what to do), you also have to tell the parent component to do something when the child emits, adding the following to your parent html template:
<app-child [addNewName]="addName" (addNameChange)="resetNameChange($event)"></app-child>
and then in your parent .ts file:
...
resetNameChange(val) {
...do logic here, probably this.addName = val;
}
Getting input from a reactive form inside a ngFor ,I have to display "correct" or "incorrect" based on the comparison of the user answer with the exercise.question.answer value.
My idea is to create a boolean reactively but I'm struggling with the execution. I'm not being able to compare index[x] of array a with index [x] of array b every time these arrays are created.
This is the template:
<form
fxLayout="column"
fxLayoutGap="2px"
[formGroup]="exerciseForm"
(ngSubmit)="onSubmit(exerciseForm.value)"
>
<ul *ngFor="let exercise of exercises">
<li>{{ exercise.instruction }}</li>
<ul *ngFor="let question of exercise.questions; let i = index">
<li>
{{ question.prefix }}
<mat-form-field>
<input
name="answer"
type="text"
id="answer"
matInput
[formControlName]="question.id"
/>
</mat-form-field>
{{ question.sufix }} -
{{ question.translation }}
<div *ngIf="isAnswered">
<div *ngIf="isCorrect"><p>Correct</p></div>
<div *ngIf="!isCorrect"><p>Incorrect</p></div>
</div>
</li>
</ul>
</ul>
<button type="submit" mat-raised-button color="primary">Submit</button>
</form>
this is the ts (it contains some of the methods I've been attempting)
export class ExerciseTestsComponent implements OnInit {
exerciseForm: FormGroup;
isAnswered: boolean;
isCorrect: boolean;
exercises: Exercise[] = [
new Exercise("Answer this question", [
new Question(1, "Eu", "maluco", "I am crazy", "sou"),
new Question(2, "Eu", "doidinho", "I am cuckoo", "estou")
])
];
constructor(private fb: FormBuilder) {}
ngOnInit(): void {
this.createGroup();
}
getAnswersArray() {}
createGroup() {
this.exerciseForm = this.fb.group({});
this.exercises[0].questions.forEach(control =>
this.exerciseForm.addControl(control.id.toString(), this.fb.control(""))
);
}
onSubmit(answer: TestAnswer) {
this.isAnswered=true;
//** 1
let answers = [];
let answersInput = [];
this.exercises[0].questions.forEach(pergunta => {
//** 2
answers.push(pergunta.answer);
console.log(answers);
});
//** 3
var bosta = Object;
bosta = this.exerciseForm.value;
console.log(bosta[1]);
if ((answers[1] = bosta[1])) {
console.log("pqp");
}
let incoming = this.exerciseForm.value;
for (var o in incoming) {
answersInput.push(incoming[o]);
console.log(answersInput);
}
answersInput.forEach(a1 =>
answers.forEach(a2 => {
if (a1 === a2) {
console.log("yay");
} else {
console.log("boo");
}
})
);
}
}
//** for every object created, I have to check if answer = */
stackblitz:
https://stackblitz.com/edit/angular-dzzzql
Then when you submit, you can compare both answers
onSubmit(answer: Answer) {
let answers = [];
console.log(this.exercises)
let answersInput = []
this.exercises[0].questions.forEach((pergunta, index) => {
answers.push(pergunta.answer)
console.log(answers)
return answers
})
let i = 0;
for (const field in this.exerciseForm.controls) { // 'field' is a string
console.log(this.exerciseForm.controls[field].value == answers[i]);
i++;
}
}
Working demo in Stackblitz
I have ReviewComponent. In this component I show all reviews and can write a new review. But when I added a new review, all reviews don't refresh and refresh only if I click a link in the component("Write a review" or "Read all reviews"). How to make refresh all reviews after add a new review?
review.component.ts
import { Component, OnInit, ChangeDetectionStrategy, Input } from '#angular/core';
import { FormBuilder } from '#angular/forms';
import { ItemService } from '../../services/item.service';
#Component({
changeDetection: ChangeDetectionStrategy.OnPush,
selector: 'app-review',
templateUrl: './review.component.html',
styleUrls: [ './review.component.css' ]
})
export class ReviewComponent implements OnInit {
#Input() itemId: string;
stars = [];
reviewId: string;
reviews;
commentBox: boolean = false;
reviewsBox: boolean = false;
grades = 0;
commentForm = this.fb.group({
comment: [ '' ],
assessment: [ '1' ]
});
constructor(private fb: FormBuilder, private _itemService: ItemService) {}
ngOnInit() {
this.getReviews();
}
getReviews() {
this._itemService.getReviews(this.itemId).subscribe((data) => {
this.reviews = data.map((review) => {
return {
id: review.payload.doc.id,
...review.payload.doc.data()
};
});
this.reviewId = this.reviews.length + '';
let avgAssess = 0;
this.reviews.forEach((review) => {
avgAssess += parseInt(review.assessment);
});
this.grades = Math.floor(avgAssess / this.reviews.length);
console.log(this.grades);
this.stars = [];
for (let i = 0; i < this.grades; i++) {
this.stars.push('grade');
}
for (let i = this.grades; i < 5; i++) {
this.stars.push('star_border');
}
});
}
showCommentBox() {
this.commentBox = !this.commentBox;
}
showReviewsBox() {
this.reviewsBox = !this.reviewsBox;
}
sendComment() {
let review = {
comment: this.commentForm.get('comment').value,
assessment: this.commentForm.get('assessment').value
};
this._itemService.addReview(this.itemId, this.reviewId, review);
this.showCommentBox();
this.commentForm.patchValue({
comment: [ '' ],
assessment: [ '1' ]
});
}
validPaymentInput(event) {
var char = String.fromCharCode(event.which);
if (!/[1-5]/.test(char)) {
event.preventDefault();
}
}
}
item.service.ts
import { Injectable } from '#angular/core';
import { AngularFirestore } from '#angular/fire/firestore';
#Injectable({
providedIn: 'root'
})
export class ItemService {
constructor(private _firestore: AngularFirestore) {}
addReview(key: string, reviewId, review) {
this._firestore.collection('items').doc(key).collection('reviews').doc(reviewId).set(review);
}
getReviews(key: string) {
return this._firestore.collection('items').doc(key).collection('reviews').snapshotChanges();
}
}
review.component.html
<div class="container">
<div>
<div class="stars" >
<mat-icon *ngFor="let star of stars">{{star}}</mat-icon>
<div>({{reviews.length}})</div>
</div>
<div class="reviews" (click)="showReviewsBox()">
<span>Read all {{reviews.length}} Reviews</span>
</div>
<div class="write" (click)="showCommentBox()">
<span>Write a review</span>
</div>
</div>
<div class="comment-box" *ngIf="commentBox" [formGroup]="commentForm">
<div [ngClass]="{'has-error' : commentForm.get('comment').errors && (commentForm.get('comment').touched || commentForm.get('comment').dirty)}">
<label> Enter a comment</label>
<textarea formControlName="comment" required></textarea>
<div class="error-msg"
*ngIf="commentForm.get('comment').errors && (commentForm.get('comment').touched || commentForm.get('comment').dirty)">
<span *ngIf="commentForm.get('comment').errors.required">
Comment field is required
</span>
</div>
</div>
<div [ngClass]="{'has-error' : commentForm.get('assessment').errors && (commentForm.get('assessment').touched || commentForm.get('assessment').dirty)}">
<label for="">Evaluate from 1 to 5</label>
<input type="text" (keypress)="validPaymentInput($event)" formControlName="assessment" max="5" maxlength="1" required>
<app-button btnText="Submit" [disabled]="!commentForm.valid" (click)="sendComment()"></app-button>
</div>
</div>
<div class="reviews-box" *ngIf="reviewsBox && reviews.length > 0">
<div class="review" *ngFor="let review of reviews">{{ review.comment }}</div>
</div>
</div>
Call getReviews() method inside your sendComment() method. Refer code snippet below:
sendComment() {
let review = {
comment: this.commentForm.get('comment').value,
assessment: this.commentForm.get('assessment').value
};
this._itemService.addReview(this.itemId, this.reviewId, review);
this.getReviews();
this.showCommentBox();
this.commentForm.patchValue({
comment: [ '' ],
assessment: [ '1' ]
});
}
Update:
Have noticed that the change detection strategy is onPush, which means that you have ensure that all your objects are immutable. Please change the method getReviews() to as shown below:
getReviews() {
this._itemService.getReviews(this.itemId).subscribe((data) => {
this.reviews = data.map((review) => {
return {
id: review.payload.doc.id,
...review.payload.doc.data()
};
});
this.reviewId = this.reviews.length + '';
let avgAssess = 0;
this.reviews.forEach((review) => {
avgAssess += parseInt(review.assessment);
});
this.grades = Math.floor(avgAssess / this.reviews.length);
console.log(this.grades);
this.stars = [];
const _stars:any=[];
for (let i = 0; i < this.grades; i++) {
_stars.push('grade');
}
for (let i = this.grades; i < 5; i++) {
_stars.push('star_border');
}
// to ensure that your object is immutable. Do not change the object content once it is assigned
this.stars=_stars;
});
}
Update 2:
Looks like the objects are immutable, which is causing the change detection to not work. Please remove the following line from your component:
changeDetection: ChangeDetectionStrategy.OnPush,
i try to remove a object from array in vueJS but this is impossible.
I tyr a lot of thing and read some solution on stackoverflow but nothing work for me.
I have a fake list like this in my vue.html component :
<div class="custo-list-c">
<div v-for="(item, index) in valuesFounded"
#click="addItem(item)"
v-bind:class="{ 'selected': itemSelected(item) }">
{{ item.value }}
<span v-if="itemSelected(item)">
<i class="fa fa-remove" #click="itemDeleted(item)"></i>
</span>
</div>
</div>
And my component look something like this :
import Vue from 'vue';
import Component from 'vue-class-component';
import { Prop, Watch, Emit } from "vue-property-decorator";
#Component({
name: 'custolist-component',
template: require('./custo-list.component.vue.html'),
components: {}
})
export default class CustoListComponent extends Vue {
public custoListActive: boolean = false;
public valuesFounded: Array<{key: string, value: string}> = [];
public selectedItems_: Array<{key: string, value: string}> = [];
#Prop() list;
#Watch('list') onListChanged(newList, oldList) {
// this.list = newList;
}
#Prop() placeholder;
#Watch('placeholder') onPlaceholderChanged(newPlaceholder, oldPlaceholder) {
// console.log(newPlaceholder);
}
#Prop() disabled;
#Watch('disabled') onDisabledChanged(newDisabled, oldDisabled) {
// console.log(newPlaceholder);
}
public open(event) {
this.custoListActive = true;
if (!event.target.value) {
this.valuesFounded = this.list;
} else {
this.valuesFounded = [];
const re = new RegExp(event.target.value, 'ig');
for (var i=0; i<this.list.length; i++) {
if (this.list[i].key.match(re) || this.list[i].value.match(re)) {
this.valuesFounded.push(this.list[i]);
}
}
}
}
public addItem(item: {key: string, value: string}) {
if (!this.isSelectedItem_(item)) {
this.selectedItems_.push(item);
// this.custoListActive = false;
};
this.$emit('itemclicked', item);
}
public itemSelected(item) {
return this.isSelectedItem_(item);
}
public itemDeleted(item) {
for (var i=0; i<this.selectedItems_.length; i++) {
if (item.key == this.selectedItems_[i].key) {
this.selectedItems_.splice(i, 1);
break;
}
}
this.$emit('itemdeleted', item);
}
private isSelectedItem_(item) {
const filtered = this.selectedItems_.filter(m => {
return m.key == item.key;
});
return filtered.length > 0;
}
}
but when i do this.selectedItems_.splice(i, 1); that does not work !!
Thank for your help
More precisions about my code. Here the method where i remove item from my array :
public itemDeleted(item) {
const filtered = this.selectedItems_.filter(m => {
return m.key != item.key;
});
console.log(filtered, this.selectedItems_.length);
this.selectedItems_ = filtered;
console.log(this.selectedItems_, this.selectedItems_.length);
this.$emit('itemdeleted', item);
}
And the result in the console
console
What's wrong?
Another test :
public itemDeleted(item) {
this.selectedItems_ = this.selectedItems_.filter(m => {
return m.key != item.key;
});
this.selectedItems_.splice(this.selectedItems_.length);
console.log(this.selectedItems_, this.selectedItems_.length);
this.selectedItems_ = [];
console.log(this.selectedItems_, this.selectedItems_.length);
this.$emit('itemdeleted', item);
}
result :
console
May be a bug VueJS
Sorry, it was my fault, replace
<i class="fa fa-remove" #click="itemDeleted(item)"></i>
by
<i class="fa fa-remove" v-on:click.stop="itemDeleted(item)"></i>
Having multiple steps of finding value with combination of for loop and if statement reduces readability and code predictability. In addition, invoking array mutating method splice may not trigger reactive update of this property.
I'd suggest to use filter and re-assign selectedItems_ inside itemDeleted method as follows:
public itemDeleted(item) {
this.selectedItems_ = this.selectedItems_.filter(selectedItem => selectedItem.key !== item.key)
this.$emit('itemdeleted', item);
}
This way, after method execution, selectedItems_ will consist of all previous items except the one provided as an argument to the method and all dependent properties will be re-computed.