問題描述
帶有選擇/選項下拉框的嵌套 ng‑repeat 問題 (Nested ng‑repeat issue with select/options drop down box)
我有一個 ng‑repeat,它調用一個端點來獲取一個充滿數據的巨大 JSON 對象,該對象通過控制器分配給 vm。在 vm 對象內部,有幾個屬性,包括具有對像數組的屬性,而後者又具有包含對像數組的屬性。
在下面的示例中(我正在處理的簡化版本),您可以看到 vm 對象,其中包含一個 Students 屬性,該屬性包含一個學生對像數組,其中每個學生都有一個成績屬性進一步包含一組對象,這些對象顯示特定班級和教師的成績。第一個 ng‑repeat 根據學生在表中創建行,第二個 ng‑repeat 應該根據學生的成績創建一個下拉列表(也請參見下面的 HTML)。
{
vm: { variousProperties...
variousProperties...
variousProperties...
Students:
[{ firstName: Alice
grades:
[{
class: History
teacher: Mrs. History
grade: 96
},{
class: Math
teacher: Mrs. Math
grade: 97
}]
}, {
firstName: Beth
grades:
[{
class: History
teacher: Mrs. History
grade: 92
]}
}]
}
}
基本代碼如下 ‑ 表格行可點擊,下拉一個包含附加信息的子區域:
<tbody ng‑repeat="student in vm.Students">
<tr ng‑click="isOpen=!isOpen"> <!‑‑Create the rows and make them clickable so a sub area can drop down with different information‑‑>
<td> <!‑‑clickable headers in the table‑‑> </td>
</tr>
<tr> <!‑‑This is for the drop down for each row‑‑>
<table>
<thead> <tr> <th> </th> </tr> </thead>
<tbody> <tr>
<div> <!‑‑This div ends up holding everything, and is what appears when you click on a row in the table to drop down the additional information‑‑>
<select ng‑model="vm.studentType">
<option ng‑repeat="grade in student.grades">
</option>
</select>
<div>
<span>Class: {{grade.class}}<span><br>
<span>Teacher: {{grade.teacher}}<span><br>
<span>Grade: {{grades.grade}}<span><br>
</div>
我需要能夠要做的是單擊該行,下拉附加 div,然後有一個下拉選項菜單,我可以在其中根據班級選擇學生的成績。由於學生可能並非都擁有相同的課程,因此需要第二個 ng‑repeat 來構建特定於學生的選項列表。這樣,我可以單擊 Alice 的行,看到帶有下拉菜單的子區域,然後選擇與該學生相關的各種選項而不為其他學生更改其他行。
但是,我遇到了兩個問題。我好像不能 t 同時解決這兩個問題:
- 我需要下拉列表來顯示初始選擇,並且我需要該初始選擇來相應地填充跨度。所以對於 Alice,它最初會選擇 History,然後顯示 History/Mrs. 跨度中的歷史/96。如果我再次單擊下拉菜單,我可以選擇她的其他班級,並相應地填充跨度。
- 我需要能夠以每個學生為基礎選擇下拉列表項,以便更改Alice 的選項不會改變 Beth 的。
我嘗試了許多不同的方法來做到這一點,例如:
- 使用通過 $index 跟踪並將值設置為 $index
- 設置 ng‑model (vm.studentType),將 ng‑model‑options 設置為 updateOn 默認
- 更改 span 的填充方式,例如使用 Student.grades[$index].class 或 Student.grades[vm.studentType].class
- 試過設置ng‑init選項,或者通過控制器初始化
比如在嵌套的ng‑repeat上,我設置ng‑model為vm.studentType,track by $index,將 value 設置為 $index,並使每個 span 使用 Students.grades[vm.studentType].class,等等。這將使用每個學生的初始成績填充跨度,但是如果我將 Alice 從歷史更改為數學,Beth 的所有內容都會空白。如果在此之後我將 Beth 設置回她的歷史,Alice 也會重置為歷史。所以在這種情況下,我需要能夠阻止兩個學生 當我改變一個或另一個時,跨度會發生變化。這表明設置為 ng‑model 的 vm.studentType 不起作用,因為每當我選擇新選項時,它都會為所有學生更新。
而不是將 ng‑model 設置為 vm.studentType,我改為將其設置為 $index (我確定這不是預期的設置)並在嵌套重複中通過 $index 和 value=$index 保持跟踪,我可以自由更改學生之間的選項而不會干擾其他人. 但是,這會導致下拉列表本身為空白。跨度也將是空的,除了 Alice,它的跨度最初是填充的。
所以我需要下拉菜單來顯示“1 級”左右,以便根據填充跨度1級,然後能夠在每個學生的基礎上自由更改這些,而不會干擾其他學生。
我嘗試過使用 ng‑model‑options,使用 ng‑option 而不是將選項與選擇 DOM 元素,嘗試使用 $parent.$index,控制台記錄各種事情,使用大括號打印出 $index 和 $parent.$index 等。
我已經搞砸了幾天了,並且也向同事尋求幫助,但找不到答案。
對於我對 Angular 的一些無知,我深表歉意 ‑ 我仍處於學習階段,只是在尋求幫助。任何考慮都表示讚賞,並提前感謝您的時間。
使用 ng‑option 而不是將選項與 select DOM 元素分開,嘗試使用 $parent.$index,控制台記錄了各種內容,使用大括號打印出 $index 和 $parent.$index 等。我已經搞砸了幾天,也向同事尋求幫助,但找不到答案。
我對我對 Angular 的一些無知表示歉意 ‑ 我仍在學習中階段,我只是在尋找一些幫助。任何考慮都表示讚賞,並提前感謝您的時間。
使用 ng‑option 而不是將選項與 select DOM 元素分開,嘗試使用 $parent.$index,控制台記錄了各種內容,使用大括號打印出 $index 和 $parent.$index 等。我已經搞砸了幾天,也向同事尋求幫助,但找不到答案。
我對我對 Angular 的一些無知表示歉意 ‑ 我仍在學習中階段,我只是在尋求幫助。任何考慮都表示讚賞,並提前感謝您的時間。
並且找不到答案。對於我對 Angular 的一些無知,我深表歉意 ‑ 我仍處於學習階段,只是在尋求幫助。任何考慮都表示讚賞,並提前感謝您的時間。
並且找不到答案。對於我對 Angular 的一些無知,我深表歉意 ‑ 我仍處於學習階段,只是在尋求幫助。任何考慮都表示讚賞,並提前感謝您的時間。
參考解法
方法 1:
Will this work? Make vm.studentType an Object initialy in the controller. Instead of the $index you can use student.id.
<tbody ng‑repeat="student in vm.Students track by student.id">
<tr ng‑click="isOpen=!isOpen"> <!‑‑Create the rows and make them clickable so a sub area can drop down with different information‑‑>
<td> <!‑‑clickable headers in the table‑‑> </td>
</tr>
<tr> <!‑‑This is for the drop down for each row‑‑>
<table>
<thead> <tr> <th> </th> </tr> </thead>
<tbody> <tr>
<div> <!‑‑This div ends up holding everything, and is what appears when you click on a row in the table to drop down the additional information‑‑>
<select ng‑model="vm.studentType[$index]" ng‑options="::grad.class for grade in ::student.grades">
</select>
<div>
<span>Class: {{vm.studentType[$index].class}}<span><br>
<span>Teacher: {{vm.studentType[$index].teacher}}<span><br>
<span>Grade: {{vm.studentType[$index].grade}}<span><br>
</div>
Also use one time binding in ng‑repeat where ever possible. The use of track by will also improve performance on big lists if they can change.
(by RS99、Christian Steinmann)