Inicializando a seleção com AngularJS e ng-repeat

133

Estou tentando obter a caixa de seleção para começar com uma opção pré-preenchida usando ng-repeat com o AngularJS 1.1.5. Em vez disso, a seleção sempre começa com nada selecionado. Ele também tem uma opção vazia, que eu não quero. Eu acho que há um efeito colateral de nada ser selecionado.

Posso fazer isso funcionar usando ng-options em vez de ng-repeat, mas quero usar ng-repeat neste caso. Embora meu exemplo resumido não o mostre, eu também quero definir o atributo title de cada opção, e não há como fazer isso usando ng-options, tanto quanto eu sei.

Eu não acho que isso esteja relacionado ao problema comum de escopo / herança prototípica do AngularJs. Pelo menos não vejo nada óbvio ao inspecionar em Batarang. Além disso, quando você escolhe uma opção na seleção com a interface do usuário, o modelo é atualizado corretamente.

Aqui está o HTML:

<body ng-app ng-controller="AppCtrl">
    <div>
        Operator is: {{filterCondition.operator}}
    </div>
    <select ng-model="filterCondition.operator">
       <option 
           ng-repeat="operator in operators" 
           value="{{operator.value}}"
       >
           {{operator.displayName}}
       </option>
    </select>
</body>

E o JavaScript:

function AppCtrl($scope) {

    $scope.filterCondition={
        operator: 'eq'
    }

    $scope.operators = [
        {value: 'eq', displayName: 'equals'},
        {value: 'neq', displayName: 'not equal'}
     ]
}

JS Fiddle para isso: http://jsfiddle.net/coverbeck/FxM3B/2/

Charles O.
fonte
1
O ngOption foi criado porque não havia uma maneira limpa de fazer isso com o ngRepeat. ngRepeat se desenrola após a seleção da opção. Você tentou definir ngSelect sobre as suas opções
TheSharpieOne
Sim! O ngSelected funcionou! Vou postar um JsFiddle atualizado.
Charles O.
Deve-se notar que no AngualrJS 1.2 esse código funciona de maneira diferente - ele não cria um novo elemento <OPTION> vazio, no entanto, ele só pode selecionar a primeira opção na caixa de listagem. Você pode vê-lo aqui
VitalyB

Respostas:

226

ESTÁ BEM. Se você não quiser usar da maneira correta ng-options, poderá adicionar ng-selectedatributo com uma lógica de verificação de condição para que a optiondiretiva faça com que a pré-seleção funcione.

<select ng-model="filterCondition.operator">
    <option ng-selected="{{operator.value == filterCondition.operator}}"
            ng-repeat="operator in operators"
            value="{{operator.value}}">
      {{operator.displayName}}
    </option>
</select>

Working Demo

zs2020
fonte
37
Vou lhe dar o crédito, já que você descobriu por conta própria e fez o exemplo completo. Embora eu não concorde com o seu comentário sobre ng-options ser a "maneira correta". :) Eu sempre usei ng-options, mas isso exigiu fazer algo que o ng-options não suporta, por menor que seja. E o documento Angular diz que você também pode repetir o ng-repeat. Obrigado, Charles
Charles O.
Obrigado, essa foi uma maneira fácil de desativar algumas opções.
Dorian
11
ng-options está correto apenas enquanto os casos de uso se ajustarem aos seus. Você pode precisar de atributos / classes extras nos campos opção / grupo de opções etc.
mystrdat 15/10/14
6
"a maneira correta" não funciona às vezes (por exemplo, se você quiser traduzir as cordas que povoam os nomes de opção.)
btk
11
Eu acho que a expressão ng-selecionada tem que ser sem o {{}}: ng-selected = "operator.value == filterCondition.operator"
mvermand
35

Para a tag select, angular fornece a diretiva ng-options. Ele fornece a estrutura específica para configurar opções e definir um padrão. Aqui está o violino atualizado usando ng-options que funciona conforme o esperado: http://jsfiddle.net/FxM3B/4/

HTML atualizado (o código permanece o mesmo)

<body ng-app ng-controller="AppCtrl">
<div>Operator is: {{filterCondition.operator}}</div>
<select ng-model="filterCondition.operator" ng-options="operator.value as operator.displayName for operator in operators">
</select>
</body>
Jeremy Likness
fonte
3
Oi Jeremy - Estou tentando fazer isso sem ng-options. Como eu disse na minha pergunta e em resposta a Shaun, gostaria de definir o atributo title em cada opção, e não posso fazer isso com ng-options, tanto quanto sei. Obrigado, Charles
Charles O.
9

Obrigado a TheSharpieOne por apontar a opção ng-selecionada. Se isso tivesse sido postado como uma resposta e não como um comentário, eu teria feito a resposta correta.

Aqui está um JSFiddle em funcionamento: http://jsfiddle.net/coverbeck/FxM3B/5/ .

Também atualizei o violino para usar o atributo title, que havia deixado de fora no meu post original, pois não era a causa do problema (mas é o motivo pelo qual desejo usar ng-repeat em vez de ng-options) .

HTML:

<body ng-app ng-controller="AppCtrl">
<div>Operator is: {{filterCondition.operator}}</div>
<select ng-model="filterCondition.operator">
   <option ng-repeat="operator in operators" title="{{operator.title}}" ng-selected="{{operator.value == filterCondition.operator}}" value="{{operator.value}}">{{operator.displayName}}</option>
</select>
</body>

JS:

function AppCtrl($scope) {

    $scope.filterCondition={
        operator: 'eq'
    }

    $scope.operators = [
        {value: 'eq', displayName: 'equals', title: 'The equals operator does blah, blah'},
        {value: 'neq', displayName: 'not equal', title: 'The not equals operator does yada yada'}
     ]
}
Charles O.
fonte
Desculpe por postar como um comentário. Não tinha vontade de dar um exemplo e não tinha 100% de certeza de que iria funcionar. Foi apenas um palpite.
TheSharpieOne
9

O fato de angular estar injetando um elemento de opção vazio na seleção é que o objeto de modelo vinculado a ele por padrão vem com um valor vazio quando inicializado.

Se você quiser selecionar uma opção padrão, provavelmente poderá configurá-la no escopo no controlador

$scope.filterCondition.operator = "your value here";

Se você deseja um espaço reservado para uma opção vazia, isso funciona para mim

<select ng-model="filterCondition.operator" ng-options="operator.id as operator.name for operator in operators">
  <option value="">Choose Operator</option>
</select>
Ammadu
fonte
2
Isso é bom, mas o Angular cria uma opção em branco. Como evitar isso?
MarceloBarbosa 26/11/2015
1

Conforme sugerido, você precisa usar ng-options e, infelizmente, acredito que você precise referenciar o elemento array como padrão (a menos que o array seja um array de strings).

http://jsfiddle.net/FxM3B/3/

O JavaScript:

function AppCtrl($scope) {


    $scope.operators = [
        {value: 'eq', displayName: 'equals'},
        {value: 'neq', displayName: 'not equal'}
     ]

    $scope.filterCondition={
        operator: $scope.operators[0]
    }
}

O HTML:

<body ng-app ng-controller="AppCtrl">
<div>Operator is: {{filterCondition.operator.value}}</div>
<select ng-model="filterCondition.operator" ng-options="operator.displayName for operator in operators">
</select>
</body>
shaunhusain
fonte
Você sabe por que e tem certeza? A documentação ( docs.angularjs.org/api/ng.directive:select ) diz que você só precisa usar ng-options ao vincular a um valor não string. Como eu disse, quero usar o atributo title, e não há como fazer isso com ng-options. Algo como <option title = "Uma descrição muito longa dessa escolha" ...> Obrigado.
Charles O.
Acredito que a nota nos documentos é um pouco obscura e, na verdade, significa que você precisaria usar uma string para o modelo e ter uma matriz de strings para as opções. Se você não se importa com o motivo de usar o atributo "title", não o vejo no W3C w3schools.com/tags/tag_option.asp e não consigo me lembrar de usá-lo realmente. Você não poderia simplesmente armazenar a descrição nos objetos e ainda recuperar esses dados, já que é a isso que o modelo agora está vinculado?
shaunhusain 5/09/13
Na página do W3C à qual você vinculou, se clicar no link Atributos Globais, verá que o atributo title é suportado pelo elemento option. Estou usando o atributo title apenas para exibir o texto "dica de ferramenta", para que, se você passar o mouse sobre uma opção, possa obter uma descrição maior do que ela significa. É uma coisa pequena, mas seria bom ter, se possível.
Charles O.
@CharlesO. Eu quero fazer exatamente como você. Defina um objeto (valor não-string), mas também quero usar um título na lista de opções. Existe uma solução para isso. Parece que não consigo encontrá-lo ...
Wilt:
1

Se você estiver usando md-select e ng-repeat ing md-option a partir de material angular, poderá adicionar ng-model-options="{trackBy: '$value.id'}"às cinzas da tag md-select mostradas nesta caneta

Código:

<md-select ng-model="user" style="min-width: 200px;" ng-model-options="{trackBy: '$value.id'}">
  <md-select-label>{{ user ? user.name : 'Assign to user' }}</md-select-label>
  <md-option ng-value="user" ng-repeat="user in users">{{user.name}}</md-option>
</md-select>

Japheth Ongeri - inkalimeva
fonte