Removing elements in AngularJS using ngRepeat

Many have questioned how to implement item removal within the ngRepeat directive. Through my research, I discovered that it involves using ngClick to trigger a removal function with the item's $index.

However, I haven't been able to find an example that addresses multiple ngRepeats:

<div ng-controller="MyController">
    <div ng-repeat="email in user.emails">
        {{ email }} <a href>Remove</a>
    </div>

    <div ng-repeat="phone in user.phones">
        {{ phone }} <a href>Remove</a>
    </div>
</div>

To handle this scenario, I would need to create $scope.removePhone and $scope.removeEmail functions that are called using ngClick on the Remove anchor. However, I am seeking a more universal solution, especially since I have numerous pages with multiple ngRepeats.

I am considering writing a directive that can be placed on the Remove anchor and perform the following actions:

  1. Locate the nearest ngRepeat element among parent elements.
  2. Determine the collection being iterated over ('user.emails' or 'user.phones').
  3. Remove the element at the $index from that model.

This is how the updated markup might look:

<div ng-controller="MyController">
    <div ng-repeat="email in user.emails">
        {{ email }} <a href remove-directive="$index">Remove</a>
    </div>

    <div ng-repeat="phone in user.phones">
        {{ phone }} <a href remove-directive="$index">Remove</a>
    </div>
</div>

Is it possible to achieve what I'm looking for, and what approach should I take?

Current workaround

Presently, I am using a makeshift solution to address this issue. While it may not be ideal, it serves its purpose until I discover a better method.

  myAppModule.controller('MyController', function ($scope, $parse, $routeParams, User) {
    $scope.user = User.get({id: $routeParams.id});

    $scope.remove = function ($index, $event) {
      // TODO: Find a way to make a directive that does this. This is ugly. And probably very wrong.
      var repeatExpr = $($event.currentTarget).closest('[ng-repeat]').attr('ng-repeat');
      var modelPath  = $parse(repeatExpr.split('in')[1].replace(/^\s+|\s+$/g, ''));

      $scope.$eval(modelPath).splice($index, 1);
    };
  });

In the DOM:

<div ng-repeat="email in user.email" class="control-group">
  <label class="control-label">
    {{ "Email Address"|_trans }}
  </label>

  <div class="controls">
    <input type="text" ng-model="email.address">

    <span class="help-inline"><a href ng-click="remove($index, $event)">{{ "Delete"|_trans }}</a></span>
  </div>
</div>

Answer №1

One way to simplify your code is by creating a generic remove function that accepts an array and the item to be removed.

<div ng-app="" ng-controller="MyController">
    <div ng-repeat="email in emails">{{ email }} <a ng-click="remove(emails, $index)">Remove</a>
    </div>
    <div ng-repeat="phone in phones">{{ phone }} <a ng-click="remove(phones, $index)">Remove</a>
    </div>
</div>

$scope.remove = function(array, index){
    array.splice(index, 1);
}

Answer №2

Without JavaScript

<div ng-repeat="item in items" ng-init=items=[6,7,8,9,10]>
   <button ng-click="items.splice($index,1)">Delete me</button>      
</div>

Answer №3

<div ng-app="" ng-controller="MyController">
    <div ng-repeat="item in items as data">{{ item }} 
        <a ng-click="data.splice($index,1)">Delete</a>
    </div>
    <div ng-repeat="number in numbers as data">{{ number }} 
        <a ng-click="data.splice($index,1)">Remove</a>
    </div>
</div>

Answer №4

An easy and effective method that is compatible across different browsers involves utilizing the 'remove' utility function provided by the lodash library.

<div ng-repeat="phone in phones">{{ phone }} 
  <a ng-click="removeItem(phones, phone)">Remove</a>
</div>

In your controller, you need to define the following:

// Inject the lodash dependency

// Declare the method within scope
$scope.removeItem = function(list, item){
   // Use lodash.remove() to remove the specified item from the list
   lodash.remove(list,function(someItem) { return item === someItem});
}

If desired, you can also use indexes for removal. For more information, refer to https://lodash.com/docs#remove

Answer №5

In case you have utilized ng-repeat on an object rather than an array, here is what you should do:

<div ng-app="" ng-controller="MyController">
    <div ng-repeat="email in emails">{{ email }} 
      <a ng-click="remove(emails, email)">Remove</a>
    </div>
    <div ng-repeat="phone in phones">{{ phone }} 
      <a ng-click="remove(phones, phone)">Remove</a>
    </div>
</div>

$scope.remove = function(objects, o){
    delete object[o.id];
}

or a more concise version

<div ng-app="" ng-controller="MyController">
    <div ng-repeat="email in emails">{{ email }} 
      <a ng-click="delete emails[email.id]">Remove</a>
    </div>
    <div ng-repeat="phone in phones">{{ phone }} 
      <a ng-click="delete phones[phone.id]">Remove</a>
    </div>
</div>

Assumes that the objects are structured like this

var emails = {  '123' : { id : '123', .... }  };

var phones = {  '123' : { id : '123', .... }  };

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

Testing a function within a React functional component using jest.spyOn with React Testing Library can be accomplished with the following steps:

I'm currently working on a React component and I'm facing an issue with unit testing using React Testing Library. Specifically, I'm having trouble testing the handleClick function of the TestComponent using jest.spyOn(). Can anyone provide s ...

Concatenating strings with JavaScript

I am currently working on building a web page using a combination of html and javascript. I have a json file that provides inputs for some specific content I need to display. My main goal is to set up an address variable in order to show the Google Maps AP ...

An unexpected error occurred while attempting to retrieve data from Firebase and display it in another component

An error occurred: Unhandled Runtime Error Error: Element type is invalid - expected a string (for built-in components) or a class/function (for composite components) but got undefined. This could be due to forgetting to export your component from the defi ...

Incorporate various Vue.js components into the main parent component

I am currently utilizing Vue.js to create a user interface for my HTML5 game. I have a scenario where I want to define UI containers that essentially group other UI components and position them on the screen. Here's an example of what I'd like to ...

What are the steps to ensure that data retrieved from an API is accurately displayed in a table?

My current goal is to collect data from the crypto compare API and display it in a table format. Although I am able to generate the necessary elements and append them to the table body, I am facing an unusual issue. Each time I use a for loop to iterate th ...

Dynamic styles object for React components with inline styles

I have a styles object let styles = { step_div:{ height:'150px', } } I'm trying to display multiple div elements with different colors using React class Layout extends React.Component{ constructor(props) { super(props); ...

Focus on the iPad3 model specifically, excluding the iPad4

I am looking to apply specific CSS that works on iPad 3, but not on iPad 4, or vice versa. Currently, I am able to target both versions by using the following code: @media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and ( m ...

Javascript error: The variable calculator_test has not been defined

Why am I receiving an error message: Uncaught ReferenceError: calculator_test is not defined index.html: <!DOCTYPE html> <html> <body> <p>Click the button</p> <button onclick="calculator_test()">test</button> &l ...

What is the minimum number of lines that can be used for javascript code?

Currently, I am in the process of developing a custom JavaScript minifier. One question that has come up is whether it is necessary to insert line breaks after a certain number of characters on a single line, or if it even makes a difference at all? For i ...

Pug conditional elements not styling with CSS

Currently immersed in the world of Pug, node.js, and express as I build a web application. Facing hurdles when trying to style elements within Pug conditionals using CSS. For instance, consider this Pug snippet: div(id='outside') if authoris ...

Utilizing query parameters during the on-load event in AngularJS

Upon loading my AngularJS app, I aim to extract query parameters (http://myurl/?params=Resource1,Resource2,Resource3) from a URL and retrieve JSON resources based on these parameters (e.g., Resource1, Resource2, Resource3). Subsequently, once the three res ...

What is the best way to transition a connected component from a class-based to a functional component in TypeScript?

I'm in the process of switching from a class-based component to a functional component. This is a connected component that uses mapState. Here is my initial setup: import { connect } from 'react-redux' import { fetchArticles } from '. ...

React Native encounters issues with removing the reference to the callback attribute upon unmounting

Utilizing a component that I place in an array (of various sizes) and controlling individual components through refs, while adding refs to an object to keep track of each separately. constructor(props){ super(props); this.stamps = []; this.get ...

Max value determined by a variable within a for loop

UPDATE: Revised code provided. In my Node.js JavaScript project, I am creating a script to iterate through a dataset obtained by web scraping. The main goal of this algorithm is: 1) Examine the player table for the presence of the player's name in a ...

Applying a CSS class to certain rows following the modification of cell content

Currently, I am batch updating cell data by looping through selected items/rows. I am interested in adding a class to my rows after the update has been completed to indicate that they have been modified. Is there a way to achieve this without manually se ...

Having trouble toggling the navbar on and off in mobile. Error message: Unable to read parentnode of undefined

When I try to make my mobile navbar full screen on a mobile device, the hamburger button works as expected when clicked. Initially, all the links are displayed in full page view, but once I click on a link, it disappears and takes me to the respective sect ...

Locate all instances of words that begin with a certain character and are immediately followed by numbers within

I am searching for words that start with "mc" and are followed by digits only. let myString = "hi mc1001 hello mc1002 mc1003 mc1004 mc mca"; Expected output = [mc1001, mc1002, mc1003, mc1004] This is how I tackled it: const myRegEx = /(?:^|\s)mc(. ...

I'm wondering why my .focus() function is causing the cursor to move to the start of my contenteditable div?

I am currently developing a website for writing books, primarily using php. I have implemented a jQuery function that, upon clicking the "New Chapter" button, triggers an AJAX function along with various other JS/jQuery events. One of these events is inten ...

What is the best way to delay a method in vue.js?

In the tab element called competences, there is an input field with the reference search. <ul class="nav nav-tabs" id="myTab" role="tablist"> <li class="nav-item"> <a @click="competencesTabClick" aria-controls="Company" aria-sel ...

Angular form submission with action appending key-value pairs

My main objective was to create a form submission using the 'get' method, where key-value pairs are appended to the URI. I referred to http://www.w3schools.com/tags/att_form_method.asp, which explained how setting the form method as "get" should ...