AngularJS - วิธีรับการอ้างอิงผลลัพธ์ที่กรองด้วย ngRepeat


129

ฉันใช้คำสั่ง ng-repeat กับตัวกรองดังนี้:

ng-repeat="item in items | orderBy:'order_prop' | filter:query | limitTo:4"

และฉันสามารถเห็นผลลัพธ์ที่แสดงได้ดี ตอนนี้ฉันต้องการเรียกใช้ตรรกะบางอย่างกับผลลัพธ์นั้นในคอนโทรลเลอร์ของฉัน คำถามคือฉันจะคว้าการอ้างอิงรายการผลลัพธ์ได้อย่างไร

ปรับปรุง:


เพื่อชี้แจง: ฉันกำลังพยายามสร้างการเติมข้อความอัตโนมัติฉันมีข้อมูลนี้:

<input id="queryInput" ng-model="query" type="text" size="30" placeholder="Enter query">

จากนั้นผลการกรอง:

<ul>
   <li  ng-repeat="item in items | orderBy:'order_prop' | filter:query | limitTo:4">{{item.name}}</li>
</ul>

ตอนนี้ฉันต้องการนำทางผลลัพธ์และเลือกหนึ่งในรายการ

คำตอบ:


271

อัปเดต : นี่เป็นวิธีที่ง่ายกว่าที่เคยมีมา

 <input ng-model="query">
 <div ng-repeat="item in (filteredItems = (items | orderBy:'order_prop' | filter:query | limitTo:4))">
   {{item}}
 </div>

จากนั้น$scope.filteredItemsสามารถเข้าถึงได้


ขอบคุณสำหรับการตอบกลับโปรดดูการอัปเดตของฉัน คุณจะนำไปใช้อย่างไรโปรดทราบว่าฉันได้รับรายการทั้งหมดใน init
Shlomi Schwartz

สุดยอดมากขอบคุณสำหรับสิ่งนั้น ฉันหวังว่ามันจะเป็นคุณสมบัติที่สร้างขึ้นใน NG
Shlomi Schwartz

3
ปัญหาของวิธีนี้คือถ้าคุณดูทรัพย์สินที่ได้รับมอบหมายคุณจะจบลงด้วยการสแปม $ digests (หนึ่งครั้งต่อการวนซ้ำ) ... อาจมีวิธีหลีกเลี่ยงสิ่งนี้บ้าง?
Juho Vepsäläinen

1
ถ้าฉันดูวัตถุการค้นหาและ console.log filteredItemsฉันมักจะได้รับข้อมูลหนึ่งตัวกรองในภายหลัง ไม่ใช่ผลลัพธ์ของตัวกรองที่เพิ่งเปลี่ยน แต่เป็นผลจากการเปลี่ยนแปลงก่อนหน้านี้ ความคิดใด ๆ ?
ProblemsOfSumit

4
ใครช่วยอธิบายหน่อยได้ไหมว่าทำไมถึงได้ผล ฉันเข้าใจว่าตัวแปรจาก $ ขอบเขตสามารถเข้าถึงได้ในขอบเขตการทำซ้ำ (การสืบทอดขอบเขต) แต่ในทางกลับกัน? อย่างไร? ชื่นชมเอกสารบางอย่าง ขอบคุณ
dalvarezmartinez1

30

นี่คือโซลูชันของ Andy Joslin รุ่นกรอง

อัปเดต: การเปลี่ยนแปลงอย่างรวดเร็ว ตั้งแต่เวอร์ชัน 1.3.0-beta.19 (คอมมิตนี้ ) ตัวกรองไม่มีบริบทและthisจะถูกผูกไว้กับขอบเขตส่วนกลาง คุณสามารถส่งบริบทเป็นอาร์กิวเมนต์หรือใช้ไวยากรณ์นามแฝงใหม่ในngRepeat , 1.3.0-beta.17 +

// pre 1.3.0-beta.19
yourModule.filter("as", function($parse) {
  return function(value, path) {
    return $parse(path).assign(this, value);
  };
});

// 1.3.0-beta.19+
yourModule.filter("as", function($parse) {
  return function(value, context, path) {
    return $parse(path).assign(context, value);
  };
});

แล้วในมุมมองของคุณ

<!-- pre 1.3.0-beta.19 -->
<input ng-model="query">
<div ng-repeat="item in items | orderBy:'order_prop' | filter:query | limitTo:4 | as:'filteredItems'">
 {{item}}
</div>

<!-- 1.3.0-beta.19+ -->
<input ng-model="query">
<div ng-repeat="item in items | orderBy:'order_prop' | filter:query | limitTo:4 | as:this:'filteredItems'">
 {{item}}
</div>

<!-- 1.3.0-beta.17+ ngRepeat aliasing -->
<input ng-model="query">
<div ng-repeat="item in items | orderBy:'order_prop' | filter:query | limitTo:4 as filteredItems">
 {{item}}
</div>

$scope.filteredItemsซึ่งจะช่วยให้คุณสามารถเข้าถึง


ขอบคุณ! คุณช่วยอธิบายได้ไหมว่ารหัสตัวกรองทำงานอย่างไร ฉันไม่คุ้นเคยกับ $ parse และเอกสารเชิงมุมไม่ได้ช่วยฉันถอดรหัสว่าตัวกรองของคุณทำงานอย่างไร
Magne

2
@ มาญไม่มีปัญหา! โปรดตรวจสอบการอัปเดตเนื่องจากอาจช่วยให้คุณไม่ต้องเจ็บปวดและทรมานในระหว่างเดินทาง ในการตอบคำถามของคุณโดยย่อ$parseคือคอมไพเลอร์นิพจน์ของ Angular .. ตัวอย่างเช่นจะใช้สตริง "some.object.property" และส่งคืนฟังก์ชันที่อนุญาตให้คุณกำหนดหรือรับค่าในพา ธ ดังกล่าวสำหรับค่าที่ระบุ บริบท. ฉันใช้มันเพื่อตั้งค่าผลการกรองในขอบเขต $ ที่นี่โดยเฉพาะ ฉันหวังว่านี้ตอบคำถามของคุณ.
kevinjamesus86

23

ลองทำสิ่งนี้ปัญหาของ ng-repeat คือมันสร้างขอบเขตลูกเนื่องจากคุณไม่สามารถเข้าถึงได้

filteritems

จากคอนโทรลเลอร์

<li ng-repeat="doc in $parent.filteritems = (docs | filter:searchitems)" ></li>

16

ปรับปรุง:

แม้หลังจาก 1.3.0 ถ้าคุณต้องการที่จะใส่ไว้ในขอบเขตของตัวควบคุมหรือผู้ปกครองที่คุณไม่สามารถทำเช่นนั้นกับเป็นไวยากรณ์ ตัวอย่างเช่นหากฉันมีรหัสต่อไปนี้:

<div>{{labelResults}}</div>
<li ng-repeat="label in (labels | filter:query | as labelResults)">
</div>

ข้างต้นจะไม่ทำงาน วิธีที่จะไปรอบ ๆ มันคือการใช้$ parentดังนี้:

<li ng-repeat="label in ($parent.labelResults = (labels | filter:query))">

โปรดทราบว่าหากคุณมีขีด จำกัด ในการกรองสิ่งนี้ จะไม่ปรากฏใน $ parent.labelResults
Zack

ถ้าฉันconsole.log labelResultsมักจะได้รับข้อมูลหนึ่งตัวกรองในภายหลัง ไม่ใช่ผลลัพธ์ของตัวกรองที่เพิ่งเปลี่ยน แต่เป็นผลจากการเปลี่ยนแปลงก่อนหน้านี้ คุณไม่มีปัญหานี้หรือ?
Anna

10

ฉันคิดวิธีแก้ปัญหาของ Andy ในเวอร์ชันที่ค่อนข้างดีกว่า ในการแก้ปัญหาของเขา ng-repeat วางนาฬิกาไว้ที่นิพจน์ที่มีงานที่มอบหมาย แต่ละวงย่อยจะประเมินนิพจน์นั้นและกำหนดผลลัพธ์ให้กับตัวแปรขอบเขต

ปัญหาในการแก้ปัญหานี้คือคุณอาจประสบปัญหาในการมอบหมายงานหากคุณอยู่ในขอบเขตลูก นี่คือเหตุผลเดียวที่ว่าทำไมคุณควรจะมีจุดใน NG-รุ่น

อีกอย่างที่ฉันไม่ชอบเกี่ยวกับโซลูชันนี้คือมันฝังนิยามของอาร์เรย์ที่กรองไว้ที่ใดที่หนึ่งในมาร์กอัปมุมมอง หากมีการใช้งานหลายที่ในมุมมองของคุณหรือตัวควบคุมของคุณอาจทำให้เกิดความสับสนได้

วิธีแก้ปัญหาที่ง่ายกว่าคือวางนาฬิกาไว้ในตัวควบคุมของคุณบนฟังก์ชันที่ทำให้การมอบหมายงาน:

$scope.$watch(function () {
    $scope.filteredItems = $scope.$eval("items | orderBy:'order_prop' | filter:query | limitTo:4");
});

ฟังก์ชันนี้จะได้รับการประเมินในแต่ละรอบการย่อยดังนั้นประสิทธิภาพควรเทียบเคียงกับโซลูชันของ Andy คุณยังสามารถเพิ่มงานจำนวนเท่าใดก็ได้ในฟังก์ชันเพื่อให้งานทั้งหมดอยู่ในที่เดียวแทนที่จะกระจัดกระจายไปตามมุมมอง

ในมุมมองคุณจะใช้รายการที่กรองโดยตรง:

<ul>
    <li  ng-repeat="item in filteredItems">{{item.name}}</li>
</ul>

นี่คือซอที่แสดงในสถานการณ์ที่ซับซ้อนมากขึ้น


สะอาดมากและไม่ก่อให้เกิดมลพิษต่อโครงสร้างดี!
kuzyn

วิธีนี้เหมาะสำหรับฉัน .. ฉันใช้การทำซ้ำคอลเลกชันของไอออนิกแทนการทำซ้ำ .. นั่นคือสาเหตุที่คำตอบที่ยอมรับไม่ได้ผลสำหรับฉัน
Lakshay

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