IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

AngularJS Discussion :

Déclaration dans un scope isolé


Sujet :

AngularJS

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éprouvé
    Profil pro
    Inscrit en
    Septembre 2007
    Messages
    125
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2007
    Messages : 125
    Par défaut Déclaration dans un scope isolé
    Bonjour,

    J'explore en ce moment les possibilités des directives d'angularJS et je suis tombé sur un os, si vous pouviez m'éclairer sur certaines logiques de programmations qui, apparemment, me font défaut, je vous en serais extrêmement reconnaissant.

    Voici mon template, un formulaire de connexion :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
                <login-form class="container-fluid navbar-form navbar-left" ng-submit="submit()">
                    <checked-input name="username" type="text" placeholder="login"></checked-input>
                    <checked-input name="password" type="password" placeholder="password"></checked-input>
     
                    <button type="submit" class="btn btn-default">log in</button>
                </login-form>
    Le checked-input est une directive correspondant à un input avec icône de confirmation style bootstrap ( un exemple sur l'image ci-après ) dont voici le template :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    <div class="form-group has-feedback">
        <label class="control-label" ng-class="{'sr-only': !label}">{{label}}</label>
        <input type="{{type}}" name="{{name}}" placeholder="{{placeholder}}" class="form-control" ng-model="chkInput.value">
        <span class="glyphicon form-control-feedback"></span>
    </div>


    Avant de parler des app.directive, je vous fait part de ma logique du code :
    L'idée est qu'en insérant une directive checked-input dans une page, les attributs qu'on a définit dans l'élément checked-input se répartissent sur les éléments enfants (par exemple, au-dessus j'ai crée un checked-input name="username", l'input aura donc le nom username.
    Pour la mise en place simple de ce fonctionnement, j'ai opté pour un scope isolé :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    app.directive('loginForm', function() {
        return {
            restrict: 'E',
            replace: true,
            transclude: true,
            template: '<form ng-transclude></form>',
            controller: ['$scope', '$http', function($scope, $http) {
     
                $scope.submit = function() {
                    $http.post(...
                    // pas vraiment nécessaire d'embrouiller mon code ici,
                    // seulement que j'utilise $scope.username.status(state) et $scope.password.status(state)
                    ...)
                }
            }]
        }
    });
     
    app.directive('checkedInput', function() {
        return {
            restrict: 'E',
            replace: true,
            scope: {
                chkInput: '=name',
                type: '@',
                name: '@',
                placeholder: '@',
                label: '@'
            },
            templateUrl: 'partials/chkInput.html',
            controller: ['$scope', function($scope) {
                $scope.chkInput = {
                    value: null,
                    parentStyle: null,
                    iconStyle: null,
                    status: function(state) {
                        if (state !== undefined) {
                            this.parentStyle = state ? 'has-success' : 'has-error';
                            this.iconStyle = state ? 'glyphicon-ok' : 'glyphicon-remove';
                        }
                        else {
                            this.parentStyle = null;
                            this.iconStyle = null
                        }
                    }
                };
            }]
        }
    });
    Ainsi, dans mon scope de la première instance de <checked-input> (name = "username"), $scope.chkInput est lié par data-binding au scope du <login-form> : $scope.username.
    L'idée est donc de déclarer $scope.username et $scope.password en déclarant $scope.chkInput dans la directive de l'élément enfant (car il est lié par databinding).

    Problème : Ce code ne fonctionne pas, pour la simple et bonne raison que le two-way-dataBinding permet de faire tout cela, excepté faire des déclarations dans l'élément enfant (<checked-input>). Je ne peux donc pas déclarer $scope.username de la directive <login-form> en déclarant $scope.chkInput de la directive <checked-input>.

    Solutions explorées :
    • Comme dans la doc d'angular : déclarer l'objet dans l'élement parent, mais pour des raisons évidentes de structure du code, c'est hors-propos.
    • Même si la directive est dans un scope isolé, le scope reste tout de même un enfant du scope de loginForm. On devrait donc pouvoir y accéder via $scope.$parent[$scope.name] = {..., mais pour des raisons qui m'échappent, celà ne fonctionne pas et cette objet n'est pas créé dans le scope parent.
    • Créer un contructeur de cet objet dans la directive enfant et y accéder en ajoutant require: '^checkedInput' dans la directive loginForm, j'aimerais éviter si possible.


    Je vous remercie d'avance si vous pouvez m'aider, je planche là-dessus depuis 2-3 jours et je vois vraiment pas comment m'en sortir .
    A+

    Kaari


    PS: si vous êtes d'attaque pour m'aider mais que mes faibles compétences linguistiques ne m'ont pas permis de vous expliquer clairement mon problème, je vous prie de m'en excuser et de ne pas hésiter à me dire que je me suis très mal expliqué et que vous ne comprenez rien à mon charabia .

  2. #2
    Expert confirmé
    Avatar de Marco46
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2005
    Messages
    4 419
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2005
    Messages : 4 419
    Par défaut
    Je ne comprends pas ce code, il y a une contradiction :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
     
    app.directive('checkedInput', function() {
        return {
            restrict: 'E',
            replace: true,
            scope: {
                chkInput: '=name',
                type: '@',
                name: '@',
                placeholder: '@',
                label: '@'
            },
            templateUrl: 'partials/chkInput.html',
            controller: ['$scope', function($scope) {
                $scope.chkInput = {
                    value: null,
                    parentStyle: null,
                    iconStyle: null,
                    status: function(state) {
                        if (state !== undefined) {
                            this.parentStyle = state ? 'has-success' : 'has-error';
                            this.iconStyle = state ? 'glyphicon-ok' : 'glyphicon-remove';
                        }
                        else {
                            this.parentStyle = null;
                            this.iconStyle = null
                        }
                    }
                };
            }]
        }
    });
    Dans ta déclaration du scope isolé tu dis que $scope.chkInput de ta directive est égal au contenu de l'attribut name de ta directive (via l'instruction '=name') puis dans le controleur de ta directive tu dis que $scope.chkInput est un objet complexe.

    Cela ne peut pas marcher !

    Par ailleurs, quand tu fais des bindings, n'utilise jamais de types primitifs c'est une source considérable de bugs.

    Ne fais pas
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    $scope.username = 'toto';
    $scope.password = 'tata';
    mais

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    $scope.user = {
        username: 'toto',
        password: 'tata'
    };
     
    // ou
     
    $scope.user = {};
    $scope.user.username = 'toto';
    $scope.user.password = 'tata';
    Dernier point, n'utilise pas de mots clefs d'un langage quelconque pour définir des variables de ton scope. Ou alors préfixe les.
    placeholder, name et type sont des mots clefs du html, cela crée de la confusion à la lecture je trouve.

    Mais bon, corrige déjà ta contradiction dans ton code et ça ira mieux

  3. #3
    Membre éprouvé
    Profil pro
    Inscrit en
    Septembre 2007
    Messages
    125
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2007
    Messages : 125
    Par défaut
    Bonjour Marco, merci pour ton aide

    J'ai pensé à ce que tu m'a dis et effectivement, c'est ultra-logique .

    J'ai modifié mon code en conséquence :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    // directive mère
                var username = $scope.username = {};
                var password = $scope.password = {};
    // ...
    // ...
    // directive fille :
    $scope.chkInput.style = {
                    global: null,
                    icon: null,
                    status: function (state) {
    //...
    //...
    J'ai aussi pensé à une manière plus générique pour la "copie" des attributs de la directive <checked-input> au champ input et j'ai ajouté un petit bout de code à la directive :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
            compile: function (elt, attrs) {
     
                var inputElt = elt.find('input');
     
                var hisOwnAttr = [
                    'style',
                    'class',
                    'ngClass'
                ];
                for(var attr in attrs) {
                    // for each attributes except his Own Attributes
                    if (typeof attrs[attr] === 'string' && hisOwnAttr.indexOf(attr) === -1) {
                        // copy attribute into <input>
                        inputElt.attr(attr, attrs[attr]);
                        // remove it from <checked-input>
                        elt.removeAttr(attr)
                    }
                }
            }
    Je trouve ça pas très propre mais je vois pas comment faire une directive de ce style et générique autrement :s.

Discussions similaires

  1. Réponses: 4
    Dernier message: 12/06/2007, 09h17
  2. attribut qui reste dans le scope
    Par gregounet dans le forum Struts 1
    Réponses: 3
    Dernier message: 19/04/2007, 10h15
  3. Déclaration dans ResourceBundle pour le multilinguisme
    Par thomzon dans le forum Struts 1
    Réponses: 1
    Dernier message: 13/04/2007, 16h11
  4. Servlet erreur de déclaration dans le web.xml
    Par mlequim dans le forum Servlets/JSP
    Réponses: 2
    Dernier message: 15/11/2005, 11h28
  5. Double déclaration dans un With
    Par Maglight dans le forum Langage
    Réponses: 4
    Dernier message: 24/08/2005, 18h19

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo