MountainSlayer
MountainSlayer

Reputation: 321

View is not updating in Angular 6

I have an app where I have a list, and a user can delete items from the list.

Here is the service that holds the initial list and the function that removes items from said list:

    import {Injectable} from '@angular/core';

@Injectable()
export class Services {
  public items: any[] = [
    {
      title: 'Tarek learns Angular',
      subheading: 'He now knows Angular!',
      subtext: 'He adds another framework to his techstack!',
      avatar: 'https://i.kym-cdn.com/entries/icons/original/000/013/564/doge.jpg',
      date: 'Friday July 20th 2018',
      isNewItem: true
    },
    {
      title: 'Human throws frisbee',
      subheading: 'Dog catches frisbee!',
      subtext: 'Dog is a good boy!',
      avatar: 'https://i.kym-cdn.com/entries/icons/original/000/013/564/doge.jpg',
      date: 'Friday July 20th 2018',
      isNewItem: false
    },
    {
      title: 'Human sdfgsfsdfthrows frisbee',
      subheading: 'Dog cadsfsatches frisbee!',
      subtext: 'Dog is a good bvsdfvsdvoy!',
      avatar: 'https://i.kym-cdn.com/entries/icons/original/000/013/564/doge.jpg',
      date: 'Friday July 20th 2018',
      isNewItem: false
    },
    {
      title: 'Humavsdvsdn throsdvsdvsdvws frisbee',
      subheading: 'Dog cavsddsvstches frisbee!',
      subtext: 'Dog is adsvsdfeegedsf good boy!',
      avatar: 'https://i.kym-cdn.com/entries/icons/original/000/013/564/doge.jpg',
      date: 'Friday July 20th 2018',
      isNewItem: false
    }
  ];

  numberOfNewItems: number = this.items.map(function (item) {
    if (item.isNewItem) {
      return item;
    }
  }).length;

  deleteItem = (itemObj: { itemTitle: string, itemSubheading: string, itemSubtext: string, itemDate: string }) => {
    const newItems: any [] = [];

    let numberOfFilteredNewItems: number = 0;

    const filterUndefined = this.items.map((item) => {

      if (item.title !== itemObj.itemTitle && item.subheading !== itemObj.itemSubheading) {
        if (item.subtext !== itemObj.itemSubtext && item.data !== itemObj.itemDate) {
          return item;
        }
      }
    });

    for (const item of filterUndefined) {

      if (item !== undefined) {

        newItems.push(item);

        if (item.isNewItem) {

          numberOfFilteredNewItems++;

        }

      }

    }

    this.items = newItems;

    this.numberOfNewItems = numberOfFilteredNewItems;

  };

  checkItemAsOld = (itemObj: { itemTitle: string, itemSubheading: string, itemSubtext: string, itemDate: string }) => {

    const newItems = this.items.map((item) => {

      if (item.title === itemObj.itemTitle && item.subheading === itemObj.itemSubheading && item.subtext === itemObj.itemSubtext && item.date === itemObj.itemDate) {
        return {title: item.title, subheading: item.subheading, subtext: item.subtext, date: item.date, isNewItem: false};
      } else {
        return item;

      }


    });

    let numberOfNewFilteredItems: number = 0;

    for (const item of newItems) {

      if (item.isNewItem) {

        numberOfNewFilteredItems++;

      }

    }

    this.numberOfNewItems = numberOfNewFilteredItems;

    this.items = newItems;

    console.log(this.numberOfNewItems);

    console.log(this.items);

  }
}

The deleteItem and checkItemAsOld are operating correctly, and are updating the values. Every time I console.log, it shows this.items and 'this.numberOfNewItems` updating correctly. But for some reason the view is not updating at all.

I made sure that in app.module.ts, I attached the Service to the providers array, and made sure that there were no providers arrays in the other components that could overwrite the providers array in the app.modules.ts file. Here is the app.module.ts file:

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppComponent } from './app.component';

import {ListComponent} from './ListComponent/list.component';

import {HeaderComponent} from './HeaderComponent/header.component';

import {ItemComponent} from './ItemComponent/item.component';
import {FooterComponent} from './FooterComponent/footer.component';

import {Services} from './services';

@NgModule({
  declarations: [
    AppComponent,
    ListComponent,
    HeaderComponent,
    ItemComponent,
    FooterComponent
  ],
  imports: [
    BrowserModule
  ],
  providers: [Services],
  bootstrap: [AppComponent]
})
export class AppModule { }

In app.components.html, I passed down the items as such:

<app-list [items]="items" [numberOfNewItems]="numberOfNewItems"></app-list>

And here is the 'app.component.ts` file:

import {Component, OnInit, Input} from '@angular/core';

import {Services} from './services';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})


export class AppComponent implements OnInit {

  @Input() items: { title: string, subheading: string, subtext: string, avatar: string, date: string, isNewItem: boolean }[] = [];

  @Input() numberOfNewItems: number;

  constructor(private listServices: Services) {
  }

  ngOnInit() {

    this.items = this.listServices.items;

    this.numberOfNewItems = this.listServices.numberOfNewItems;

  }


}

I passed the items array to the list.component.ts file:

        import {Component, Input, EventEmitter} from '@angular/core';

    import {ItemModel} from '../ItemComponent/item.model';
    import {Services} from '../services';

    @Component({
      selector: 'app-list',
      templateUrl: './list.component.html',
      styleUrls: ['./list.component.css']
    })

    export class ListComponent {
      @Input() items: any [];
      @Input() numberOfNewItems: number;

      constructor(private listServices: Services) {
      }

    }

But still the view doesn't update even though this.items updates. Can anyone help me? I am new to Angular.

Upvotes: 1

Views: 1723

Answers (1)

Michael Kang
Michael Kang

Reputation: 52847

Within your service you are updating the list reference when an item is deleted (basically copying the list into another array, and over-writing the previous reference):

this.items = newItems;

this.numberOfNewItems = numberOfFilteredNewItems;

But not updating the list reference used in your component:

ngOnInit() {

  this.items = this.listServices.items;

  this.numberOfNewItems = this.listServices.numberOfNewItems;

}

There are many ways to solve this to keep your references in synch.

One simple way is to bind to the reference directly:

<app-list [items]="listServices.items" [numberOfNewItems]="listServices.numberOfNewItems"></app-list>

Another way is to expose Observables from your service that your component can subscribe to whenever the list changes.

Finally, the third option: keep the list reference, just delete the item. Why re-create the list as a new array reference when you don't need to.

deleteItem(item: any) {
    let i = this.items.indexOf(item);
    if (i >= 0) {
       this.items.splice(i, 1);
    }
}

The 3rd option is probably the simplest, most typical way one would delete from a list. This is also the option I recommend, followed by option 2, then option 1.

Upvotes: 1

Related Questions