ข้อผิดพลาดเชิงมุม ng-repeat“ ไม่อนุญาตให้ทำซ้ำใน repeater”


472

ฉันกำลังกำหนดตัวกรองแบบกำหนดเองดังนี้:

<div class="idea item" ng-repeat="item in items" isoatom>    
    <div class="section comment clearfix" ng-repeat="comment in item.comments | range:1:2">
        ....
    </div>
</div>

ในขณะที่คุณสามารถดู ng-repeat ที่มีการใช้ตัวกรองซ้อนอยู่ภายใน ng-repeat อื่น

ตัวกรองถูกกำหนดดังนี้:

myapp.filter('range', function() {
    return function(input, min, max) {
        min = parseInt(min); //Make string input int
        max = parseInt(max);
        for (var i=min; i<max; i++)
            input.push(i);
        return input;
    };
});

ฉันได้รับ:

ข้อผิดพลาด: ไม่อนุญาตให้ทำซ้ำใน repeater Repeater: แสดงความคิดเห็นใน item.comments | ช่วง: 1: 2 ngRepeatAction @ https://ajax.googleapis.com/ajax/libs/angularjs/1.1.4/an

คำตอบ:


955

วิธีการแก้ปัญหามีการอธิบายจริงที่นี่: http://www.anujgakhar.com/2013/06/15/duplicates-in-a-repeater-are-not-allowed-in-angularjs/

AngularJS ไม่อนุญาตการทำซ้ำในคำสั่ง ng-repeat ซึ่งหมายความว่าหากคุณพยายามทำสิ่งต่อไปนี้คุณจะได้รับข้อผิดพลาด

// This code throws the error "Duplicates in a repeater are not allowed.
// Repeater: row in [1,1,1] key: number:1"
<div ng-repeat="row in [1,1,1]">

อย่างไรก็ตามการเปลี่ยนรหัสข้างต้นเล็กน้อยเพื่อกำหนดดัชนีเพื่อตรวจสอบความไม่เหมือนใครด้านล่างจะทำให้มันทำงานได้อีกครั้ง

// This will work
<div ng-repeat="row in [1,1,1] track by $index">

เอกสารอย่างเป็นทางการอยู่ที่นี่: https://docs.angularjs.org/error/ngRepeat/dupes


48
ฉันต้องการพูดถึงว่าคุณสามารถใช้คุณสมบัติการติดตามแบบกำหนดเองเพื่อกำหนดเอกลักษณ์ไม่เพียงแค่ $ index เนื่องจากในสถานการณ์นี้วัตถุไม่มีคุณสมบัติอื่นใดที่ทำงานได้ดี สาเหตุข้อผิดพลาดนี้เกิดขึ้นคือแองกูลาร์กำลังใช้พจนานุกรมเพื่อจัดเก็บ id ของรายการเป็นคีย์ที่มีค่าเป็นการอ้างอิง DOM จากรหัส (บรรทัด 15402 ใน angular.js) ดูเหมือนว่าพวกเขากำลังแคชองค์ประกอบก่อนหน้านี้พบองค์ประกอบ DOM ตามคีย์ของพวกเขาเป็นการเพิ่มประสิทธิภาพประสิทธิภาพ เนื่องจากพวกเขาต้องการคีย์ที่ไม่ซ้ำกันพวกเขาจะโยนข้อผิดพลาดนี้อย่างชัดเจนเมื่อพวกเขาพบกุญแจที่ซ้ำกันในบรรทัด 15417
devshorts

16
<div ng-repeat="row in [1,1,1,2,2] |filter: 2 track by $index" >ต้องมี "ตัวกรองการค้นหา" ก่อน "ติดตามโดย $ index"
Zhe Hu

21
Yikes สิ่งที่น่ารังเกียจในการออกแบบของ Angular มันจะเป็นเรื่องง่ายมากที่จะพลาดปัญหานี้ในระหว่างการพัฒนาและทดสอบเพราะอาร์เรย์ของคุณไม่เคยมีรายการที่ซ้ำกันเท่านั้นที่จะทำให้แอปของคุณระเบิดในการผลิตเมื่อได้รับการสัมผัสซ้ำในครั้งแรก ฉันได้สร้างแอพเชิงมุมมาก่อนโดยไม่ทราบว่ามีข้อ จำกัด "ไม่หลอก" ตอนนี้ฉันพบว่าตัวเองกำลังคิดและสงสัยว่าฉันเขียนรหัสที่ไม่สมบูรณ์หรือไม่
Mark Amery

แอพของเรามีการระเบิดเนื่องจากเหตุผลนี้และฉันไม่ใช่นักพัฒนาเชิงมุม$indexตัวแปรมีอยู่ที่อื่นหรือไม่?
Chang Zhao

โปรดทราบว่ามีข้อแม้หากคุณอัปเดตองค์ประกอบอาร์เรย์ของคุณในภายหลังจะไม่รวบรวมแท็ก DOM ใหม่แทนการแสดงข้อมูลเก่า คุณสามารถใช้track by ($index + ':' + row)เพื่อจะอัปเดตแต่ละรายการ<ng-repeat>เมื่อใดก็ตามที่มีการอัปเดตข้อมูลรวมถึงเมื่อมีการเพิ่มองค์ประกอบใหม่โดยไม่ต้องสะดุดคู่กัน
Hashbrown

45

สำหรับผู้ที่คาดหวังว่า JSON และยังคงได้รับข้อผิดพลาดเดียวกันตรวจสอบให้แน่ใจว่าคุณได้วิเคราะห์ข้อมูลของคุณ:

$scope.customers = JSON.parse(data)

4
สิ่งนี้ไม่ได้ผลสำหรับฉันฉันคาดว่า json หลังจากใช้บริการ $ http แต่ SyntaxError: โทเค็นที่ไม่คาดคิด o ที่ Object.parse (native)
aurelius

1
@ Fergus ดีใจที่ได้ผลสำหรับคุณ อย่างไรก็ตามตรวจสอบให้แน่ใจว่าได้ค้นหาความแตกต่างระหว่าง JSON.parse และ JSON.stringify เว้นแต่คุณจะทราบแล้ว
helpfulBee

2
บ้า. หลังจากหลายเดือนของการทำงานอย่างถูกต้อง Angular ตัดสินใจทันทีว่า JSON กลับมาจาก $ http () ไม่ใช่ JSON อีกต่อไป การแยกวิเคราะห์อย่างชัดเจนแก้ไขปัญหานี้ให้กับเรา ขอบคุณสำหรับคำแนะนำที่บ้า
Eric L.

12

ฉันมีปัญหาในโครงการของฉันซึ่งฉันใช้ ng-repeat track โดย $ index แต่ผลิตภัณฑ์ไม่ได้รับการสะท้อนเมื่อข้อมูลมาจากฐานข้อมูล รหัสของฉันเป็นดังนี้:

<div ng-repeat="product in productList.productList track by $index">
  <product info="product"></product>
 </div>

ในรหัสข้างต้นผลิตภัณฑ์เป็นคำสั่งแยกต่างหากเพื่อแสดงผลิตภัณฑ์ แต่ฉันรู้ว่า $ index ทำให้เกิดปัญหาเมื่อเราส่งข้อมูลออกจากขอบเขต ดังนั้นข้อมูลสูญหายและ DOM ไม่สามารถอัปเดตได้

ฉันพบวิธีแก้ปัญหาโดยใช้ product.id เป็นกุญแจสำคัญใน ng-repeat เช่นด้านล่าง:

<div ng-repeat="product in productList.productList track by product.id">
  <product info="product"></product>
 </div>

แต่รหัสข้างต้นล้มเหลวอีกครั้งและเกิดข้อผิดพลาดด้านล่างเมื่อมีผลิตภัณฑ์มากกว่าหนึ่งรายการที่มีรหัสเดียวกัน:

angular.js: 11706 ข้อผิดพลาด: [ngRepeat: dupes] ไม่อนุญาตให้ทำซ้ำใน repeater ใช้นิพจน์ 'ติดตามโดย' เพื่อระบุคีย์เฉพาะ ทบทวน

ดังนั้นในที่สุดฉันก็แก้ปัญหาโดยการทำคีย์เฉพาะแบบไดนามิกของ ng-repeat เช่นด้านล่าง:

<div ng-repeat="product in productList.productList track by (product.id + $index)">
  <product info="product"></product>
 </div>

นี่เป็นการแก้ไขปัญหาของฉันและหวังว่าสิ่งนี้จะช่วยคุณในอนาคต


1
แน่นอนtrack by $indexจะดีกว่าtrack by (product.id + $index)? สำหรับสิ่งหนึ่งtrack by $indexนั้นง่ายกว่าและอีกอย่างหนึ่งคุณอาจไม่มีหลักประกันใด ๆ เลยว่าคุณค่าของมัน(product.id + $index)จะไม่ซ้ำกัน ตัวอย่างเช่นหากอาร์เรย์ของคุณเริ่มต้นด้วยผลิตภัณฑ์ที่มีid5 และหลังจากนั้นมีผลิตภัณฑ์ที่มีid4 ค่าของ(product.id + $index)ทั้งคู่จะเท่ากับ 5 (5 + 0 สำหรับผลิตภัณฑ์แรก 4 + 1 สำหรับวินาที) และคุณจะยังคงได้รับซ้ำใน repeater จะไม่ได้รับอนุญาตข้อผิดพลาด
Mark Amery

1
ฉันเห็นด้วยกับว่า $ index นั้นง่ายกว่า แต่วิธีการข้างต้นนั้นใช้งานได้สำหรับฉันในการแก้ไขปัญหาทั้งหมดที่ฉันเผชิญกับ $ index และในกรณีของฉัน product.id เป็นตัวอักษรและตัวเลขดังนั้น (product.id + $ index) ไม่สามารถทำซ้ำในกรณีใด ๆ ดังนั้นแนวคิดที่อยู่เบื้องหลังการแก้ปัญหานี้ก็คือถ้าหากดัชนี $ ก่อให้เกิดปัญหาใด ๆ ในกรณีนี้เราสามารถใช้ตรรกะใด ๆ กับแทร็กที่สร้างรหัสไม่ซ้ำกัน
Mahima Agrawal

5

คุณต้องการให้ตัวกรอง "ช่วง" ของคุณทำอะไร

นี่คือตัวอย่างการทำงานของสิ่งที่ฉันคิดว่าคุณกำลังพยายามทำ: http://jsfiddle.net/evictor/hz4Ep/

HTML:

<div ng-app="manyminds" ng-controller="MainCtrl">
  <div class="idea item" ng-repeat="item in items" isoatom>    
    Item {{$index}}
    <div class="section comment clearfix" ng-repeat="comment in item.comments | range:1:2">
      Comment {{$index}}
      {{comment}}
    </div>
  </div>
</div>

JS:

angular.module('manyminds', [], function() {}).filter('range', function() {
    return function(input, min, max) {
        var range = [];
        min = parseInt(min); //Make string input int
        max = parseInt(max);
        for (var i=min; i<=max; i++)
            input[i] && range.push(input[i]);
        return range;
    };
});

function MainCtrl($scope)
{
    $scope.items = [
        {
            comments: [
                'comment 0 in item 0',
                'comment 1 in item 0'
            ]
        },
        {
            comments: [
                'comment 0 in item 1',
                'comment 1 in item 1',
                'comment 2 in item 1',
                'comment 3 in item 1'
            ]
        }
    ];
}

1

หากบังเอิญข้อผิดพลาดนี้เกิดขึ้นเมื่อทำงานกับ SharePoint 2010: เปลี่ยนชื่อนามสกุลไฟล์. json ของคุณและให้แน่ใจว่าได้อัปเดตเส้นทาง restService ของคุณ ไม่จำเป็นต้องมี "track by $ index" เพิ่มเติม

โชคดีที่ฉันถูกส่งต่อลิงก์นี้ไปยังเหตุผลนี้:

.json กลายเป็นประเภทไฟล์สำคัญใน SP2010 SP2010 รวมถึงจุดสิ้นสุดเว็บเซอร์รับรอง ตำแหน่งของไฟล์เหล่านี้คือ 14hive \ isapi โฟลเดอร์ นามสกุลของไฟล์เหล่านี้คือ. json นั่นคือเหตุผลที่ทำให้เกิดข้อผิดพลาดดังกล่าว

"ใส่ใจเฉพาะเนื้อหาของไฟล์ json คือ json - ไม่ใช่นามสกุลไฟล์"

เมื่อเปลี่ยนนามสกุลไฟล์แล้วควรตั้งค่าทั้งหมด


0

ในกรณีที่เกิดเหตุการณ์นี้กับคนอื่นฉันกำลังบันทึกไว้ที่นี่ฉันได้รับข้อผิดพลาดนี้เนื่องจากฉันตั้งค่า ng-model ผิดกับอาร์เรย์ ng-repeat ซ้ำโดยไม่ได้ตั้งใจ:

 <select ng-model="list_views">
     <option ng-selected="{{view == config.list_view}}"
         ng-repeat="view in list_views"
         value="{{view}}">
         {{view}}
     </option>
 </select>

แทน:

<select ng-model="config.list_view">
     <option ng-selected="{{view == config.list_view}}"
         ng-repeat="view in list_views"
         value="{{view}}">
         {{view}}
     </option>
 </select>

ฉันตรวจสอบอาร์เรย์และไม่มีการซ้ำซ้อนเพียงตรวจสอบตัวแปรของคุณอีกครั้ง


0

ไม่อนุญาตให้ทำซ้ำใน repeater ใช้นิพจน์ 'ติดตามโดย' เพื่อระบุคีย์เฉพาะ

Repeater: {0}, Duplicate key: {1}, Duplicate value: {2}

ตัวอย่าง

<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="utf-8" />
    <title></title>
    <script src="angular.js"></script>

</head>
<body>
    <div ng-app="myApp" ng-controller="personController">
        <table>
            <tr> <th>First Name</th> <th>Last Name</th> </tr>
            <tr ng-repeat="person in people track by $index">
                <td>{{person.firstName}}</td>
                <td>{{person.lastName}}</td>
                <td><input type="button" value="Select" ng-click="showDetails($index)" /></td>
            </tr>

        </table> <hr />
        <table>
            <tr ng-repeat="person1 in items track by $index">
                <td>{{person1.firstName}}</td>
                <td>{{person1.lastName}}</td>
            </tr>
        </table>
        <span>   {{sayHello()}}</span>
    </div>
    <script> var myApp = angular.module("myApp", []);
        myApp.controller("personController", ['$scope', function ($scope)
        { 
            $scope.people = [{ firstName: "F1", lastName: "L1" },
                { firstName: "F2", lastName: "L2" }, 
                { firstName: "F3", lastName: "L3" }, 
                { firstName: "F4", lastName: "L4" }, 
                { firstName: "F5", lastName: "L5" }]
            $scope.items = [];
            $scope.selectedPerson = $scope.people[0];
            $scope.showDetails = function (ind) 
            { 
                $scope.selectedPerson = $scope.people[ind];
                $scope.items.push($scope.selectedPerson);
            }
            $scope.sayHello = function ()
            {
                return $scope.items.firstName;
            }
        }]) </script>
</body>
</html>

2
โปรดประกาศการเชื่อมโยงไปยังลิงก์ใด ๆ ที่คุณโพสต์
Draken


-1

JSONคำตอบของฉันเป็นเช่นนี้:

{"items": 
  &nbsp;[
    &nbsp;&nbsp;{
      "index": 1,
      "name": "Samantha",
      "rarity": "Scarborough",
      "email": "maureen@sykes.mk"
    },
    &nbsp;&nbsp;{
      "index": 2,
      "name": "Amanda",
      "rarity": "Vick",
      "email": "jessica@livingston.mv"
    }]
}

ดังนั้นฉันเคยng-repeat = "item in variables.items" แสดงมัน


-1

ไม่อนุญาตให้ทำซ้ำใน repeater ใช้นิพจน์ 'ติดตามโดย' เพื่อระบุคีย์เฉพาะ Repeater: sdetail ใน mydt, คีย์ซ้ำ: string:, ค่าซ้ำ:

ฉันประสบข้อผิดพลาดนี้เพราะฉันเขียนชื่อฐานข้อมูลผิดใน php api part ของฉัน ......

ดังนั้นข้อผิดพลาดนี้อาจเกิดขึ้นเมื่อคุณดึงข้อมูลจากฐานข้อมูลที่มีชื่อคุณเขียนไม่ถูกต้อง

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.