4 votes

Comment déplacer une vue dans le DOM avec angular.js ?

Comment déplacer un élément à différents endroits du DOM avec angular js ?

J'ai une liste d'éléments comme suit

<ul id="list" ng-controller="ListController">
    <li ng-controller="ItemController"><div>content</div></li>
    <li ng-controller="ItemController"><div>content</div></li>
    <li ng-controller="ItemController"><div>content</div></li>
    <li ng-controller="ItemController">
        <div>content</div>
        <div id="overlay"></div>
    </li>
</ul>

Ce que j'essaie d'accomplir, c'est de déplacer le #overlay d'un endroit à l'autre de la liste sans avoir à avoir un double caché dans chaque élément que je signale comme étant caché/non caché.

Si c'était jquery, je pourrais faire quelque chose comme ça :

$("#overlay").appendTo("#list li:first-child");

Existe-t-il un moyen équivalent de faire cela en angulaire ?

11voto

pkozlowski.opensource Points 52557

Grâce à vos éclaircissements, je comprends que vous avez une liste d'articles. Vous aimeriez pouvoir sélectionner un élément de cette liste (par balayage, mais aussi par d'autres événements potentiels), puis afficher un élément DOM supplémentaire (div) pour l'élément sélectionné. Si l'autre élément a été sélectionné, il doit être désélectionné - de cette façon, un div supplémentaire doit être affiché pour un seul élément.

Si la compréhension ci-dessus est correcte, alors vous pourriez résoudre ce problème avec les simples directives ng-repeat et ng-show comme ceci :

<ul ng-controller="ListController">
    <li ng-repeat="item in items">
        <div ng-click="open(item)">{{item.content}}</div>
        <div ng-show="isOpen(item)">overlay: tweet, share, pin</div>
    </li>
</ul>

où se trouve le code dans le contrôleur (en montrant un fragment seulement) :

$scope.open = function(item){
    if ($scope.isOpen(item)){
        $scope.opened = undefined;
    } else {
        $scope.opened = item;
    }        
};

$scope.isOpen = function(item){
    return $scope.opened === item;
};

Voici le jsFiddle complet : http://jsfiddle.net/pkozlowski_opensource/65Cxv/7/

Si vous craignez d'avoir trop d'éléments DOM, vous pouvez obtenir le même résultat en utilisant la directive ng-switch :

<ul ng-controller="ListController">
    <li ng-repeat="item in items">
        <div ng-click="open(item)">{{item.content}}</div>
        <ng-switch on="isOpen(item)">
            <div ng-switch-when="true">overlay: tweet, share, pin</div>
        </ng-switch>        
    </li>
</ul>

Voici le jsFiddle : http://jsfiddle.net/pkozlowski_opensource/bBtH3/2/

4voto

Mark Rajcok Points 85912

Comme exercice pour le lecteur (moi), j'ai voulu essayer une directive personnalisée pour accomplir ceci. Voici ce que j'ai trouvé (après de nombreuses tentatives infructueuses) :

<ul ng-controller="ListController">
    <li ng-repeat="item in items">
        <div singleton-overlay>{{item.content}}</div>
    </li>
</ul>

Un service est nécessaire pour stocker l'élément qui a actuellement la superposition, le cas échéant. (J'ai décidé de ne pas utiliser le contrôleur pour cela, car je pense qu'un 'service + directive' ferait un composant plus réutilisable qu'un 'contrôleur + directive').

service('singletonOverlayService', function() {
    this.overlayElement = undefined;
})

Et la directive :

directive('singletonOverlay', function(singletonOverlayService) {
    return {
        link: function(scope, element, attrs) {
            element.bind('click', moveOrToggleOverlay);

            function moveOrToggleOverlay() {
                if (singletonOverlayService.overlayElement === element) {
                    angular.element(element.children()).remove();
                    singletonOverlayService.overlayElement = undefined;
                } else {
                    if (singletonOverlayService.overlayElement != undefined) {
                        // this is a bit odd... modifying DOM elsewhere
                        angular.element(singletonOverlayService.overlayElement.children()).remove();
                    }
                    element.append('<div>overlay: tweet, share, pin</div>')
                    singletonOverlayService.overlayElement = element;

jsFiddle : http://jsfiddle.net/mrajcok/ya4De/

Je pense que l'implémentation est un peu non conventionnelle, cependant... la directive ne modifie pas seulement le DOM associé à son propre élément, mais elle peut aussi modifier le DOM associé à l'élément qui a actuellement la superposition.

J'ai essayé de mettre en place des $watches sur la portée et de faire en sorte que le singleton stocke et modifie les objets de la portée, mais je n'ai pas réussi à déclencher les $watches lorsque j'ai changé la portée à l'intérieur de la fonction moveOrToggleOverlay.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X