2012-12-18 19 views
55

In qualche modo, attraverso la magia di Angular, se si utilizza ng-model e si fornisce un valore booleano, la casella di controllo verrà controllata se detto valore booleano è true e deselezionato se false.AngularJS: Reverse Checkbox State

<input type="checkbox" ng-model="video.hidden"> 

Anche se questo da solo è abbastanza sconcertante, in realtà sto cercando di invertire lo stato controllato, perché a differenza l'esempio todo dove todo.done significa la casella viene selezionata, il mio modello è più simile todo.incomplete.

Purtroppo la mia prima ipotesi non ha funzionato:

<input type="checkbox" ng-model="!video.hidden"> 

io sono in una posizione in cui il modello è stato dettato a me, quindi non posso cambiarla e non vogliono avere a massaggiarlo sul client (perché sto inviando oggetti client al server, poiché è in esecuzione in un ambiente attendibile).

Aggiornamento

Questo funziona in 1.3 e non ti dà le stringhe (1.2.xxx ti ha dato corde invece di booleani):

<input type="checkbox" ng-model="video.hidden" ng-true-value="false" ng-false-value="true"> 
+0

o semplicemente usare una negazione di qualsiasi parola che hai usato per descrivere il tuo modello: video.shown:? oppure utilizzare una funzione nel controller per impostare il valore di un altro modello quando la casella di controllo è selezionata ... non è un problema reale secondo me. – mpm

+0

@camus L'ultima cosa che ho detto è che non volevo cambiare il modello e non avrei dovuto. Certo, non è un problema reale, ma quando un framework sta sollecitando la facilità d'uso, non c'è motivo per cui la mia prima ipotesi sopra non dovrebbe funzionare. – Langdon

+1

utilizzando una funzione non sta cambiando il modello ma aggiungendo una funzione a un controller. E nessun quadro è un proiettile d'argento. Ma questo è facilmente estensibile, è quello che dovrai fare comunque, scrivere direttive. – mpm

risposta

69

si può fare che ora, senza la necessità di direttiva personalizzato, il supporto angolare ng-true-value e ng-false-value

https://docs.angularjs.org/api/ng/input/input[checkbox]

tuo esempio dovrebbe funzionare ora <input type="checkbox" ng-model="video.hidden" ng-true-value="false" ng-false-value="true">

+1

Il problema con questa soluzione è che la casella di controllo visualizzerà ancora il valore video.hidden quando viene visualizzato. –

+0

Sembra che l'abbiano risolto in 1.3. – Langdon

+0

Vedo 'ng-true-value' e' ng-false-value', ma il valore 'false' non viene inviato al server. Forse è trattato come un controllo formale non riuscito. –

23

Io non credo che ci sia un modo per fallo semplicemente nel modello. Il modo più ovvio per realizzare ciò è creare una nuova variabile scope che viene manualmente associata al valore del modello. Così come:

<input type="checkbox" ng-model="videoShowing"> 

E nel controller:

$scope.videoShowing = !$scope.video.hidden; 

$scope.$watch('video.hidden', function(value) { 
    $scope.videoShowing = !value; 
}); 
$scope.$watch('videoShowing', function(value) { 
    $scope.video.hidden = !value; 
} 

Si potrebbe quasi usare appena vincolante con un ng cambio a senso unico, ma che non funziona del tutto:

<input type="checkbox" ng-checked="!video.hidden" ng-change="???"> 

Poiché ng-change non mescola il valore corrente nello scope locale. Se ti trovavi in ​​un contesto in cui avevi accesso a NgModelController, potresti fare qualcosa, ma avresti bisogno di una direttiva personalizzata per questo. Non sarebbe difficile creare una direttiva di attributo "invertita" che modifichi i formattatori e i parser di NgModel. Ti suggerirei se hai bisogno di molte caselle di controllo invertite.

Modifica

Ai posteri, facendo un attributo "invertita" è super semplice, potrebbe anche solo farlo. Fare le direttive sembra sempre un dolore all'inizio, ma è davvero il modo angolare.

someModule.directive('inverted', function() { 
    return { 
    require: 'ngModel', 
    link: function(scope, element, attrs, ngModel) { 
     ngModel.$parsers.push(function(val) { return !val; }); 
     ngModel.$formatters.push(function(val) { return !val; }); 
    } 
    }; 
}); 

potrebbe essere necessario impostare la priorità di troppo, o "innesto" invece di spinta, per assicurarsi che questi ragazzi correre dopo il built-in quelli inputDirective.

+0

cos'è l'argomento 'ngModel' qui? c'è qualche documentazione a riguardo? o è un qualche tipo di magia DI? –

+1

Il quarto argomento di 'link' rispecchia ciò che tu richiedi'. – jpsimons

13

Questo sembra funzionare

<input type="checkbox" 
     ng-init = "video.checked = !video.hidden" 
     ng-model ="video.checked" 
     ng-change ="video.hidden = !video.checked"/> 

Si introduce una proprietà video.checked che è l'opposto di video.hidden e, non appena la casella di controllo cambia i valori vengono aggiornati.

Esempio qui: http://plnkr.co/edit/7HYht6ubkUUJQ0r3g16m?p=preview

+0

Bello, sembra funzionare. È necessaria la parte 'ng-init'? All'interno di 'ng-change', non hai accesso a' input' per leggere lo stato controllato da esso? – Langdon

+0

senza 'ng-init' quando la vista è compilata il valore di' video.checked' sarebbe 'indefinito' e le caselle di controllo sarebbero deselezionate anche quando' video.hidden' è impostato su 'false' che è quando vuoi che siano spuntate . Se rimuovi 'ng-init', dovrai modificare gli oggetti' videos' dal controller e fare l'inizializzazione da lì. – jaime

+1

Quindi non si ha accesso all'entrata di destinazione all'interno di ng-change? Ad esempio, non potrei dire: 'ng-change =" video.hidden =! $ Element.checked "' – Langdon

4

mia soluzione utilizza una direttiva "negate", che si aggiunge solo al "input". È semplice e non è necessario cambiare il controller.

angular 
    .module("<< your module >>") 
    .directive('negate', [ 
     function() { 
      return { 
       require: 'ngModel', 
       link: function (scope, element, attribute, ngModelController) { 
        ngModelController.$isEmpty = function(value) { 
         return !!value; 
        }; 

        ngModelController.$formatters.unshift(function (value) { 
         return !value; 
        }); 

        ngModelController.$parsers.unshift(function (value) { 
         return !value; 
        }); 
       } 
      }; 
     } 
    ] 
); 

Utilizzare in questo modo:

<input type="checkbox" negate ng-model="entity.nologin"> 
0

ritengo la soluzione più semplice per ottenere il valore selezionato o deselezionato una casella è aggiungendo la direttiva ng-init all'interno dell'elemento ingresso casella come segue:

<input type="checkbox" ng-init="video = false" ng-model="video" > 

questo modo il valore iniziale della casella di controllo per sii falso, lo stato non è controllato. All'invio del modulo, se la casella di spunta è deselezionata, il valore restituito (o console) sarà falso, anziché "non definito", altrimenti al momento del controllo sarà vero.

se si desidera aggiungere valori su misura per lo stato vero o falso, è possibile utilizzare:

ng-true-value="'custom_true value'" 

e

ng-false-value="'custom_false value'" 

all'interno dell'elemento di ingresso. come:

<input type="checkbox" ng-init="video = false" ng-model="video" ng-true-value="'custom_true value'" ng-false-value="'custom_false value'"> 
0

La mia soluzione è molto semplice: basta utilizzare ng-true-valore/ng-falso-valore e impostare falso per NG-vero valore e vero per NG-falso-value che invertirà la funzionalità.

<input type="checkbox" ng-model="<<-- Your Model -->> " ng-true-value="false" 
 
      ng-false-value="true">