Définir la variable de portée angulaire dans le balisage

94

Question simple: Comment puis-je définir une valeur de portée en html, à lire par mon contrôleur?

var app = angular.module('app', []);

app.controller('MyController', function($scope) {
  console.log($scope.myVar);
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app='app'>
  <div ng-controller="MyController" app-myVar="test">
    {{myVar}}
  </div>
</div>

JSFiddle: http://jsfiddle.net/ncapito/YdQcX/

Rien
la source
Vous feriez peut-être mieux de créer une directive pour gérer cela. Une directive encapsulerait: le ou les paramètres, un contrôleur spécifique à cette directive et un modèle pour le balisage «myMap».
Ian Mercer
C'est en fait ce que j'ai fait ... j'ai juste quelques problèmes pour accéder à $ scope.myVar dans le contrôleur de directive. Pourquoi dois-je utiliser une montre dans le contrôleur pour accéder aux variables de portée?
Nix
1
Peut-être pourriez-vous publier votre directive? Jetez un œil à "Comprendre la transclusion et les portées" ici docs.angularjs.org/guide/directive Vous avez probablement besoin de scope: {myVar: '='} et vous diriez my-var="foo"quand vous l'appelez. Notez l'utilisation du trait d'union contre camelCase. Remarque: fooici est évalué , si vous ne souhaitez pas utiliser '@' dans la définition de portée pour accéder à la valeur de l'attribut.
Ian Mercer
1
@Nix Pouvez-vous expliquer pourquoi la valeur doit être initialisée dans la vue plutôt que dans votre contrôleur? Je suppose que vous savez déjà que ce n'est pas la manière conventionnelle d'initialiser les valeurs (sinon vous ne le demanderiez pas), et d'autres pourront vous donner de meilleures réponses s'ils comprennent mieux votre cas d'utilisation.
Sean the Bean
1
@SeantheBean j'étais jeune et stupide ...;) Je n'ai aucune idée de pourquoi j'avais besoin de le faire. J'essayais probablement de pirater quelque chose.
Nix

Réponses:

138

ng-initne fonctionne pas lorsque vous affectez des variables à l'intérieur de la boucle. Utilisation {{myVariable=whatever;""}}

La fin ""arrête l'évaluation de l'expression angulaire en n'importe quel texte.

Ensuite, vous pouvez simplement appeler {{myVariable}}pour afficher la valeur de votre variable.

J'ai trouvé cela très utile lors de l'itération de plusieurs tableaux imbriqués et je voulais conserver mes informations d'itération actuelles dans une variable au lieu de l'interroger plusieurs fois.

Glogo
la source
1
Bien que cela fonctionne, cela semble piraté. Autrement dit, il est généralement recommandé de {{}}ne l' utiliser que pour générer une seule variable, et non pour affecter des variables. Je dirais que stackoverflow.com/a/16799763/814160 est plus correct (moins de code JS dans la vue).
Sean the Bean
1
+1 pour @SeantheBean - J'ai testé cela. Il semble y avoir des problèmes avec les contrôleurs enfants et la portée de l'attribution de la variable dans le balisage. La directive fonctionne à mes fins et semble être une solution solide.
Paul Carlton
2
Cela ne semble pas fonctionner dans angular2 / 4 - Les liaisons ne peuvent pas contenir d'affectations
Demodave
1
@Demodave, vous devez à la place définir toutes les variables de votre contrôleur dans le code Typescript, et utiliser le modèle uniquement pour connecter Typescript au HTML. Le modèle ne doit pas affecter de variables.
boxmein le
80

ngInit peut aider à initialiser les variables.

<div ng-app='app'>
    <div ng-controller="MyController" ng-init="myVar='test'">
        {{myVar}}
    </div>
</div>

exemple jsfiddle

Mark Coleman
la source
3
Il convient de noter qu'ils ne recommandent pas cette solution pour de vraies applications (mais ne suggèrent pas vraiment d'alternative): docs.angularjs.org/guide/dev_guide.mvc.understanding_model
Mike Robinson
Cela a fonctionné pour moi, cependant, au début, la variable n'était toujours pas définie dans le contrôleur. J'ai fait une petite boucle d'intervalle: var interval = setInterval (function () {if ($ scope.whatever) {// dostuff clearInterval (interval);}}, 10);
roelleor
19

Créez une directive appelée myVaravec

scope : { myVar: '@' }

et appelez-le comme ceci:

<div name="my_map" my-var="Richmond,VA">

Notez en particulier la référence de cas de chameau dans la directive au nom de la balise avec trait d'union.

Pour plus d'informations, consultez "Comprendre la transclusion et les portées" ici: - http://docs.angularjs.org/guide/directive

Voici un violon qui montre comment copier des valeurs d'attributs vers des variables d'étendue de différentes manières au sein d'une directive.

Ian Mercer
la source
Je veux pouvoir en faire plusieurs var-nick='my' var-nick2='test'. À moins que vous ne puissiez penser à un moyen de l'implémenter avec des directives que je vais simplement utiliserng-init
Nix
Vous pouvez inclure plusieurs attributs dans la portée, tout ce dont vous avez besoin est que l'un d'entre eux soit le nom de la directive que vous souhaitez exécuter (ou incluez également ce nom de directive dans le code HTML). scope: {varNick: '@', varNick2: '@'}
Ian Mercer
Mais ce n'est pas évolutif? Devrais-je définir une directive par variable?
Nix
Non, vous n'avez pas besoin d'une directive par variable. Jetez un œil au violon que j'ai ajouté à la réponse.
Ian Mercer
Désolé j'ai manqué de lire, votre exemple est parfait, mon seul changement a été la portée {'@': '@ "}.
Nix
10

Vous pouvez définir des valeurs de HTML comme ceci. Je ne pense pas qu'il existe encore une solution directe d'angular.

 <div style="visibility: hidden;">{{activeTitle='home'}}</div>
ibsenv
la source
7
Nice hack ... je le recommanderais <div style="display: none">cependant.
Roger
3

Vous pouvez utiliser ng-initcomme indiqué ci-dessous

<div class="TotalForm">
  <label>B/W Print Total</label>
  <div ng-init="{{BWCount=(oMachineAccounts|sumByKey:'BWCOUNT')}}">{{BWCount}}</div>
</div>
<div class="TotalForm">
  <label>Color Print Total</label>
  <div ng-init="{{ColorCount=(oMachineAccounts|sumByKey:'COLORCOUNT')}}">{{ColorCount}}</div>
</div>

puis utilisez la variable de portée locale dans d'autres sections:

<div>Total: BW: {{BWCount}}</div>
<div>Total: COLOR: {{ColorCount}}</div>
Mahesh
la source
J'aime cette approche; semble moins hacky. Une clarification cependant, ng-init n'a pas besoin des accolades.
mklbtz
1
$scope.$watch('myVar', function (newValue, oldValue) {
        if (typeof (newValue) !== 'undefined') {
            $scope.someothervar= newValue;
//or get some data
            getData();
        }


    }, true);

La variable s'initialise après le contrôleur, vous devez donc la surveiller et l'utiliser lorsqu'elle n'est pas initialisée.

Senad Mulaosmanović
la source
0

J'aime la réponse mais je pense qu'il serait préférable de créer une fonction de portée globale qui vous permettra de définir la variable de portée nécessaire.

Donc, dans le globalController, créez

$scope.setScopeVariable = function(variable, value){
    $scope[variable] = value;
}

puis dans votre fichier html, appelez-le

{{setScopeVariable('myVar', 'whatever')}}

Cela vous permettra ensuite d'utiliser $ scope.myVar dans votre contrôleur respectif

Lance N. Solomon
la source
0

Si vous n'êtes pas dans une boucle, vous pouvez utiliser ng-init sinon vous pouvez utiliser

{{var=foo;""}}

le "" permet de ne pas afficher votre var

Yohann JAFFRES
la source