0
votes

I have a list of items, and I want to implement add/update/delete functionality.

In general, I have a list of items (parent's component) and a button next to it. When clicked, modal window is opened (child's component) which allows to input item's properties.

Also, when clicked on an item in the list, the same modal window is shown with all the item's properties (enable for editing). On the same modal window there should be a "delete item" button, which removes item from list.

So far I have this template located in parent's bootstrap code, which points to the modal component (which plays a child role here)

<h3>Top Items</h3>
<div class="grid grid-pad">
  <a *ngFor="let e of items" class="col-1-4"  (click)="openModal(e)">
    <div class="module items">
      <h4>{{e.name}}</h4>
    </div>
  </a>
</div>

<button type="button" class="btn btn-primary" (click)="openModal(item)">Add new item</button>

  <ng-template #newItem>
  <app-create-or-update-item
  [(item)]="item"
  (ngModelChange)="itemChange.emit($event); change()" ngControl="item" name="item">

It allows me to change items in the list (parent component) as soon as it is changed in the modal window (child component). However, I don't know how to implement two other cases - creating new component and deleting old one.

[(item)] is an item which is being edited. However, what should I pass as an item when a "create new item" button is clicked and I don't have an item to edit, but want to create a new one? And how to implement automatic adding this new creating item to the list when the modal window is closed?

Same question for deleting. What should I pass to child's element and pass back to parent's so that I can see this item being removed from the list without making another API Get() call?

1
This question feels a little too broad. It feels like you are asking the community to implement features for you as opposed to doing research and coming to SO when you get truly stuck. CRUD operations are covered in many tutorials and courses, it could be worth having a look into that. - Will Alexander
@WillAlexander I didn't want someone to implement it for me of course, just some tips/common ideas of how to do it the right way. I looked into a bunch of different articles regarding it and I didn't find an ultimate way of implementing all the functionality I wrote about. Anyway, I implemented it how I got it, and will answer my own questions and look forward any critics/suggestions/tips/etc. - Sofia Bo

1 Answers

0
votes

So, in case anyone is interested this is how I implemented aforementioned behavior. It might not be the right way to do it, so if you have any critics/suggestions/tips leave them down below, please.

In general, if a user clicks on existing item, I pass this Item to child component, otherwise I pass null. In child component I assume that if null was passed, its a 'create' mode, otherwise it is 'update' mode.

Change/add/close/delete are @Output EventEmitter. Is it a good way to do implement it or not?

Hope it'll be helpful to someone one day.

Parent component with a list of items: dashboard.component.html

<div class="grid grid-pad">
  <a *ngFor="let e of items" class="col-1-4"  (click)="openModal(newItem,e)">
    <div class="module items">
      <h4>{{e.name}}</h4>
    </div>
  </a>
</div>

<button type="button" class="btn btn-primary" (click)="openModal(newItem)">Add new item</button>

<ng-template #newItem>
  <app-create-or-update-item
  [item]="item"
  (itemChange)="item($event)"
  (itemAdd)="addItem($event)"
  (close)="closeModal()"
  (delete)="deleteItem($event)"
  >
</app-create-or-update-item>

dashboard.component.ts

export class DashboardComponent implements OnInit {
  @ViewChild(CreateOrUpdateItemComponent, { static: false }) itemModal: CreateOrUpdateItemComponent;

  items: Item[] = [];
  newItemModal: BsModalRef;
  item: Item;

  constructor(private itemService: ItemService,
    private modalService: BsModalService) { }

  ngOnInit() {
    this.getItems();
  }

  getItems(): void {
    this.itemService.getItems()
      .subscribe(res => {
        this.items = res.slice(0, 50);
      });
  }

  openModal(template: TemplateRef<any>, item: Item) {
    this.item = item;
    this.newItemModal = this.modalService.show(template, { backdrop: true, keyboard: true });
  }

  closeModal() {
    this.modalService.hide(1);
  }

  change(value): void {
    this.closeModal();
  }

  addItem(value: Item) {
    this.items.push(value);
    this.closeModal();
  }

  deleteItem(value: Item) {
    this.itemService.deleteItem(value.id).subscribe();
    this.closeModal();
  }
}

And for the child component: create-or-update-item.component.html

<div id="modal-content-wrapper">

  <div class="modal-header">
    <h4 class="modal-title pull-left">Add new item</h4>
    <button type="button" class="close" data-dismiss="modal" aria-label="Close" (click)="closeModal()">
      <span aria-hidden="true">&times;</span>
    </button>
  </div>
  <div class="modal-body">

    <label for="itemName">Item</label>
    <input type="text" class="form-control" id="itemName" [(ngModel)]="item.name">       

  </div>
  <div class="modal-footer">
    <div *ngIf="createMode; then saveBlock else updateBlock"></div>
  </div>

</div>

<ng-template #saveBlock>
  <button type="button" class="btn btn-secondary" (click)="save()">Save</button>
</ng-template>
<ng-template #updateBlock>
  <button type="button" class="btn btn-danger" (click)="confirmDelete(confirmDeletionModal)">Delete</button>
  <button type="button" class="btn btn-secondary" (click)="save()">Update</button>
</ng-template>


<ng-template #confirmDeletionModal>
  <div class="modal-header">
    <h4 class="modal-title pull-left">Are you sure about this?</h4>
    <button type="button" class="close" data-dismiss="modal" aria-label="Close" (click)="closeModal()">
      <span aria-hidden="true">&times;</span>
    </button>
  </div>
  <div class="modal-body">
    <p>Do you really want to delete this item?</p>
  </div>
  <div class="modal-footer">
    <button type="button" class="btn btn-info" data-dismiss="modal">Cancel</button>
    <button type="button" class="btn btn-danger" (click)="deleteItem()">Delete</button>
  </div>

</ng-template>

create-or-update-item.component.ts:

export class CreateOrUpdateItemComponent implements OnInit {

  @Input() item: Item;
  @Output() itemChange:EventEmitter<Item> = new EventEmitter<Item>();
  @Output() itemAdd:EventEmitter<Item> = new EventEmitter<Item>();
  @Output() close:EventEmitter<any> = new EventEmitter<any>();
  @Output() delete:EventEmitter<any> = new EventEmitter<any>();

  createMode: boolean;
  deleteConfirmationModal: BsModalRef;


  constructor(private modalService: BsModalService,
              private itemService: ItemService) { }

  ngOnInit() {   
     if (this.item==null) {
       this.createMode=true;
       this.item=new Item();
     }
     else {
       this.createMode=false;
     }

  }

  save(): void {
    if (this.createMode) {
      this.itemService.createItem(this.item).subscribe();
      var addedItem=this.item;
      this.itemAdd.emit(addedItem);
    }
    else {
      this.itemService.updateItem(this.item).subscribe();
      var updatedItem=this.item;
      this.itemChange.emit(updatedItem);
    }
  }

  closeModal(): void {
    this.close.emit();
  }

  confirmDelete(template: TemplateRef<any>):void {
    this.deleteConfirmationModal = this.modalService.show(template, { backdrop: true, keyboard: true });
  }

  deleteItem():void {
    this.delete.emit(this.item);
    this.modalService.hide(1);
  }
}