การเรียกซ้ำในคำสั่งเชิงมุม


178

มีคำถามเกี่ยวกับการทำมุมคำสั่งแบบเรียกซ้ำซึ่งเป็นที่นิยมซึ่งมีทั้งหมดหนึ่งคำตอบต่อไปนี้:

คนแรกมีปัญหาที่คุณไม่สามารถลบรหัสที่รวบรวมไว้ก่อนหน้านี้เว้นแต่ว่าคุณจะจัดการกระบวนการรวบรวมด้วยตนเองอย่างละเอียด แนวทางที่สองมีปัญหาว่า ... ไม่ใช่คำสั่งและขาดความสามารถอันทรงพลัง แต่ยิ่งเร่งด่วนมันไม่สามารถกำหนดพารามิเตอร์แบบเดียวกับที่คำสั่งนั้นสามารถทำได้ มันเพิ่งถูกผูกไว้กับอินสแตนซ์ตัวควบคุมใหม่

ฉันได้เล่นกับการทำงานด้วยตนเองangular.bootstrapหรือ@compile()ในฟังก์ชั่นการเชื่อมโยง แต่นั่นทำให้ฉันมีปัญหาในการติดตามองค์ประกอบด้วยตนเองเพื่อลบและเพิ่ม

มีวิธีที่ดีที่จะมีรูปแบบแบบเรียกซ้ำพารามิเตอร์ที่จัดการการเพิ่ม / ลบองค์ประกอบเพื่อสะท้อนสถานะ runtime หรือไม่? กล่าวคือต้นไม้ที่มีปุ่มเพิ่ม / ลบโหนดและฟิลด์อินพุตบางฟิลด์ที่ค่าถูกส่งผ่านโหนดชายด์ของโหนด อาจเป็นการรวมกันของแนวทางที่สองเข้ากับขอบเขตที่ถูกล่ามโซ่ (แต่ฉันไม่รู้ว่าจะทำอย่างไร)

คำตอบ:


316

แรงบันดาลใจจากการแก้ปัญหาที่อธิบายไว้ในหัวข้อดังกล่าวโดย @ dnc253 ผมใจลอยฟังก์ชันการทำงานที่เรียกซ้ำตัวเองเข้าไปในบริการ

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);
                    }
                }
            };
        }
    };
}]);

ซึ่งใช้ดังนี้:

module.directive("tree", ["RecursionHelper", 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) {
            // Use the compile function from the RecursionHelper,
            // And return the linking function(s) which it returns
            return RecursionHelper.compile(element);
        }
    };
}]);

ดูPlunkerนี้สำหรับการสาธิต ฉันชอบวิธีนี้ดีที่สุดเพราะ:

  1. คุณไม่จำเป็นต้องมีคำสั่งพิเศษซึ่งทำให้ html ของคุณสะอาดน้อยลง
  2. ตรรกะการเรียกซ้ำถูกแยกออกไปยังบริการ RecursionHelper ดังนั้นคุณจึงรักษาคำสั่งของคุณให้สะอาด

อัปเดต: ตั้งแต่ Angular 1.5.x ไม่จำเป็นต้องใช้ลูกเล่นเพิ่มเติม แต่ใช้ได้กับเทมเพลตเท่านั้นไม่ใช่กับtemplateUrl


3
ขอบคุณทางออกที่ยอดเยี่ยม! ทำความสะอาดและทำงานนอกกรอบจริงๆสำหรับฉันเพื่อสอบถามซ้ำระหว่างสองแนวทางที่รวมถึงงานอื่น
jssebastian

6
ปัญหาดั้งเดิมคือเมื่อคุณใช้คำสั่งแบบเรียกซ้ำ AngularJS จะวนซ้ำไม่รู้จบ รหัสนี้แบ่งลูปนี้โดยการลบเนื้อหาในระหว่างการรวบรวมเหตุการณ์ของคำสั่งและการรวบรวมและการเพิ่มเนื้อหาในเหตุการณ์ลิงค์ของคำสั่ง
Mark Lagendijk

15
ในตัวอย่างของคุณคุณสามารถแทนที่ด้วยcompile: function(element) { return RecursionHelper.compile(element); } compile: RecursionHelper.compile
เปาโล Moretti

1
ถ้าคุณต้องการให้เทมเพลตอยู่ในไฟล์ภายนอก
CodyBugstein

2
นี่คือความสง่างามในแง่ที่ว่า / เมื่อ Angular core ใช้การสนับสนุนที่คล้ายกันคุณสามารถลบ wrapper คอมไพล์ที่กำหนดเองและรหัสที่เหลือทั้งหมดจะยังคงเหมือนเดิม
Carlo Bonamico

25

การเพิ่มองค์ประกอบด้วยตนเองและรวบรวมพวกเขาเป็นวิธีที่สมบูรณ์แบบแน่นอน หากคุณใช้ ng-repeat คุณจะไม่ต้องลบองค์ประกอบด้วยตนเอง

ตัวอย่าง: http://jsfiddle.net/KNM4q/113/

.directive('tree', function ($compile) {
return {
    restrict: 'E',
    terminal: true,
    scope: { val: '=', parentData:'=' },
    link: function (scope, element, attrs) {
        var template = '<span>{{val.text}}</span>';
        template += '<button ng-click="deleteMe()" ng-show="val.text">delete</button>';

        if (angular.isArray(scope.val.items)) {
            template += '<ul class="indent"><li ng-repeat="item in val.items"><tree val="item" parent-data="val.items"></tree></li></ul>';
        }
        scope.deleteMe = function(index) {
            if(scope.parentData) {
                var itemIndex = scope.parentData.indexOf(scope.val);
                scope.parentData.splice(itemIndex,1);
            }
            scope.val = {};
        };
        var newElement = angular.element(template);
        $compile(newElement)(scope);
        element.replaceWith(newElement);
    }
}
});

1
ฉันอัปเดตสคริปต์ของคุณเพื่อให้มีเพียงคำสั่งเดียว jsfiddle.net/KNM4q/103เราจะทำให้ปุ่มลบทำงานได้อย่างไร
Benny Bottema

ดีมาก! ฉันใกล้มาก แต่ไม่มี @position (ฉันคิดว่าฉันสามารถหามันได้ด้วย parentData [val] หากคุณอัปเดตคำตอบของคุณด้วยรุ่นสุดท้าย ( jsfiddle.net/KNM4q/111 ) ฉันจะยอมรับมัน
Benny Bottema

12

ผมไม่ทราบว่าถ้าแก้ปัญหานี้จะพบได้ในหนึ่งในตัวอย่างที่คุณที่เชื่อมโยงหรือแนวความคิดพื้นฐานที่เหมือนกัน แต่ฉันมีความต้องการของการสั่ง recursive และผมพบว่าดีแก้ปัญหาง่าย

module.directive("recursive", function($compile) {
    return {
        restrict: "EACM",
        priority: 100000,
        compile: function(tElement, tAttr) {
            var contents = tElement.contents().remove();
            var compiledContents;
            return function(scope, iElement, iAttr) {
                if(!compiledContents) {
                    compiledContents = $compile(contents);
                }
                iElement.append(
                    compiledContents(scope, 
                                     function(clone) {
                                         return clone; }));
            };
        }
    };
});

module.directive("tree", function() {
    return {
        scope: {tree: '='},
        template: '<p>{{ tree.text }}</p><ul><li ng-repeat="child in tree.children"><recursive><span tree="child"></span></recursive></li></ul>',
        compile: function() {
            return  function() {
            }
        }
    };
});​

คุณควรสร้างrecursiveคำสั่งและล้อมรอบองค์ประกอบที่ทำให้เกิดการเรียกซ้ำ


1
@MarkError และ @ dnc253 สิ่งนี้มีประโยชน์ แต่ฉันมักจะได้รับข้อผิดพลาดต่อไปนี้:[$compile:multidir] Multiple directives [tree, tree] asking for new/isolated scope on: <recursive tree="tree">
Jack

1
หากบุคคลอื่นกำลังประสบกับข้อผิดพลาดนี้เพียงคุณ (หรือ Yoeman) ไม่ได้รวมไฟล์ JavaScript ใด ๆ มากกว่าหนึ่งครั้ง ยังไงก็ตามไฟล์ main.js ของฉันถูกรวมสองครั้งดังนั้นจึงมีการสร้างคำสั่งสองชื่อที่มีชื่อเดียวกัน หลังจากลบหนึ่งใน JS แล้วรหัสก็ใช้ได้
แจ็ค

2
@ แจ็คขอบคุณสำหรับการชี้ให้เห็นว่า เพียงใช้เวลาหลายชั่วโมงในการแก้ไขปัญหานี้และความคิดเห็นของคุณชี้ให้ฉันไปในทิศทางที่ถูกต้อง สำหรับผู้ใช้ ASP.NET ที่ใช้บริการบันเดิลตรวจสอบให้แน่ใจว่าคุณไม่มีไฟล์เวอร์ชันย่อขนาดเล็กในไดเรกทอรีในขณะที่คุณใช้ไวด์การ์ดรวมอยู่ในบันเดิล
เบเยอร์

สำหรับฉันองค์ประกอบที่จำเป็นในการเพิ่มภายในการโทรกลับเช่น:. compiledContents(scope,function(clone) { iElement.append(clone); });อื่น ๆ "ต้องการ" ควบคุม ed ไม่ได้จัดการอย่างถูกต้องและข้อผิดพลาด: Error: [$compile:ctreq] Controller 'tree', required by directive 'subTreeDirective', can't be found!สาเหตุ
Tsuneo Yoshioka

ฉันพยายามที่จะสร้างโครงสร้างต้นไม้ด้วย angs js แต่ติดอยู่กับที่
Learning-Overthinker-Confused

10

ตั้งแต่ Angular 1.5.x ไม่ต้องใช้อุบายอีกต่อไปจึงสามารถทำสิ่งต่อไปนี้ได้ ไม่ต้องทำงานสกปรกอีกต่อไป!

การค้นพบนี้เป็นผลพลอยได้จากการตามล่าของฉันสำหรับวิธีแก้ปัญหาที่ดีกว่า / สะอาดกว่าสำหรับคำสั่งแบบเรียกซ้ำ คุณสามารถพบได้ที่นี่https://jsfiddle.net/cattails27/5j5au76c/ สนับสนุนเท่าที่เป็น 1.3.x

angular.element(document).ready(function() {
  angular.module('mainApp', [])
    .controller('mainCtrl', mainCtrl)
    .directive('recurv', recurveDirective);

  angular.bootstrap(document, ['mainApp']);

  function recurveDirective() {
    return {
      template: '<ul><li ng-repeat="t in tree">{{t.sub}}<recurv tree="t.children"></recurv></li></ul>',
      scope: {
        tree: '='
      },
    }
  }

});

  function mainCtrl() {
    this.tree = [{
      title: '1',
      sub: 'coffee',
      children: [{
        title: '2.1',
        sub: 'mocha'
      }, {
        title: '2.2',
        sub: 'latte',
        children: [{
          title: '2.2.1',
          sub: 'iced latte'
        }]
      }, {
        title: '2.3',
        sub: 'expresso'
      }, ]
    }, {
      title: '2',
      sub: 'milk'
    }, {
      title: '3',
      sub: 'tea',
      children: [{
        title: '3.1',
        sub: 'green tea',
        children: [{
          title: '3.1.1',
          sub: 'green coffee',
          children: [{
            title: '3.1.1.1',
            sub: 'green milk',
            children: [{
              title: '3.1.1.1.1',
              sub: 'black tea'
            }]
          }]
        }]
      }]
    }];
  }
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.8/angular.min.js"></script>
<div>
  <div ng-controller="mainCtrl as vm">
    <recurv tree="vm.tree"></recurv>
  </div>
</div>


1
ขอบคุณสำหรับสิ่งนี้. คุณช่วยนำฉันไปที่รายการเปลี่ยนแปลงที่แนะนำคุณสมบัตินี้ได้ ขอบคุณ!
Steven

การใช้เชิงมุม 1.5.x นั้นสำคัญมาก 1.4.x จะไม่ทำงานและเป็นรุ่นที่ให้ใน jsfiddle
Paqman

ใน jsfiddle jsfiddle.net/cattails27/5j5au76c ไม่มีรหัสเดียวกันของคำตอบนี้ ... ใช่ไหม? สิ่งที่ฉันหายไป?
เปาโลเบียวาติ

ซอแสดงให้เห็นถึงรุ่นเชิงมุมน้อยกว่า 1.5x
jkris

4

หลังจากใช้วิธีแก้ปัญหาหลายวิธีมาระยะหนึ่งฉันกลับมาที่ปัญหานี้ซ้ำ

ฉันไม่พอใจกับโซลูชันการบริการเนื่องจากใช้ได้กับคำสั่งที่สามารถฉีดเซอร์วิสได้ แต่ไม่สามารถทำงานกับแฟรกเมนต์เทมเพลตนิรนาม

ในทำนองเดียวกันการแก้ปัญหาที่ขึ้นอยู่กับโครงสร้างแม่แบบที่เฉพาะเจาะจงโดยทำการจัดการ DOM ในคำสั่งนั้นเฉพาะเจาะจงและเปราะเกินไป

ฉันมีสิ่งที่ฉันเชื่อว่าเป็นวิธีการแก้ปัญหาทั่วไปที่ห่อหุ้มการเรียกซ้ำเป็นคำสั่งของตัวเองที่รบกวนน้อยที่สุดกับคำสั่งอื่น ๆ และสามารถนำมาใช้โดยไม่ระบุชื่อ

ด้านล่างนี้เป็นการสาธิตที่คุณสามารถเล่นด้วยได้ที่ plnkr: http://plnkr.co/edit/MSiwnDFD81HAOXWvQWIM

var hCollapseDirective = function () {
  return {
    link: function (scope, elem, attrs, ctrl) {
      scope.collapsed = false;
      scope.$watch('collapse', function (collapsed) {
        elem.toggleClass('collapse', !!collapsed);
      });
    },
    scope: {},
    templateUrl: 'collapse.html',
    transclude: true
  }
}

var hRecursiveDirective = function ($compile) {
  return {
    link: function (scope, elem, attrs, ctrl) {
      ctrl.transclude(scope, function (content) {
        elem.after(content);
      });
    },
    controller: function ($element, $transclude) {
      var parent = $element.parent().controller('hRecursive');
      this.transclude = angular.isObject(parent)
        ? parent.transclude
        : $transclude;
    },
    priority: 500,  // ngInclude < hRecursive < ngIf < ngRepeat < ngSwitch
    require: 'hRecursive',
    terminal: true,
    transclude: 'element',
    $$tlb: true  // Hack: allow multiple transclusion (ngRepeat and ngIf)
  }
}

angular.module('h', [])
.directive('hCollapse', hCollapseDirective)
.directive('hRecursive', hRecursiveDirective)
/* Demo CSS */
* { box-sizing: border-box }

html { line-height: 1.4em }

.task h4, .task h5 { margin: 0 }

.task { background-color: white }

.task.collapse {
  max-height: 1.4em;
  overflow: hidden;
}

.task.collapse h4::after {
  content: '...';
}

.task-list {
  padding: 0;
  list-style: none;
}


/* Collapse directive */
.h-collapse-expander {
  background: inherit;
  position: absolute;
  left: .5px;
  padding: 0 .2em;
}

.h-collapse-expander::before {
  content: '•';
}

.h-collapse-item {
  border-left: 1px dotted black;
  padding-left: .5em;
}

.h-collapse-wrapper {
  background: inherit;
  padding-left: .5em;
  position: relative;
}
<!DOCTYPE html>
<html>

  <head>
    <link href="collapse.css" rel="stylesheet" />
    <link href="style.css" rel="stylesheet" />
    <script data-require="angular.js@1.3.15" data-semver="1.3.15" src="https://code.angularjs.org/1.3.15/angular.js"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.min.js" data-semver="2.1.1" data-require="jquery@*"></script>
    <script src="script.js"></script>
    <script>
      function AppController($scope) {
        $scope.toggleCollapsed = function ($event) {
          $event.preventDefault();
          $event.stopPropagation();
          this.collapsed = !this.collapsed;
        }
        
        $scope.task = {
          name: 'All tasks',
          assignees: ['Citizens'],
          children: [
            {
              name: 'Gardening',
              assignees: ['Gardeners', 'Horticulture Students'],
              children: [
                {
                  name: 'Pull weeds',
                  assignees: ['Weeding Sub-committee']
                }
              ],
            },
            {
              name: 'Cleaning',
              assignees: ['Cleaners', 'Guests']
            }
          ]
        }
      }
      
      angular.module('app', ['h'])
      .controller('AppController', AppController)
    </script>
  </head>

  <body ng-app="app" ng-controller="AppController">
    <h1>Task Application</h1>
    
    <p>This is an AngularJS application that demonstrates a generalized
    recursive templating directive. Use it to quickly produce recursive
    structures in templates.</p>
    
    <p>The recursive directive was developed in order to avoid the need for
    recursive structures to be given their own templates and be explicitly
    self-referential, as would be required with ngInclude. Owing to its high
    priority, it should also be possible to use it for recursive directives
    (directives that have templates which include the directive) that would
    otherwise send the compiler into infinite recursion.</p>
    
    <p>The directive can be used alongside ng-if
    and ng-repeat to create recursive structures without the need for
    additional container elements.</p>
    
    <p>Since the directive does not request a scope (either isolated or not)
    it should not impair reasoning about scope visibility, which continues to
    behave as the template suggests.</p>
    
    <p>Try playing around with the demonstration, below, where the input at
    the top provides a way to modify a scope attribute. Observe how the value
    is visible at all levels.</p>
    
    <p>The collapse directive is included to further demonstrate that the
    recursion can co-exist with other transclusions (not just ngIf, et al)
    and that sibling directives are included on the recursive due to the
    recursion using whole 'element' transclusion.</p>
    
    <label for="volunteer">Citizen name:</label>
    <input id="volunteer" ng-model="you" placeholder="your name">
    <h2>Tasks</h2>
    <ul class="task-list">
      <li class="task" h-collapse h-recursive>
        <h4>{{task.name}}</h4>
        <h5>Volunteers</h5>
        <ul>
          <li ng-repeat="who in task.assignees">{{who}}</li>
          <li>{{you}} (you)</li>
        </ul>
        <ul class="task-list">
          <li h-recursive ng-repeat="task in task.children"></li>
        </ul>
      <li>
    </ul>
    
    <script type="text/ng-template" id="collapse.html">
      <div class="h-collapse-wrapper">
        <a class="h-collapse-expander" href="#" ng-click="collapse = !collapse"></a>
        <div class="h-collapse-item" ng-transclude></div>
      </div>
    </script>
  </body>

</html>


2

ตอนนี้ Angular 2.0 แสดงตัวอย่างแล้วฉันคิดว่ามันโอเคที่จะเพิ่มทางเลือก Angular 2.0 ลงในส่วนผสม อย่างน้อยมันจะเป็นประโยชน์ต่อผู้คนในภายหลัง:

แนวคิดหลักคือการสร้างเทมเพลตแบบเรียกซ้ำด้วยการอ้างอิงตนเอง:

<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>

จากนั้นคุณผูกวัตถุต้นไม้กับแม่แบบและดูการสอบถามซ้ำดูแลส่วนที่เหลือ นี่คือตัวอย่างเต็มรูปแบบ: http://www.syntaxsuccess.com/viewarticle/recursive-treeview-in-angular-2.0


2

มีวิธีแก้ปัญหาง่ายๆจริง ๆ สำหรับสิ่งนี้ที่ไม่ต้องการคำสั่งเลย

ในความหมายนั้นบางทีมันอาจไม่ใช่วิธีแก้ปัญหาดั้งเดิมหากคุณคิดว่าคุณต้องการคำสั่ง แต่มันเป็นวิธีแก้ปัญหาหากคุณต้องการโครงสร้าง GUI แบบเรียกซ้ำที่มีโครงสร้างย่อยแบบย่อยของ GUI ซึ่งอาจเป็นสิ่งที่คุณต้องการ

วิธีการแก้ปัญหานั้นขึ้นอยู่กับเพียงแค่ใช้ ng-controller, ng-init และ ng-include เพียงทำดังนี้สมมติว่าคอนโทรลเลอร์ของคุณเรียกว่า "MyController" เทมเพลตของคุณอยู่ใน myTemplate.html และคุณมีฟังก์ชั่นการเริ่มต้นบนคอนโทรลเลอร์ที่เรียกว่า init ซึ่งรับอาร์กิวเมนต์ A, B และ C แก้ไขตัวควบคุมของคุณ จากนั้นวิธีแก้ปัญหามีดังนี้:

myTemplate.htlm:

<div> 
    <div>Hello</div>
    <div ng-if="some-condition" ng-controller="Controller" ng-init="init(A, B, C)">
       <div ng-include="'myTemplate.html'"></div>
    </div>
</div>

ฉันพบโดยบังเอิญว่าโครงสร้างชนิดนี้สามารถเกิดขึ้นซ้ำได้ตามที่คุณต้องการในมุมวานิลลาธรรมดา เพียงทำตามรูปแบบการออกแบบนี้และคุณสามารถใช้โครงสร้าง UI แบบเรียกซ้ำโดยไม่มีการคอมไพล์ขั้นสูงอื่น ๆ

ภายในตัวควบคุมของคุณ:

$scope.init = function(A, B, C) {
   // Do something with A, B, C
   $scope.D = A + B; // D can be passed on to other controllers in myTemplate.html
} 

ข้อเสียเดียวที่ฉันเห็นคือไวยากรณ์ clunky ที่คุณต้องทน


ฉันกลัวว่าสิ่งนี้จะล้มเหลวในการแก้ปัญหาด้วยวิธีการพื้นฐาน: ด้วยวิธีนี้คุณจะต้องทราบความลึกของการเรียกซ้ำเพื่อให้มีตัวควบคุมที่เพียงพอใน myTemplate.html
Stewart_R

จริงๆแล้วคุณทำไม่ได้ เนื่องจากไฟล์ของคุณ myTemplate.html มีการอ้างอิงตัวเองกับ myTemplate.html โดยใช้ ng-include (เนื้อหา html ด้านบนคือเนื้อหาของ myTemplate.html อาจไม่ได้ระบุไว้อย่างชัดเจน) วิธีนั้นจะกลายเป็นแบบเรียกซ้ำอย่างแท้จริง ฉันใช้เทคนิคในการผลิต
erobwen

นอกจากนี้อาจจะไม่ได้ระบุไว้อย่างชัดเจนว่าคุณต้องใช้ ng-if เพื่อยกเลิกการสอบถามซ้ำ ดังนั้น myTemplate.html ของคุณจึงเป็นแบบฟอร์มที่อัปเดตในความคิดเห็นของฉัน
erobwen

0

คุณสามารถใช้ angular-recursion-injector เพื่อ: https://github.com/knyga/angular-recursion-injector

ช่วยให้คุณสามารถทำรังแบบลึกได้ไม่ จำกัด ด้วยการปรับสภาพ ทำการคอมไพล์ซ้ำหากจำเป็นและคอมไพล์องค์ประกอบที่ถูกต้องเท่านั้น ไม่มีเวทมนตร์ในรหัส

<div class="node">
  <span>{{name}}</span>

  <node--recursion recursion-if="subNode" ng-model="subNode"></node--recursion>
</div>

หนึ่งในสิ่งที่ช่วยให้มันทำงานได้เร็วขึ้นและง่ายขึ้นแล้วโซลูชันอื่น ๆ คือส่วนต่อท้าย "--recursion"


0

ฉันสิ้นสุดการสร้างชุดคำสั่งพื้นฐานสำหรับการสอบถามซ้ำ

IMO มันเป็นพื้นฐานมากกว่าโซลูชันที่พบที่นี่และมีความยืดหยุ่นถ้าไม่มากกว่าดังนั้นเราจึงไม่ผูกพันกับการใช้โครงสร้าง UL / LI ฯลฯ ... แต่เห็นได้ชัดว่าผู้ใช้เหมาะสม แต่คำสั่งนี้ไม่ทราบ ความเป็นจริง ...

ตัวอย่างที่ง่ายที่สุดคือ:

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

การใช้งาน 'dx-start-with' an 'dx-connect' ดูได้ที่: https://github.com/dotJEM/angular-tree

ซึ่งหมายความว่าคุณไม่จำเป็นต้องสร้างคำสั่ง 8 คำสั่งถ้าคุณต้องการรูปแบบที่แตกต่างกัน 8 แบบ

หากต้องการสร้างมุมมองแบบต้นไม้ด้านบนของตำแหน่งที่คุณสามารถเพิ่มหรือลบโหนดได้ค่อนข้างง่าย เช่นเดียวกับใน: http://codepen.io/anon/pen/BjXGbY?editors=1010

angular
  .module('demo', ['dotjem.angular.tree'])
  .controller('AppController', function($window) {

this.rootNode = {
  name: 'root node',
  children: [{
    name: 'child'
  }]
};

this.addNode = function(parent) {
  var name = $window.prompt("Node name: ", "node name here");
  parent.children = parent.children || [];
  parent.children.push({
    name: name
  });
}

this.removeNode = function(parent, child) {
  var index = parent.children.indexOf(child);
  if (index > -1) {
    parent.children.splice(index, 1);
  }
}

  });
<div ng-app="demo" ng-controller="AppController as app">
  HELLO TREE
  <ul dx-start-with="app.rootNode">
<li><button ng-click="app.addNode($dxPrior)">Add</button></li>
<li ng-repeat="node in $dxPrior.children">
  {{ node.name }} 
  <button ng-click="app.removeNode($dxPrior, node)">Remove</button>
  <ul dx-connect="node" />
</li>
  </ul>

  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular.min.js"></script>
  <script src="https://rawgit.com/dotJEM/angular-tree-bower/master/dotjem-angular-tree.min.js"></script>

</div>

จากจุดนี้เป็นต้นไปคอนโทรลเลอร์และเทมเพลตสามารถห่อหุ้มด้วยคำสั่งของตัวเองถ้าใครต้องการมัน

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.