img angularjs

angularjs - img - ng src angular 6



¿Es posible hacer una vista de árbol con angular? (14)

Al hacer algo como esto, la mejor solución es una directiva recursiva. Sin embargo, cuando elabora una directiva de este tipo, descubre que AngularJS entra en un ciclo sin fin.

La solución para esto es dejar que la directiva elimine el elemento durante el evento de compilación y compilarlo manualmente y agregarlo en los eventos de enlace.

Descubrí esto en este hilo y resumí esta funcionalidad en un servicio .

module.factory(''RecursionHelper'', [''$compile'', function($compile){ return { /** * Manually compiles the element, fixing the recursion loop. * @param element * @param [link] A post-link function, or an object with function(s) registered via pre and post properties. * @returns An object containing the linking functions. */ compile: function(element, link){ // Normalize the link parameter if(angular.isFunction(link)){ link = { post: link }; } // Break the recursion loop by removing the contents var contents = element.contents().remove(); var compiledContents; return { pre: (link && link.pre) ? link.pre : null, /** * Compiles and re-adds the contents */ post: function(scope, element){ // Compile the contents if(!compiledContents){ compiledContents = $compile(contents); } // Re-add the compiled contents to the element compiledContents(scope, function(clone){ element.append(clone); }); // Call the post-linking function, if any if(link && link.post){ link.post.apply(null, arguments); } } }; } }; }]);

Con este servicio puede hacer fácilmente una directiva de árbol (u otras directivas recursivas). Aquí hay un ejemplo de una directiva de árbol:

module.directive("tree", function(RecursionHelper) { return { restrict: "E", scope: {family: ''=''}, template: ''<p>{{ family.name }}</p>''+ ''<ul>'' + ''<li ng-repeat="child in family.children">'' + ''<tree family="child"></tree>'' + ''</li>'' + ''</ul>'', compile: function(element) { return RecursionHelper.compile(element); } }; });

Vea este Plunker para una demostración. Me gusta esta solución mejor porque:

  1. No necesita una directiva especial que hace que su html sea menos limpio.
  2. La lógica de recursión se abstrae en el servicio RecursionHelper, por lo que mantiene sus directivas limpias.

Actualización: Se agregó soporte para funciones de enlace personalizadas.

Estoy buscando mostrar datos en una estructura de árbol en una aplicación web. Esperaba usar Angular para esta tarea.

Parece que ng-repeat me permitirá iterar a través de una lista de nodos, pero ¿cómo puedo anidar cuando aumenta la profundidad de un nodo determinado?

Probé el siguiente código , pero el escapado automático del HTML impide que funcione. Además, la etiqueta end ul está en el lugar equivocado.

Estoy bastante seguro de que estoy abordando este problema del todo mal.

¿Algunas ideas?


Aquí hay un ejemplo que usa una directiva recursiva: http://jsfiddle.net/n8dPm/ Tomado de https://groups.google.com/forum/#!topic/angular/vswXTes_FtM

module.directive("tree", function($compile) { return { restrict: "E", scope: {family: ''=''}, template: ''<p>{{ family.name }}</p>''+ ''<ul>'' + ''<li ng-repeat="child in family.children">'' + ''<tree family="child"></tree>'' + ''</li>'' + ''</ul>'', compile: function(tElement, tAttr) { var contents = tElement.contents().remove(); var compiledContents; return function(scope, iElement, iAttr) { if(!compiledContents) { compiledContents = $compile(contents); } compiledContents(scope, function(clone, scope) { iElement.append(clone); }); }; } }; });


Basado en la answer @ganaraj y la answer @dnc253, acabo de hacer una simple "directiva" para la estructura de árbol que tiene la función de selección, adición, eliminación y edición.

Jsfiddle: http://jsfiddle.net/yoshiokatsuneo/9dzsms7y/

HTML:

<script type="text/ng-template" id="tree_item_renderer.html"> <div class="node" ng-class="{selected: data.selected}" ng-click="select(data)"> <span ng-click="data.hide=!data.hide" style="display:inline-block; width:10px;"> <span ng-show="data.hide && data.nodes.length > 0" class="fa fa-caret-right">+</span> <span ng-show="!data.hide && data.nodes.length > 0" class="fa fa-caret-down">-</span> </span> <span ng-show="!data.editting" ng-dblclick="edit($event)" >{{data.name}}</span> <span ng-show="data.editting"><input ng-model="data.name" ng-blur="unedit()" ng-focus="f()"></input></span> <button ng-click="add(data)">Add node</button> <button ng-click="delete(data)" ng-show="data.parent">Delete node</button> </div> <ul ng-show="!data.hide" style="list-style-type: none; padding-left: 15px"> <li ng-repeat="data in data.nodes"> <recursive><sub-tree data="data"></sub-tree></recursive> </li> </ul> </script> <ul ng-app="Application" style="list-style-type: none; padding-left: 0"> <tree data=''{name: "Node", nodes: [],show:true}''></tree> </ul>

JavaScript:

angular.module("myApp",[]); /* https://.com/a/14657310/1309218 */ angular.module("myApp"). directive("recursive", function($compile) { return { restrict: "EACM", require: ''^tree'', priority: 100000, compile: function(tElement, tAttr) { var contents = tElement.contents().remove(); var compiledContents; return function(scope, iElement, iAttr) { if(!compiledContents) { compiledContents = $compile(contents); } compiledContents(scope, function(clone) { iElement.append(clone); }); }; } }; }); angular.module("myApp"). directive("subTree", function($timeout) { return { restrict: ''EA'', require: ''^tree'', templateUrl: ''tree_item_renderer.html'', scope: { data: ''='', }, link: function(scope, element, attrs, treeCtrl) { scope.select = function(){ treeCtrl.select(scope.data); }; scope.delete = function() { scope.data.parent.nodes.splice(scope.data.parent.nodes.indexOf(scope.data), 1); }; scope.add = function() { var post = scope.data.nodes.length + 1; var newName = scope.data.name + ''-'' + post; scope.data.nodes.push({name: newName,nodes: [],show:true, parent: scope.data}); }; scope.edit = function(event){ scope.data.editting = true; $timeout(function(){event.target.parentNode.querySelector(''input'').focus();}); }; scope.unedit = function(){ scope.data.editting = false; }; } }; }); angular.module("myApp"). directive("tree", function(){ return { restrict: ''EA'', template: ''<sub-tree data="data" root="data"></sub-tree>'', controller: function($scope){ this.select = function(data){ if($scope.selected){ $scope.selected.selected = false; } data.selected = true; $scope.selected = data; }; }, scope: { data: ''='', } } });


Cuando la estructura del árbol es grande, Angular (hasta 1.4.x) se vuelve muy lento en la representación de una plantilla recursiva. Después de probar varias de estas sugerencias, terminé creando una cadena HTML simple y usando ng-bind-html para mostrarla. Por supuesto, esta no es la forma de usar las características angulares

Aquí se muestra una función recursiva escueta (con HTML mínimo):

function menu_tree(menu, prefix) { var html = ''<div>'' + prefix + menu.menu_name + '' - '' + menu.menu_desc + ''</div>/n''; if (!menu.items) return html; prefix += menu.menu_name + ''/''; for (var i=0; i<menu.items.length; ++i) { var item = menu.items[i]; html += menu_tree(item, prefix); } return html; } // Generate the tree view and tell Angular to trust this HTML $scope.html_menu = $sce.trustAsHtml(menu_tree(menu, ''''));

En la plantilla, solo necesita esta línea:

<div ng-bind-html="html_menu"></div>

Esto omite todos los enlaces de datos de Angular y simplemente muestra el HTML en una fracción del tiempo de los métodos de plantilla recursiva.

Con una estructura de menú como esta (un árbol de archivos parcial de un sistema de archivos Linux):

menu = {menu_name: '''', menu_desc: ''root'', items: [ {menu_name: ''bin'', menu_desc: ''Essential command binaries'', items: [ {menu_name: ''arch'', menu_desc: ''print machine architecture''}, {menu_name: ''bash'', menu_desc: ''GNU Bourne-Again SHell''}, {menu_name: ''cat'', menu_desc: ''concatenate and print files''}, {menu_name: ''date'', menu_desc: ''display or set date and time''}, {menu_name: ''...'', menu_desc: ''other files''} ]}, {menu_name: ''boot'', menu_desc: ''Static files of the boot loader''}, {menu_name: ''dev'', menu_desc: ''Device files''}, {menu_name: ''etc'', menu_desc: ''Host-specific system configuration''}, {menu_name: ''lib'', menu_desc: ''Essential shared libraries and kernel modules''}, {menu_name: ''media'', menu_desc: ''Mount point for removable media''}, {menu_name: ''mnt'', menu_desc: ''Mount point for mounting a filesystem temporarily''}, {menu_name: ''opt'', menu_desc: ''Add-on application software packages''}, {menu_name: ''sbin'', menu_desc: ''Essential system binaries''}, {menu_name: ''srv'', menu_desc: ''Data for services provided by this system''}, {menu_name: ''tmp'', menu_desc: ''Temporary files''}, {menu_name: ''usr'', menu_desc: ''Secondary hierarchy'', items: [ {menu_name: ''bin'', menu_desc: ''user utilities and applications''}, {menu_name: ''include'', menu_desc: ''''}, {menu_name: ''local'', menu_desc: '''', items: [ {menu_name: ''bin'', menu_desc: ''local user binaries''}, {menu_name: ''games'', menu_desc: ''local user games''} ]}, {menu_name: ''sbin'', menu_desc: ''''}, {menu_name: ''share'', menu_desc: ''''}, {menu_name: ''...'', menu_desc: ''other files''} ]}, {menu_name: ''var'', menu_desc: ''Variable data''} ] }

El resultado se convierte en:

- root /bin - Essential command binaries /bin/arch - print machine architecture /bin/bash - GNU Bourne-Again SHell /bin/cat - concatenate and print files /bin/date - display or set date and time /bin/... - other files /boot - Static files of the boot loader /dev - Device files /etc - Host-specific system configuration /lib - Essential shared libraries and kernel modules /media - Mount point for removable media /mnt - Mount point for mounting a filesystem temporarily /opt - Add-on application software packages /sbin - Essential system binaries /srv - Data for services provided by this system /tmp - Temporary files /usr - Secondary hierarchy /usr/bin - user utilities and applications /usr/include - /usr/local - /usr/local/bin - local user binaries /usr/local/games - local user games /usr/sbin - /usr/share - /usr/... - other files /var - Variable data




No complicado.

<div ng-app="Application" ng-controller="TreeController"> <table> <thead> <tr> <th>col 1</th> <th>col 2</th> <th>col 3</th> </tr> </thead> <tbody ng-repeat="item in tree"> <tr> <td>{{item.id}}</td> <td>{{item.fname}}</td> <td>{{item.lname}}</td> </tr> <tr ng-repeat="children in item.child"> <td style="padding-left:15px;">{{children.id}}</td> <td>{{children.fname}}</td> </tr> </tbody> </table> </div>

código del controlador:

angular.module("myApp", []). controller("TreeController", [''$scope'', function ($scope) { $scope.tree = [{ id: 1, fname: "tree", child: [{ id: 1, fname: "example" }], lname: "grid" }]; }]);


Otro ejemplo basado en la fuente original , con una estructura de árbol de muestra ya en su lugar (más fácil de ver cómo funciona IMO) y un filtro para buscar en el árbol:

JSFiddle


Puede usar un inyector de recursión angular para eso: https://github.com/knyga/angular-recursion-injector

Le permite hacer anidamiento ilimitado en profundidad con acondicionamiento. Recopila solo si es necesario y compila solo los elementos correctos. Sin magia en el código.

<div class="node"> <span>{{name}}</span> <node--recursion recursion-if="subNode" ng-model="subNode"></node--recursion> </div>

Una de las cosas que le permite trabajar más rápido y más simple que las otras soluciones es el sufijo "--recisión".


Puedes probar con Angular-Tree-DnD sample con Angular-Ui-Tree, pero Angular-Tree-DnD , compatibilidad con table, grid, list.

  • Arrastrar y soltar Able
  • Directiva de función extendida para list (next, prev, getChildren, ...)
  • Filtrar datos
  • OrderBy (ver)

Sí, definitivamente es posible. La pregunta aquí probablemente asume Angular 1.x, pero para referencia futura incluyo un ejemplo de Angular 2:

Conceptualmente, todo lo que tiene que hacer es crear una plantilla recursiva:

<ul> <li *for="#dir of directories"> <span><input type="checkbox" [checked]="dir.checked" (click)="dir.check()" /></span> <span (click)="dir.toggle()">{{ dir.name }}</span> <div *if="dir.expanded"> <ul *for="#file of dir.files"> {{file}} </ul> <tree-view [directories]="dir.directories"></tree-view> </div> </li> </ul>

A continuación, enlaza un objeto de árbol con la plantilla y deja que Angular trabaje su magia. Este concepto es obviamente aplicable también a Angular 1.x.

Aquí hay un ejemplo completo: http://www.syntaxsuccess.com/viewarticle/recursive-treeview-in-angular-2.0


Si está utilizando Bootstrap CSS ...

He creado un control de árbol (directiva) reutilizable simple para AngularJS basado en una lista de "navegación" de Bootstrap. Agregué indentación adicional, íconos y animación. Los atributos HTML se usan para la configuración.

No usa recursividad.

Lo llamé angular-bootstrap-nav-tree (nombre pegadizo, ¿no crees?)

Aquí hay un ejemplo, y la fuente está here .


Tantas soluciones geniales, pero siento que todas, de una forma u otra, complican un poco las cosas.

Quería crear algo que recreara la simplicidad de Awnser de @Mark Lagendijk, pero sin definir una plantilla en la directiva, sino que permitiría al "usuario" crear la plantilla en HTML ...

Con ideas tomadas de https://github.com/stackfull/angular-tree-repeat etc. Terminé creando el proyecto: https://github.com/dotJEM/angular-tree

Lo cual te permite construir tu árbol como:

<ul dx-start-with="rootNode"> <li ng-repeat="node in $dxPrior.nodes"> {{ node.name }} <ul dx-connect="node"/> </li> </ul>

Lo que para mí es más limpio que tener que crear directivas múltiples para árboles con estructura diferente ... En esencia, llamar al árbol de arriba es un poco falso, recoge mucho más de la frase de @renaraj de "plantillas recursivas", pero nos permite define la plantilla donde necesitamos el árbol.

(Podrías hacer eso con una plantilla basada en una etiqueta de script, pero todavía tiene que sentarse justo fuera del nodo del árbol real, y todavía se siente un poco raro ...)

Dejado aquí solo por otra elección ...