ng-clickを使用して配列からアイテムまたはオブジェクトを削除するにはどうすればよいですか?


261

ボタンがクリックされたときにアイテムを削除できるようにする関数を記述しようとしていますが、関数と混同していると思います$digest。使用しますか?

HTMLとapp.js:

<ul ng-repeat="bday in bdays">
  <li>
    <span ng-hide="editing" ng-click="editing = true">{{bday.name}} | {{bday.date}}</span>
    <form ng-show="editing" ng-submit="editing = false">
      <label>Name:</label>
      <input type="text" ng-model="bday.name" placeholder="Name" ng-required/>
      <label>Date:</label>
      <input type="date" ng-model="bday.date" placeholder="Date" ng-required/>
      <br/>
      <button class="btn" type="submit">Save</button>
      <a class="btn" ng-click="remove()">Delete</a>
    </form>
  </li>
</ul>

$scope.remove = function(){
  $scope.newBirthday = $scope.$digest();
};

2
$ digestは必要ありません。これは、Angularのダイジェストループを開始するために使用されるためです(ng-clickのため、すでにダイジェストループに入っています)。配列から項目を削除しようとしていますか?
Mark Rajcok 2013年

@MarkRajcok :)はい、それは私がやろうとしていることです
ジェス・マッケンジー

remove()中にng-clickあなたが持っている方法、それは何のコンテキストを持っていません。マークアップに詳細を追加して、何が削除されるのか、それが内ng-repeatにあるのか、どこから削除されるのか、またはどのような動作にするのかを示すremove()
charlietfl

@charlietfl ng-repeat内にあります私は質問を更新しました
Jess McKenzie

回答:


552

アイテムを削除するには、配列から削除する必要があり、bdayアイテムをマークアップで削除関数に渡すことができます。次に、コントローラで項目のインデックスを検索し、配列から削除します

<a class="btn" ng-click="remove(item)">Delete</a>

次にコントローラで:

$scope.remove = function(item) { 
  var index = $scope.bdays.indexOf(item);
  $scope.bdays.splice(index, 1);     
}

Angularはbdaysアレイへの変更を自動的に検出し、更新を行いますng-repeat

デモ:http : //plnkr.co/edit/ZdShIA?p=preview

編集:サーバーでライブ更新を行う場合、作成したサービスを使用して、サーバーを$resource更新すると同時にアレイの更新を管理する場合


62
$indexテンプレートでリストがフィルタリングされている場合、直接使用するとバグが発生する可能性があります。これはテンプレートです。それは使用する方が安全ですng-click='remove(bday)'、その後arr.splice(arr.indexOf(bday),1);
UmurKontacı

6
メソッド内で「this」を使用できるため、$ indexを渡す必要はありません。$ scope.remove = function(){$ scope.bdays.splice(this。$ index、1); }
matchdav 2013

1
@matthewdavidson this is undefined。Plunker / jsfiddle?
Tjorriemorrie 2013

11
.indexOf(item)見つからない場合は-1を返します。これを確認しないと、配列の最後の項目が削除される可能性があります。
ベンワイルド


54

これは正解です。

<a class="btn" ng-click="remove($index)">Delete</a>
$scope.remove=function($index){ 
  $scope.bdays.splice($index,1);     
}

@charlietflの答えで。あなた$indexはパラメーターとして渡すので間違っていると思いますが、コントローラーではウィッシュを代わりに使用します。私が間違っている場合は私を修正してください:)


関数は$なしでインデックスを受け入れることができ、それでも機能しますが、両方の答えは同等であるように見えます。
svarog 2014年

これが正解です。 indexOfIE9 +の場合にのみ機能します
levi

17
これは、ng-repeatにorderByまたはフィルターがある場合は機能しません
Joan-Diego Rodriguez

$ indexによるトラックを使用した場合、これはより適切に機能します
Ankit Balyan

@ Joan-DiegoRodriguezフィルター/注文がある場合、どのように機能させますかXMLilley's Answer
jamesmstone

26

ng-repeat内にいる場合

ワンライナーオプションを使用できます

    <div ng-repeat="key in keywords"> 
        <button ng-click="keywords.splice($index, 1)">

            {{key.name}}
        </button>
    </div>

$index 内部の配列の現在のインデックスを表示するために角度によって使用されます ng-repeat


1
私はこのライナーを気に入って使用しました
etoricky

24

$index基本的なケースでは、使用は完全にうまく機能し、@ charlietflの答えは素晴らしいです。しかし、時には$index十分ではありません。

単一の配列があり、2つの異なるng-repeatで提示していると想像してください。それらのng-repeatの1つは、真実のプロパティを持つオブジェクトに対してフィルタリングされ、もう1つは偽のプロパティに対してフィルタリングされます。単一の元のアレイから派生した2つの異なるフィルター済みアレイが提示されています。(または、視覚化に役立つ場合:おそらく単一の配列の人々がいて、その配列の女性に1つのng-repeat 、同じ配列の男性にもう1つng-repeatが必要です。)あなたの目標:確実に削除するフィルターされた配列のメンバーからの情報を使用した元の配列。

これらのフィルターされた配列のそれぞれで、$ indexは元の配列内のアイテムのインデックスにはなりません。これは、フィルターされたサブ配列のインデックスになります。そのため、元のpeople配列で人のインデックスを確認することはできません。womenまたは、menサブ配列から$ indexだけがわかります。それを使用して削除してみてください。そうすれば、必要な場所を除いて、どこからでもアイテムが消えます。何をすべきか?

幸運なことに、データモデルを使用して各オブジェクトに一意の識別子が含まれている場合は、$ indexの代わりにそれを使用して、オブジェクトとspliceメイン配列からオブジェクトを見つけます。(以下の私の例を使用しますが、その一意の識別子を使用します)。

Angularは、実際にはngが繰り返される配列(メインの元の配列)の各項目を、という一意のプロパティで増強します$$hashKey。元の配列で、$$hashKey削除する項目の一致を検索し、その方法で取り除くことができます。

これ$$hashKeyは実装の詳細であり、ng-repeatの公開されたAPIには含まれていません。彼らはいつでもそのプロパティのサポートを削除できます。しかし、おそらくそうではありません。:-)

$scope.deleteFilteredItem = function(hashKey, sourceArray){
  angular.forEach(sourceArray, function(obj, index){
    // sourceArray is a reference to the original array passed to ng-repeat, 
    // rather than the filtered version. 
    // 1. compare the target object's hashKey to the current member of the iterable:
    if (obj.$$hashKey === hashKey) {
      // remove the matching item from the array
      sourceArray.splice(index, 1);
      // and exit the loop right away
      return;
    };
  });
}

で呼び出す:

ng-click="deleteFilteredItem(item.$$hashKey, refToSourceArray)"

編集:$$hashKeyモデル固有のプロパティ名の代わりにキーを使用するこのような関数を使用すると、この関数をさまざまなモデルやコンテキストで再利用できるという大きな追加の利点もあります。配列参照とアイテム参照を指定してください。これで問題なく動作します。


10

私は通常そのようなスタイルで書いています:

<a class="btn" ng-click="remove($index)">Delete</a>


$scope.remove = function(index){
  $scope.[yourArray].splice(index, 1)
};

これが$ scopeと[yourArray]の間にドット(。)を使用するのに役立つことを願っています


(index、1)の「1」の意味は何ですか
ShibinRagh

@ShibinRagh deleteCountです。 削除する古い配列要素の数を示す整数。deleteCountが0の場合、要素は削除されません。この場合、少なくとも1つの新しい要素を指定する必要があります。deleteCountがstartから始まる配列に残っている要素の数より大きい場合、配列の最後までのすべての要素が削除されます。 Array.prototype.splice()ドキュメンテーション
ᴍᴀᴛᴛʙᴀᴋᴇʀ15年

9

受け入れられた回答に基づいて、これはで動作しngRepeatfilter期待をより適切に処理します。

コントローラ:

vm.remove = function(item, array) {
  var index = array.indexOf(item);
  if(index>=0)
    array.splice(index, 1);
}

見る:

ng-click="vm.remove(item,$scope.bdays)"

コントローラーの$ scope.vmに「削除」を割り当てなかったため、このコードは機能しませんでした。これを行った場合... $ scope.vm = {remove:function(){...}}なら、そうなります。
ジャスティンルッソ

4

コントローラなしの実装。

<!DOCTYPE html>
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<body>

<script>
  var app = angular.module("myShoppingList", []); 
</script>

<div ng-app="myShoppingList"  ng-init="products = ['Milk','Bread','Cheese']">
  <ul>
    <li ng-repeat="x in products track by $index">{{x}}
      <span ng-click="products.splice($index,1)">×</span>
    </li>
  </ul>
  <input ng-model="addItem">
  <button ng-click="products.push(addItem)">Add</button>
</div>

<p>Click the little x to remove an item from the shopping list.</p>

</body>
</html>

splice()メソッドは、項目を配列に追加したり、配列から削除したりします。

array.splice(index, howmanyitem(s), item_1, ....., item_n)

index:必須。アイテムを追加/削除する位置を指定する整数。配列の末尾からの位置を指定するには、負の値を使用します。

howmanyitem(s):オプション。削除するアイテムの数。0に設定すると、アイテムは削除されません。

item_1、...、item_n:オプション。配列に追加される新しいアイテム


1
これが正解です。単純なJavaScript呼び出しを実行するためにコントローラーに依存するのはなぜですか?
Elle Fie

3

コントローラのメソッドを呼び出す必要があることに同意しません。実際の機能ではサービスを使用し、スケーラビリティとモジュール性のために機能のディレクティブを定義する必要があります。また、ディレクティブに挿入するサービスの呼び出しを含むクリックイベントを割り当てる必要があります。

たとえば、HTMLで...

<a class="btn" ng-remove-birthday="$index">Delete</a>

次に、ディレクティブを作成します...

angular.module('myApp').directive('ngRemoveBirthday', ['myService', function(myService){
    return function(scope, element, attrs){
        angular.element(element.bind('click', function(){
            myService.removeBirthday(scope.$eval(attrs.ngRemoveBirthday), scope);  
        };       
    };
}])

その後、あなたのサービスで...

angular.module('myApp').factory('myService', [function(){
    return {
        removeBirthday: function(birthdayIndex, scope){
            scope.bdays.splice(birthdayIndex);
            scope.$apply();
        }
    };
}]);

このようにコードを適切に記述すると、コードを再構築する必要なく、将来の変更を非常に簡単に記述できます。これは適切に構成されており、カスタムディレクティブを使用してバインドすることにより、カスタムクリックイベントを正しく処理しています。

たとえば、クライアントが「サーバーを呼び出してパンを作ってから、モーダルをポップアップするようにしましょう」と言ったとします。HTMLやコントローラーのメソッドコードを追加または変更する必要なく、サービス自体に簡単にアクセスできます。コントローラーに1行しかない場合は、最終的にサービスを使用する必要があります。これは、機能をクライアントが要求するより重いものに拡張するためです。

また、別の場所に別の[削除]ボタンが必要な場合は、ページの任意の要素に簡単に割り当てることができるディレクティブ属性( 'ng-remove-birthday')があります。これにより、モジュール化され、再利用可能になります。これは、Angular 2.0のHEAVY Webコンポーネントパラダイムを扱うときに便利です。2.0にはコントローラはありません。:)

ハッピー開発!!!



0

アイテムにIDまたは特定のフィールドがある場合は、filter()を使用できます。Where()のように動作します。

<a class="btn" ng-click="remove(item)">Delete</a>

コントローラ内:

$scope.remove = function(item) { 
  $scope.bdays = $scope.bdays.filter(function (element) {
                    return element.ID!=item.ID
                });
}

0
Pass the id that you want to remove from the array to the given function 

コントローラーから(機能は同じコントローラーに含めることができますが、サービス内に保持することを優先します)

    function removeInfo(id) {
    let item = bdays.filter(function(item) {
      return bdays.id=== id;
    })[0];
    let index = bdays.indexOf(item);
    data.device.splice(indexOfTabDetails, 1);
  }
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.