How to Transfer Deleted List Items from one Unordered List to another in Angular 9 using Event Binding

Greetings to all =) I've recently delved into Angular 9 and I'm really enjoying the component-based approach. To sharpen my skills in property and event binding, I embarked on a project involving building a deck with two lists. English isn't my first language, but I'll do my best to explain clearly.

IMPORTANT: Since I'm keen on mastering this tool, could you please provide detailed explanations in your responses? If you have hints or solutions, I'm open to exploring them independently for learning purposes.

GOAL:

The aim is to have two lists (CardlistComponent and DecklistComponent) where clicking on an item in CardListComponent (or DecklistComponent) removes it from that list and adds it to the other list.

COMPONENTS :

  1. DeckbuilderComponent containing the two other components (the two lists)
  2. CardlistComponent (the first list)
  3. DecklistComponent (the second list)

ISSUE:

I can successfully remove an element from CardlistComponent, but I'm struggling to add the same element to DecklistComponent. I believe the problem lies in how I handle arrays in JavaScript.

DeckbuilderComponent (HTML) (Parent component)

<app-cardlist></app-cardlist>
<app-decklist
  (cardAdded)="onCardAdded($event)">
</app-decklist>

*DeckbuilderComponent (TS)* (Parent component) The issue might be related here as I've duplicated the logic of adding an item in the parent AND in DecklistComponent.

@Output() cardAdded = new EventEmitter<{name: string}>();

decklist: Card[] = [
new Card('CardC'),
new Card('CardD')
]

onCardAdded(element : HTMLLIElement){
this.decklist.push({
name: element.textContent
})
}

CardlistComponent

@Output() cardRemoved = new EventEmitter<{cardName: string}>();

cardlist: Card[] = [
new Card('CardA'),
new Card('CardB')
]

removeCard(indexCard: number, element: HTMLLIElement){
this.cardlist.splice(indexCard, 1)
this.cardRemoved.emit({
cardName: element.textContent
});

DecklistComponent - this list should receive the element removed from the first list

@Input() cardName: {name: string};

decklist: Card[] = [
new Card('CardC'),
new Card('CardD')
]

onCardAdded(element : HTMLLIElement){ 
this.decklist.push({
name: element.textContent
})
}

Here's the HTML code for my two components just in case.

DecklistComponent (HTML)

<div class="container">
<div class="col-xs-12">
    <ul class="list-group">
        <li
        *ngFor="let card of decklist; let indexCard=index"
        class="list-group-item"
        #cardName
        >
            <a href="#"  class="list-group-item list-group-item-action" >{{ card.name }}</a>
        </li>
    </ul>
</div>

CardlistComponent (HTML)

<div class="container">
<div class="col-xs-12">
    <ul class="list-group">
        <li *ngFor="let card of cardlist; let indexCard=index" class="list-group-item">
            <a href="#"
            (click)="removeCard(indexCard, card)"
            class="list-group-item list-group-item-action">{{ card.name }}</a>
        </li>
    </ul>
</div>

If there's anything else important that I missed mentioning, please feel free to share, and may your day be filled with enthusiastic coding =D

Answer №1

To enhance your application, consider structuring DeckbuilderComponent as a Container Component and

CardlistComponent, DecklistComponent
as Presentational Components.

source

Container Components: These components are responsible for fetching data from the service layer. Typically, the top-level component of a route serves as a Container Component, hence the naming convention

Presentational Components - these components simply receive data as input and handle its display on the UI. They also have the ability to emit custom events

<deck-list (remove)="removeAndMoveTo($event, deckList, cardList)" [items]="deckList"></deck-list>
<card-list (remove)="removeAndMoveTo($event, cardList, deckList)" [items]="cardList"></card-list>
<div class="container">
<div class="col-xs-12">
    <ul class="list-group">
        <li *ngFor="let card of cardlist; let indexCard=index" class="list-group-item">
            <a href="#"
            (click)="removeCard(card)"
            class="list-group-item list-group-item-action">{{ card.name }}</a>
        </li>
    </ul>
</div>
class CardlistComponent {

  @Output("remove") removeCardEmitter: EventEmitter<Card>;

  constructor() {
    this.removeCardEmitter = new EventEmitter();
  }

  removeCard(card: Card){
    this.removeCardEmitter.emit(card);
  };

}
class DeckbuilderComponent {

  cardList: Card[];
  decklist: Card[];

  constructor() {
    this.cardList = [
      new Card('CardA'),
      new Card('CardB')
    ];

    this.decklist = [
      new Card('CardC'),
      new Card('CardD')
    ];
  }

  removeAndMoveTo(card: Card, sourceList: Card[], targetList: Card[]) {
    this.sourceList = this.sourceList.filter(pr => pr.id === card.id);
    this.targetList.push(card);
  }
}

There are various methods to transfer elements between lists. Alternatively, each card could contain information on which group it belongs to, resulting in a simple filter '

[items]="list.filter(pr => pr.isInCardList)
'.

Another approach involving a single-list setup might utilize rxjs with an observable that can be divided using the partition operator.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The server will only respond with a 200 status code to an OPTIONS request

My current situation bears some resemblance to this inquiry, although there are some differences and no solutions provided. In my case, the backend is in Python and the front-end is Angular. The live server runs on Ngnix/Unix while development is on Windo ...

Executing installed packages using npm: A step-by-step guide

Recently, I have encountered a confusing issue in my coding journey. In Python, I got used to installing packages and using them right away without any hiccups. For example, with SpotDL, everything worked seamlessly. However, things took a different turn w ...

Issue when transferring properties of a component to a component constructed Using LoadingButton MUI

Check out my new component created with the LoadingButton MUI: view image description here I'm having issues passing props to my component: view image description here Dealing with a TypeScript problem here: view image description here I can resolv ...

Encountering Issues with TypeScript Strict in Visual Studio Code Problems Panel

I have discovered that I can optimize my TypeScript compilation process by utilizing the --strict flag, which enhances type checking and more. Typically, I compile my TypeScript code directly from Visual Studio Code with a specific task that displays the c ...

Discovering password values within JSON objects through the use of regular expressions

In my possession is a substantial JSON object that houses numerous JSON entities, many of which adhere to the following structure (key: sometext-v1.password, value: password for example: "apps":[ "settings": [ ...

What is the best way to incorporate dynamic infographics into an ionic app?

Looking to design unique infographics for my ionic app, similar to the ones seen here: Any recommendations on tools or strategies for creating these infographics? ...

steps for transferring a shallow copy of an array to a function

How can I adjust this code so that when I press each button, the console.log displays a different slice of the array instead of always showing me the last 20 elements? for (var i = 0; i < array.length; i++) { var b; var NewArr = []; ...

Updating the styles of React Native components using stylesheets

I've created a unique React component with the following structure: import { StyleSheet } from 'react-native'; import { Input, Item } from 'native-base'; import Icon from 'react-native-vector-icons/FontAwesome'; import { ...

What could be the reason for the crash caused by ngModel?

The usage of [(ngModel)] within a *ngFor-Loop is causing an endless loop and crashing the browser. This is how my HTML looks: <div class="container"> <div class="row" *ngFor="let item of controlSystemTargetViewModel.values; let index = i ...

Is there a way to automatically establish a connection with a BLE device when it is within

I am currently working on an app for IONIC 2 that requires my BLE device to automatically connect when in range. The app should be able to handle this whether it is in the background or foreground, and if the connection is lost, it should continuously se ...

I have set up a custom ag-grid three times within a single component, however, only the first instance is properly initialized while the other two instances are not initialized

I have developed a custom ag-grid for reusability in my project. Initially, when I initialize the custom ag-grid in one component, it works perfectly as shown below: example.html <html> <body> <input type="text"> <md-app-aggrid [c ...

Difficulties with managing button events in a Vue project

Just getting started with Vue and I'm trying to set up a simple callback function for button clicks. The callback is working, but the name of the button that was clicked keeps showing as "undefined." Here's my HTML code: <button class="w ...

Include baseHref in the sourceLocale configuration of Angular's internationalization feature

In order to set a baseHref for my default language in my Angular code (written in Portuguese), I need to make some adjustments. My goal is to use "ng serve --configuration=pt" to serve angular, and have the router display "http://localhost:4200/pt", simila ...

What is the best way to initialize a value asynchronously for React context API in the latest version of NextJS, version

Currently, I'm working on implementing the React context API in my NextJS e-commerce application to manage a user's shopping cart. The challenge I'm facing is how to retrieve the cart contents from MongoDB to initiate the cart context. This ...

Construct an outdated angular project from scratch

I'm facing an issue with an old Angular project that I'm trying to build. After pulling down the code, running npm install @angular/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="fc9f9095bccdd2cbd2c8">[email p ...

Transferring data from two child components back to the parent component

Within my web application, I have a parent component (A) and two children components (B, C). The parent component is responsible for maintaining the basic layout of the page, which remains consistent across all layouts. However, I need to dynamically swap ...

Does SharePoint Online support the .webmanifest format? What is the process for creating a Progressive Web Application in SharePoint Online using a supported webmanifest file?

Currently, I am in the process of developing a Progressive Web Application for SharePoint Online by utilizing the Angular 8 PWA build. The service worker and application are running smoothly; however, I have encountered an issue with loading the webmanifes ...

Error message "Uncaught MatSnackBar provider error encountered while attempting to execute 'ng test' command"

I've been encountering issues while trying to execute "ng test" on my Angular 4 project using Angular CLI. One of the problems I face is that the UI doesn't provide any useful feedback when a test fails, but fortunately, the console does display ...

Is there a compatibility issue between Nativescript and Angular Universal?

I am fairly new to Nativescript and recently attempted to incorporate Angular Universal building into an existing Angular 9/Nativescript application. However, I encountered the following error: [error] Error: Schematic "universal" not found in collect ...

The state may be modified, but the component remains unchanged

I've been tasked with implementing a feature on a specific website. The website has a function for asynchronously retrieving data (tickets), and I need to add a sorting option. The sorting process occurs on the server side, and when a user clicks a s ...