AngularJS - como obter uma referência de resultado filtrada ngRepeat

129

Estou usando uma diretiva ng-repeat com filtro da seguinte forma:

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

e eu posso ver os resultados renderizados bem; agora eu quero executar alguma lógica nesse resultado no meu controlador. A questão é como posso pegar a referência de itens de resultado?

Atualizar:


Só para esclarecer: estou tentando criar uma conclusão automática, tenho esta entrada:

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

e depois os resultados filtrados:

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

agora eu quero navegar no resultado e selecionar um dos itens.

Shlomi Schwartz
fonte

Respostas:

270

ATUALIZAÇÃO : Aqui está uma maneira mais fácil do que a que existia antes.

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

Então $scope.filteredItemsé acessível.

Andrew Joslin
fonte
Obrigado pela resposta, consulte a minha atualização. Como você poderia implementar isso, nota que eu recebo toda a lista de itens de inicialização
Shlomi Schwartz
super legal, obrigado por isso. Eu gostaria que fosse um recurso interno do NG
Shlomi Schwartz
3
O problema dessa abordagem é que, se você observar a propriedade atribuída, acabará enviando spam digests $ (um por iteração) ... Talvez haja alguma maneira de evitar isso?
Juho Vepsäläinen
1
Se eu assistir o objeto de pesquisa e o console.log filteredItems, sempre recebo os dados um filtro mais tarde. Não é o resultado do filtro recém-alterado, mas o da alteração anterior. Alguma ideia?
ProblemsOfSumit
4
Alguém pode me explicar, por que isso funciona? Eu posso entender que uma variável do escopo $ está acessível no escopo de repetição (herança do escopo), mas o contrário? Quão? Alguma documentação é apreciada. Graças
dalvarezmartinez1
30

Aqui está a versão do filtro da solução de Andy Joslin.

Atualização: BREAKING CHANGE. A partir da versão 1.3.0-beta.19 ( este commit ), os filtros não têm um contexto e thisestarão vinculados ao escopo global. Você pode passar o contexto como argumento ou usar a nova sintaxe de alias no 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);
  };
});

Então, na sua opinião

<!-- 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>

O que lhe dá acesso $scope.filteredItems.

kevinjamesus86
fonte
Obrigado! Você poderia explicar como o código do filtro funciona? Não estou familiarizado com $ parse, e os documentos angulares não me ajudaram a decifrar como seu filtro funciona exatamente.
Magne
2
@Magne Sem problemas! Por favor, verifique a atualização, pois ela pode poupar um pouco de dor e sofrimento no caminho. Para responder à sua pergunta, em resumo, $parseé o compilador de expressão do Angular . Por exemplo, ele pega a string 'some.object.property' e retorna uma função que permite definir ou obter um valor no referido caminho para um especificado contexto. Estou usando-o para definir os resultados do filtro no escopo $ aqui, especificamente. Espero que isso responda à sua pergunta.
kevinjamesus86
23

Tente algo como isto, o problema com o ng-repeat é que ele cria escopo filho por causa disso você não pode acessar

filteritems

do controlador

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

Atualizar:

Mesmo depois da 1.3.0. se você quiser colocá-lo no escopo do controlador ou do pai, não poderá fazê-lo como sintaxe. Por exemplo, se eu tiver o seguinte código:

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

o acima não irá funcionar. A maneira de contornar isso é usar o $ parent da seguinte maneira:

<li ng-repeat="label in ($parent.labelResults = (labels | filter:query))">
Gal Bracha
fonte
É bom observar que, se você tiver um filtro limitTo sobre isso. Não será refletido no $ parent.labelResults
Zack
Se eu console.log labelResultssempre obtiver os dados um filtro mais tarde. Não é o resultado do filtro recém-alterado, mas o da alteração anterior. Você não teve esse problema?
1717 Anna
10

Eu vim com uma versão um pouco melhor da solução de Andy. Em sua solução, ng-repeat coloca um relógio na expressão que contém a atribuição. Cada loop de resumo avaliará essa expressão e atribuirá o resultado à variável de escopo.

O problema com esta solução é que você pode ter problemas de atribuição se estiver no escopo filho. Esta é a mesma razão pela qual você deve ter um ponto no modelo ng .

A outra coisa que eu não gosto nessa solução é que ela enterra a definição da matriz filtrada em algum lugar da marcação de exibição. Se for usado em vários lugares na sua visualização ou no seu controlador, pode ficar confuso.

Uma solução mais simples é colocar um relógio no seu controlador em uma função que faz a atribuição:

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

Esta função será avaliada durante cada ciclo de digestão, para que o desempenho seja comparável à solução de Andy. Você também pode adicionar qualquer número de atribuições à função para mantê-las todas em um só lugar, em vez de espalhadas pela exibição.

Na visualização, você usaria a lista filtrada diretamente:

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

Aqui está um violino, onde isso é mostrado em um cenário mais complicado.

Dave Johnson
fonte
Super limpo e não polui a estrutura, ótimo!
kuzyn
esta solução é perfeita para me..i estava usando de iônica repetição coleção em vez de repeat..thats ng por que o aceite resposta não funcionava para mim
Lakshay