0

Я хотел бы использовать фильтр orderBy с директивой ng-repeat, итерации по свойствам объектов. Поскольку фильтр orderBy работает только с массивом, Angular doc предлагает использовать фильтр toArray.Почему использование фильтра toArray с ng-repeat и объект строк вызывает бесконечный цикл дайджеста?

ToArray фильтр работает как шарм с объектными свойствами, как:

var obj = { 
    a: { name: 'A' }, 
    b: { name: 'B' }, 
    c: { name: 'C' } 
}; 

Но это вызывает бесконечный переваривать цикл при использовании свойств необъектных:

var obj = { 
    a: 'A', 
    b: 'B', 
    c: 'C' 
}; 

Здесь a plunker, иллюстрирующий эту проблему.

ответ

1

Вы все равно не должны этого делать, фильтры, как правило, являются плохими идеями при преобразовании данных, потому что они будут пересчитываться каждый раз, когда цикл дайджеста делает цикл. Ваш плункер не работает, поэтому трудно сказать, почему, но, глядя на код, я бы сказал, что он делает полностью новый массив с каждым циклом дайджеста, а в случае объектов он добавляет свойство $ key, что помогает остановить цикл дайджеста. Он не может добавить такое свойство в строки. Но я не совсем уверен в этом.

Edit: при добавлении console.log к ToArray:

return Object.keys(obj).map(function (key) { 
     var value = obj[key]; 

     console.log(key, value); 

     return angular.isObject(value) ? 
      Object.defineProperty(value, '$key', { enumerable: false, value: key}) : 
      { $key: key, $value: value }; 
     }); 

В журналах вы можете увидеть ответ на свой вопрос:

VM596 angular-toArrayFilter.js:15 b b 
VM596 angular-toArrayFilter.js:15 a a 
VM596 angular-toArrayFilter.js:15 c Object {p: "c"} 
VM596 angular-toArrayFilter.js:15 b Object {p: "b"} 
VM596 angular-toArrayFilter.js:15 a Object {p: "a"} 
VM596 angular-toArrayFilter.js:15 c Object {p: "c", $key: "c"} 
VM596 angular-toArrayFilter.js:15 b Object {p: "b", $key: "b"} 
VM596 angular-toArrayFilter.js:15 a Object {p: "a", $key: "a"} 
VM596 angular-toArrayFilter.js:15 c c 
VM596 angular-toArrayFilter.js:15 b b 
VM596 angular-toArrayFilter.js:15 a a 
VM596 angular-toArrayFilter.js:15 c Object {p: "c", $$hashKey: "object:11", $key: "c"} 
VM596 angular-toArrayFilter.js:15 b Object {p: "b", $$hashKey: "object:10", $key: "b"} 
VM596 angular-toArrayFilter.js:15 a Object {p: "a", $$hashKey: "object:9", $key: "a"} 

В случае объектов, угловатый использует одни и те же объекты, и не создает новых. Чтобы он мог предположить, что массив не изменился и не закончил цикл дайджеста. В случае строковых значений он создает новые объекты при каждом запуске фильтра, так что он предполагает, что каждый раз, когда создается другой массив, так что он не может закончить цикл дайджест.

+0

Благодарим вас за ответ @sielakos. Мой плукер был неудачным, чтобы подчеркнуть неудачное поведение, я обновил его с помощью рабочего корпуса, чтобы сделать все более ясным. – Mic

+0

О вашей второй точке @sielakos, если свойства объекта, которые повторяются, не являются объектами, тогда фильтр заменит не-объект новым объектом формы: {$ key: key, $ value: value}. Вы заявляете, что это плохая идея использовать фильтр в этом случае, но Angular Doc явно предлагает toArrayFilter, когда нам нужно использовать orderBy при использовании ng-repeat и объекта. Какую альтернативу вы предлагаете? – Mic

+0

Преобразуйте свои данные в контроллер/службу таким образом, что вам не придется преобразовывать их в циклы цикла времени, вы будете делать это только один раз. Также вы можете избежать проблем с бесконечным циклом дайджест. – sielakos

Смежные вопросы