Angular 11 get any param from object is undefined - javascript

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

Related

Angular Expression has changed after it was checked

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

update value from child to parent component in mat card

I have a angular application and I have two components. ONe where you can update the item. And a other one where the updated value has to be visible directly when the button update is been triggered.
So I made a service like this:
export class ItemListService {
_updateItemChanged = new Subject<string>();
constructor() {}
get refreshNeeded() {
return this._updateItemChanged.next();
}
}
and the value where the value is comming from:
[appSubmitIfValid]="editItemForm" (valid)="save()" i18n>Update</button>
<button *ngIf="!isNew" mat-raised-button color="warn" (click)="openRemoveDialog()" i18n>Remove</button>
save(): void {
const form = this.editItemForm;
const dossierItemDto: DossierItemPostDto = {
title: form.controls.title.value,
itemType: form.controls.itemType.value,
date: (form.controls.date.value as moment.Moment).format('Y-MM-DD'),
body: form.controls.body.value
};
form.disable();
if (!this.isNew) {
this.dossierItemService.updateDossierItemById(this.dossier.id, this.item.id, dossierItemDto)
.subscribe(item => {
this.item = item;
this.sortDossierItems();
form.enable();
form.markAsPristine();
this.itemListService._updateItemChanged.next(this.item.title);
this.errorProcessor.openSuccessSnackBar($localize`Item is saved`);
}, error => this.handleError(error));
} else {
this.dossierItemService.newDossierItem(this.dossier.id, dossierItemDto)
.subscribe(item => {
this.item = item;
this.dossierItems.unshift(item);
this.sortDossierItems();
this.isNew = false;
form.enable();
form.markAsPristine();
this.errorProcessor.openSuccessSnackBar($localize`Item is saved`);
}, error => this.handleError(error));
}
}
and the component that has to been updated(parent):
dossierItems: DossierItemDto[] = [];
ngOnInit(): void {
this.itemlistService._updateItemChanged.subscribe((data) => {
data = this.dossierItems.map(a => a.title) ;
});
But I get now this error:
Type 'string[]' is not assignable to type 'string'.ts(2322)
So what I have to change?
Thank you
oke, and this value has to be updated: the item.title.
<ng-template #itemList let-itemType="itemType">
<mat-card *ngFor="let item of dossierItemsBy(itemType); let i = index" class="dossier-item-view">
<mat-card-header>
<mat-card-title>
<span [innerHTML]="item.title | highlight: searchQuery"></span>
<span class="spacer"></span>
<span><app-attachment-links [attachments]="item.attachments" [dossierId]="dossier.id" ></app-attachment-links></span>
</mat-card-title>
<div class="mat-card-header-text">
<span *ngIf="!createdAtEqualsDate(item)"
>{{ item.date | date: 'shortDate' }}<ng-template i18n>created</ng-template></span
>
<span>{{ item.createdAt | date: 'short' }}</span>
<span *ngIf="item.createdAt !== item.lastModifiedAt"
><ng-template i18n>modified</ng-template> {{ item.lastModifiedAt | date: 'short' }}</span
>
</div>
<span>
<a mat-icon-button [routerLink]="['../', dossier.id, 'item', item.id]" routerLinkActive="active-link"
[routerLinkActiveOptions]="{exact:true}"
i18n-title title="Edit">
<mat-icon>edit</mat-icon>
</a>
</span>
</mat-card-header>
</mat-card>
</ng-template>
dossierItemsBy(itemType: DossierItemTypeDto) {
return this.dossierItems.filter(
i => i.itemType === itemType && (!this.hasSearchQuery || this.itemSearchMatches[i.id].hasMatch)
);
}
You wrote that in subject pass string
_updateItemChanged = new Subject<string>();
And in subscribe you try to assign an array of strings to it
this.itemlistService._updateItemChanged.subscribe((data) => {
data = this.dossierItems.map(a => a.title) ;
});
If you want to update your parent, why not use Output ?

Cannot delete property '1' of [object Array]

get list with Input in my components :
#Input() usersInput: Section[];
export interface Section {
displayName: string;
userId: number;
title: number;
}
and this is the value list :
0:
displayName: "بدون نام"
firstName: null
lastName: null
title: 0
userId: 1
1:
displayName: "محمدامین چهاردولی"
firstName: "محمدامین"
lastName: "چهاردولی"
title: 0
userId: 2
in ngAfterViewInit i set the input Value to users List :
ngAfterViewInit(): void {
this.users = this.usersInput;
if (this.users.length === 0) {
this.show = false;
} else {
this.show = true;
}
}
this is Users :
users: Section[] = [];
and i use it in html List :
<div *ngFor="let item of users" class="d-flex selected-list-items mt-3">
<div class="col-md-5 col-lg-5 col-xs-5 col-sm-5 col-xl-5">
<label>{{item.displayName}}</label>
</div>
<div class="col-md-5 col-lg-5 col-xs-5 col-sm-5 col-xl-5">
<label> {{ getEnumTranslate(item.title)}}</label>
</div>
<div class="justify-content-center col-md-2 col-lg-2 col-xs-2 col-sm-2 col-xl-2">
<button (click)="deleteUser(item.userId)" mat-button>
<mat-icon aria-label="Delete" color="accent">delete</mat-icon>
</button>
</div>
</div>
now when i need to use delete button :
<button (click)="deleteUser(item.userId)" mat-button>
<mat-icon aria-label="Delete" color="accent">delete</mat-icon>
</button>
ts :
deleteUser(id: number): void {
let userModel = {} as Section;
userModel = this.users.find(x => x.userId === id);
const index = this.users.indexOf(userModel);
this.users.splice(index, 1);
this.emitValueModel.push(
{
title: this.user.title,
userId: this.user.userId
}
);
this.selectedUserId.emit(this.emitValueModel);
if (this.users.length === 0) {
this.show = false;
}
this.cdref.detectChanges();
}
it show me this error :
ERROR TypeError: Cannot delete property '1' of [object Array]
whats the problem??? how can i solve that ?
I've faced the same issue and according to this article the problem is that user array has non configurable properties. I suppose angular Inputs are set as non configurable. When you do:
this.users = this.usersInput
you simply pass the reference of input to this.users.
The solution is to simply copy input array before splicing. In your case:
this.users = [...this.usersInput];
Btw. do it in deleteUser method instead of afterViewInit with local variable. You do not need two class props referring to the same object.
I ran across this issue in my React app, but assume the same issue is occurring here, in Angular. The reason for the error was that I was making a shallow copy via the JS spread operator.
const newArr = [...oldArr];
newArr.splice(1) // Remove all items except for the first one.
// This would throw the error `Cannot delete property '1' of [object Array]`
The solution was to install lodash.clonedeep and perform a deep clone.
import cloneDeep from "lodash.clonedeep";
const newArr = cloneDeep(oldArr);
newArr.splice(1) // Remove all items except for the first one.
// Success!
Try:
deleteUser(id) {
const index = this.users.findIndex(x => x.userId === id);
this.users.splice(index, 1);
}
Working Demo
This article states what you have to do to solve this. Basically, you have to specify that the element of the index in the array you want to delete is configurable. So you just have to state
Object.defineProperty( array , index you want to delete, { configurable : true } );
Article: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Non_configurable_array_element

Angular Filter Pipe for KeyValue and AutoComplete

First of all I want to show countries with this pipe and filter them with inserted characters and I need the ISO codes to show the flags of the countries. The problem is that I want to use a library which has all countries with ISO codes and stuff. This has the key value form.
First of all I export this data to var to be able to use the data.
export var indexedArray: { [key: string]: string }
countryStuff: Country; //currently not used
countries = [] as Array<string>
filteredCountries: Observable<string[]>;
export interface Country { //currently not used
[key: string]: string
}
ngOnInit() {
this.startDate.setFullYear(this.startDate.getFullYear() - 18);
this.buildForm();
this.filteredCountries = this.personalForm.controls['country'].valueChanges
.pipe(
startWith(''),
map(value => this._filter(value))
);
i18nIsoCountries.registerLocale(require("i18n-iso-countries/langs/en.json"));
i18nIsoCountries.registerLocale(require("i18n-iso-countries/langs/de.json"));
this.currentLanguage = this.translateService.currentLang;
indexedArray = i18nIsoCountries.getNames(this.currentLanguage);
for (let key in indexedArray) {
let value = indexedArray[key];
this.countries.push(value);
}
}
In the html I can use this like this:
<mat-option *ngFor="let item of countryStuff | keyvalue:keepOriginalOrder" [value]="item.key">
Key: <b>{{item.key}}</b> and Value: <b>{{item.value}}</b>
</mat-option>
The normal way I can also use but completly without the key value way and just like the Angular examples say (without the TS logic):
<mat-option *ngFor="let option of filteredCountries | async" [value]="option">
<span class="flag-icon flag-icon-de flag-icon-squared"></span>
{{option}}
</mat-option>
That just gives me the full country name like Algeria or something.
I have found an idea here https://long2know.com/2017/04/angular-pipes-filtering-on-multiple-keys/ but I couldn't change it for my purposes. That would be even more perfect if I could filter for key and value so maybe "DE" for key and "Ger" for value of Germany. It does not seem to be possible with existing pipes.
Edit on request (filtering):
private _filter(value: string): string[] {
var filterValue;
if (value) {
filterValue = value.toLowerCase();
} else {
filterValue = "";
}
return this.countries.filter(option => option.toLowerCase().startsWith(filterValue));
}
Also updated the ngOnInit()
I got it working with the i18n library and even flag-icon-css
TypeScript (filter class):
#Pipe({
name: 'filterLanguages'
})
export class FilterLanguages implements PipeTransform {
transform(items: any, filter: any, isAnd: boolean): any {
if (filter && Array.isArray(items)) {
let filterKeys = Object.keys(filter);
if (isAnd) {
return items.filter(item =>
filterKeys.reduce((memo, keyName) =>
(memo && new RegExp(filter[keyName], 'gi').test(item[keyName])) || filter[keyName] === "", true));
} else {
return items.filter(item => {
return filterKeys.some((keyName) => {
return new RegExp(filter[keyName], 'gi').test(item[keyName]) || filter[keyName] === "";
});
});
}
} else {
return items;
}
}
}
HTML:
<mat-form-field class="field-sizing">
<input matInput required placeholder="{{ 'REGISTRATION.COUNTRY' | translate }}" name="country"
id="country" [matAutocomplete]="auto" formControlName="country" [value]="filterText" />
<mat-autocomplete autoActiveFirstOption #auto="matAutocomplete">
<mat-option *ngFor="let item of countries | filterLanguages:{ name: filterText, iso: filterText, flagId: filterText } : false" [value]="item.name">
<span class="flag-icon flag-icon-{{item.flagId}} flag-icon-squared"></span>
{{ item.name }} - {{ item.iso }}
</mat-option>
</mat-autocomplete>
</mat-form-field>
TypeScript (component):
export var countryList: {
[key: string]: string
}
declare const require;
export class YourComponent implements OnInit {
countries = [] as Array<any>
currentLanguage: string;
filterText: string;
ngOnInit() {
i18nIsoCountries.registerLocale(require("i18n-iso-countries/langs/en.json"));
i18nIsoCountries.registerLocale(require("i18n-iso-countries/langs/de.json"));
this.currentLanguage = this.translateService.currentLang;
countryList = i18nIsoCountries.getNames(this.currentLanguage);
this.buildForm();
this.createCountries();
this.personalForm.controls['country']
.valueChanges
.pipe(debounceTime(100))
.pipe(distinctUntilChanged())
.subscribe(term => {
this.filterText = term;
});
}
ngAfterContentChecked() {
this.cdRef.detectChanges();
if (this.currentLanguage != this.translateService.currentLang) {
countryList = i18nIsoCountries.getNames(this.translateService.currentLang);
this.createCountries();
this.currentLanguage = this.translateService.currentLang;
this.personalForm.get('country').updateValueAndValidity();
}
}
createCountries() {
this.countries = [];
for (let key in countryList) {
var countryName: string = countryList[key];
var isoValue: string = key;
var isoLowerValue: string = key.toLowerCase();
this.countries.push({ name: countryName, iso: isoValue, flagId: isoLowerValue })
}
}
You need the i18n library and like in my example a formControl.

VueJS Typescript WebPack, impossible to remove object from array with splice or delete

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.

Categories