Khó khăn với ng-model, ng-repeat và đầu vào


116

Tôi đang cố gắng cho phép người dùng chỉnh sửa danh sách các mục bằng cách sử dụng ngRepeatngModel. ( Xem điều này .) Tuy nhiên, cả hai cách tiếp cận mà tôi đã thử đều dẫn đến hành vi kỳ lạ: một cách không cập nhật mô hình và cách còn lại làm mờ biểu mẫu trên mỗi lần nhấn phím.

Tôi đang làm gì đó sai ở đây? Đây không phải là một trường hợp sử dụng được hỗ trợ?

Đây là mã từ fiddle, được sao chép để thuận tiện:

<html ng-app>
    <head>
        <link href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.2.1/css/bootstrap-combined.min.css" rel="stylesheet">
    </head>
    <body ng-init="names = ['Sam', 'Harry', 'Sally']">
        <h1>Fun with Fields and ngModel</h1>
        <p>names: {{names}}</p>
        <h3>Binding to each element directly:</h3>
        <div ng-repeat="name in names">
            Value: {{name}}
            <input ng-model="name">                         
        </div>
        <p class="muted">The binding does not appear to be working: the value in the model is not changed.</p>
        <h3>Indexing into the array:</h3>
        <div ng-repeat="name in names">
            Value: {{names[$index]}}
            <input ng-model="names[$index]">                         
        </div>
        <p class="muted">Type one character, and the input field loses focus. However, the binding appears to be working correctly.</p>
    </body>
</html>

Các bác sĩ cho biết:


1
Điều này rất giống với stackoverflow.com/questions/12977894/… , nhưng cách tiếp cận thứ 2 là mới ở đây, vì vậy nó không chính xác là một bản sao. Tôi đã cung cấp câu trả lời chi tiết (tương tự như của Artem) ở đó, giải thích cách hoạt động của phạm vi con ng-repeat.
Mark Rajcok

Vì tôi phải tốn một khoản chi phí hợp lý của googling trước khi cuối cùng tìm thấy luồng này, tôi có thể đổi tên nó thành sth như: "Mô hình chính không được cập nhật từ đầu vào ngRepeat" hoặc "Mô hình không được cập nhật khi sử dụng ngRepeat" hoặc "đầu vào ngRepeat không bị ràng buộc với (cha) không mô hình"? Có lẽ bạn có ý tưởng tốt hơn cho tiêu đề?
vucalur

Câu trả lời:


120

Đây dường như là một vấn đề ràng buộc.

Lời khuyên là đừng ràng buộc với những điều nguyên thủy .

Của bạn ngRepeatđang lặp qua các chuỗi bên trong một bộ sưu tập, khi nó nên lặp qua các đối tượng. Để khắc phục sự cố của bạn

<body ng-init="models = [{name:'Sam'},{name:'Harry'},{name:'Sally'}]">
    <h1>Fun with Fields and ngModel</h1>
    <p>names: {{models}}</p>
    <h3>Binding to each element directly:</h3>
    <div ng-repeat="model in models">
        Value: {{model.name}}
        <input ng-model="model.name">                         
    </div>

jsfiddle: http://jsfiddle.net/jaimem/rnw3u/5/


3
Cảm ơn siêu liên kết đầu tiên, vì nó giải thích sự cố mờ / mất nét / nhấp nháy. Tôi luôn tự hỏi tại sao điều đó lại xảy ra.
Mark Rajcok

2
cảm ơn vì điều đó, đã giúp rất nhiều. Tuy nhiên, liên kết với nguyên thủy nên có mặt ở đó imo ...
Daniel Gruszczyk

1
bài cũ nhưng thnx, đưa tôi một thời gian để tìm ra 'không thay đổi mô hình bên ngRepeat' vấn đề và đó là lời khuyên của bạn không bám vào nguyên thủy
Stefanos Chrs

Ngoài ra: Đừng sửa đổi toàn bộ danh sách trong khi nhập - một cái bẫy mà tôi đã rơi vào. Tôi đang xem bộ sưu tập để tìm các thay đổi và thay thế nó bằng một bản sao y hệt - vì vậy, mặc dù tôi không ràng buộc với các nguyên bản, các phần tử đang được tạo lại.
z0r

71

Sử dụng Angular phiên bản mới nhất (1.2.1) và theo dõi $index. Sự cố này đã được khắc phục

http://jsfiddle.net/rnw3u/53/

<div ng-repeat="(i, name) in names track by $index">
    Value: {{name}}
    <input ng-model="names[i]">                         
</div>

đã làm công việc; không bị mất tài liệu tham khảo hơn
Dan Ochiana

Tôi đã tìm kiếm rất lâu cho điều đó .... quá dễ dàng ... chỉ quá ẩn. Hãy cho đây là câu trả lời!
Andrea,

oooooh, vì vậy việc thêm "track by $ index" trong ng-repeat cũng khắc phục được sự cố "chập chờn"
boi_echos. 14/09/16

43

Bạn rơi vào tình huống khó khăn khi cần phải hiểu cách thức hoạt động của phạm vi , ngRepeatngModel với NgModelController . Cũng cố gắng sử dụng phiên bản 1.0.3. Ví dụ của bạn sẽ hoạt động hơi khác một chút.

Bạn chỉ cần sử dụng giải pháp được cung cấp bởi jm-

Nhưng nếu bạn muốn giải quyết tình huống sâu hơn, bạn phải hiểu:

  • cách AngularJS hoạt động ;
  • phạm vi có cấu trúc phân cấp;
  • ngRepeat tạo phạm vi mới cho mọi phần tử;
  • ngRepeat xây dựng bộ nhớ cache của các mục với thông tin bổ sung (hashKey); trên mỗi lệnh gọi đồng hồ cho mọi mục mới (không có trong bộ nhớ cache) ngRepeat xây dựng phạm vi mới, phần tử DOM, v.v. Mô tả chi tiết hơn .
  • từ 1.0.3 ngModelController kết xuất đầu vào với giá trị mô hình thực tế.

Cách hoạt động của ví dụ "Liên kết trực tiếp với từng phần tử" cho AngularJS 1.0.3:

  • bạn nhập ký tự 'f'vào đầu vào;
  • ngModelControllerthay đổi mô hình cho phạm vi mục (mảng tên là không thay đổi) => name == 'Samf', names == ['Sam', 'Harry', 'Sally'];
  • $digest vòng lặp được bắt đầu;
  • ngRepeatthay thế giá trị mô hình từ phạm vi mục ( 'Samf') bằng giá trị từ các tên không thay đổi array ( 'Sam');
  • ngModelControllerkết xuất đầu vào với giá trị mô hình thực tế ( 'Sam').

Cách hoạt động của ví dụ "Lập chỉ mục vào mảng":

  • bạn nhập ký tự 'f'vào đầu vào;
  • ngModelControllerthay đổi mục trong tên array=> `tên == ['Samf', 'Harry', 'Sally'];
  • Vòng lặp thông báo $ được bắt đầu;
  • ngRepeatkhông thể tìm thấy 'Samf'trong bộ nhớ cache;
  • ngRepeat tạo phạm vi mới, thêm phần tử div mới với đầu vào mới (đó là lý do tại sao trường đầu vào mất tiêu điểm - div cũ với đầu vào cũ được thay thế bằng div mới với đầu vào mới);
  • các giá trị mới cho các phần tử DOM mới được hiển thị.

Ngoài ra, bạn có thể thử sử dụng AngularJS Batarang và xem cách thay đổi $ id của phạm vi div với đầu vào mà bạn nhập.


cảm ơn cho lời giải thích 1.0.3. Điều thú vị là trong 1.0.3, trường hợp "liên kết trực tiếp", trường đầu vào dường như bị hỏng, theo nghĩa là nó dường như không chấp nhận bất kỳ thay đổi / đầu vào đã nhập nào (ít nhất là trong Chrome). Tôi chắc rằng chúng ta sẽ thấy khá nhiều bài đăng SO về điều này trong tương lai gần :) Tôi cho rằng cách mới này tốt hơn, vì sẽ rõ ràng hơn rằng có điều gì đó không ổn.
Mark Rajcok

6

Nếu bạn không cần mô hình cập nhật với mọi hành trình phím, chỉ cần liên kết với namevà sau đó cập nhật mục mảng trong sự kiện mờ:

<div ng-repeat="name in names">
    Value: {{name}}
    <input ng-model="name" ng-blur="names[$index] = name" />
</div>

Tại sao không sử dụng ng-model="names[$index]"... Tôi biết đó là một cách giải quyết, nhưng nó hoạt động ;-)
Draško Kokić


2

Vấn đề dường như nằm ở cách ng-modelhoạt động với inputvà ghi đè nameđối tượng, khiến nó bị mất ng-repeat.

Để giải quyết vấn đề, người ta có thể sử dụng mã sau:

<div ng-repeat="name in names">
    Value: {{name}}
    <input ng-model="names[$index]">                         
</div>

Hy vọng nó giúp


1

Tôi đã thử giải pháp ở trên cho vấn đề của tôi tại nó hoạt động như một sự quyến rũ. Cảm ơn!

http://jsfiddle.net/leighboone/wn9Ym/7/

Đây là phiên bản của tôi về điều đó:

var myApp = angular.module('myApp', []);
function MyCtrl($scope) {
    $scope.models = [{
        name: 'Device1',
        checked: true
    }, {
        name: 'Device1',
        checked: true
    }, {
        name: 'Device1',
        checked: true
    }];

}

và HTML của tôi

<div ng-app="myApp">
    <div ng-controller="MyCtrl">
         <h1>Fun with Fields and ngModel</h1>
        <p>names: {{models}}</p>
        <table class="table table-striped">
            <thead>
                <tr>
                    <th></th>
                    <th>Feature 1</td>
                    <th>Feature 2</th>
                    <th>Feature 3</th>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>Device</td>
                   <td ng-repeat="modelCheck in models" class=""> <span>
                                    {{modelCheck.checked}}
                                </span>

                    </td>
                </tr>
                <tr>
                    <td>
                        <label class="control-label">Which devices?</label>
                    </td>
                    <td ng-repeat="model in models">{{model.name}}
                        <input type="checkbox" class="checkbox inline" ng-model="model.checked" />
                    </td>
                </tr>
            </tbody>
        </table>
    </div>
</div>

-5

làm thế nào để làm một cái gì đó như:

<select ng-model="myModel($index+1)">

Và trong yếu tố thanh tra của tôi là:

<select ng-model="myModel1">
...
<select ng-model="myModel2">
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.