4

I just can't get it working. Simplified everything and placed it in fiddle: http://jsfiddle.net/svdoever/94aQH/1/.

I want to render a hierarchical chapter of a book which containg paragraphs, and paragraphs can contain sub-paragraphs.

Code:

angular.module("myApp", []).controller("TreeController", ['$scope', function($scope) {
$scope.vm = {};
$scope.vm.chapter = {
        "Id": "N7313",
        "Title": "1 Chapter1",
        "Content": "<p>Contents1</p>",
        "Paragraphs": [
            {
                "Id": "N1.1",
                "Title": "1.1 Paragraph1.1",
                "Content": "<p>Content2</p>",
                "Paragraphs": [
                    {
                        "Id": "N1.1.1",
                        "Title": "1.1.1 Paragraph1.1.1",
                        "Content": "<p>ContentA</p>",
                        "Paragraphs": []
                    },
                    {
                        "Id": "N1.1.2",
                        "Title": "1.1.2 Paragraph1.1.2",
                        "Content": "<p>ContentB.</p>",
                        "Paragraphs": []
                    }
                ]
            },
            {
                "Id": "N1.2",
                "Title": "1.2 Paragraph1.2",
                "Content": "<p>Content3.</p>",
                "Paragraphs": []
            }
        ]
    };
}]);

And html:

<div ng-app="Application" ng-controller="TreeController">
  <script id="paragraphTmpl.html" type="text/ng-template">
    <a class="anchor" ng-attr-id="data.Id"></a>
    <h4 ng-bind="data.Title" />
    <div class="paragraph-text" ng-bind-html="data.Content"></div>
    <!-- Want to loose the div in the repeat as well -->
    <div ng-repeat="paragraph in data.Paragraphs" ng-include="paragraphTmpl.html"></div>
  </script>

  <div class="bookchapter">
    <a class="anchor" ng-attr-id="vm.chapter.Id"></a>
    <h3 ng-bind="vm.chapter.Title" />
    <div class="chapter-text" ng-bind-html="vm.chapter.Content"/>
    <div ng-repeat="paragraph in vm.chapter.Paragraphs" ng-include="paragraphTmpl.html"/>
  </div>
</div>

I also don't want a div rendered in the repeat as specified in the comment. I know how to do this with knockout, but couldn't find it for AngularJS.

Help would be appreciated.

Serge van den Oever
  • 4,340
  • 8
  • 45
  • 66

2 Answers2

2

If you use child scopes to manage the recursion with arbitrarily large size I think you'll need to use the element. How else can you have data refer to different objects, if they all share the same parent element?

Therefore I think you have two options: create a custom directive that has a compile function (which I'm not super familiar with) or hard-code the paragraphs to have a maximum depth of recursion (using ngIf like in my plnkr to remove the unused <div>'s). Here's a good question to get you started. (and of course reading Angular's documentation on directives will be helpful, if you haven't already).

I fixed your code to do everything but remove the extra div's.

http://plnkr.co/edit/ONnvYj91HRSvboWUxDg2

<div ng-app="Application" ng-controller="TreeController">
  <script id="paragraphTmpl.html" type="text/ng-template">
    <a class="anchor" ng-attr-id="data.Id"></a>
    <h4 ng-bind="data.Title"></h4>
    <div class="paragraph-text" ng-bind-html="data.Content"></div>
    <!-- Want to loose the div in the repeat as well -->
    <ng-include
      ng-if="data.Paragraphs.length > 0" 
      onload="data = paragraph" 
      ng-repeat="paragraph in data.Paragraphs" 
      src="'paragraphTmpl.html'"></div>
  </script>

  <div class="bookchapter">
    <a class="anchor" ng-attr-id="vm.chapter.Id"></a>
    <h3 ng-bind="vm.chapter.Title"></h3>
    <div class="chapter-text" ng-bind-html="vm.chapter.Content"></div>
    <ng-include  
      ng-repeat="paragraph in vm.chapter.Paragraphs" 
      ng-if="vm.chapter.Paragraphs.length > 0"
      src="'paragraphTmpl.html'" 
      onload="data = paragraph"/>
  </div>
</div>
Community
  • 1
  • 1
Jesus is Lord
  • 14,971
  • 11
  • 66
  • 97
  • Great, you got it working! It is a pity I have to introduce that extra div... In knockout I solved it using: – Serge van den Oever Jan 13 '14 at 10:46
  • I overlooked it, the div's I wanted removed are gone as well... You will get the accept, but one question: why do you do the extra test for length of Paragraphs? The ng-repeat already works if the array is empty. Any ( performace?) reason for that? – Serge van den Oever Jan 13 '14 at 11:34
  • Thanks! Are you referring to the `ngIf` inside of the `
    ` or the `
    – Jesus is Lord Jan 13 '14 at 12:40
  • Hmm well maybe it's not necessary anymore. If I recall it made it freeze without it. Oh that was probably when I had the thing as a directive that had a custom compile function. Yeah so it's not necessary anymore. Good catch. – Jesus is Lord Jan 13 '14 at 13:18
1

This fiddle just about achieves what you want http://jsfiddle.net/uBMKr/1/

The key is that you were missing '' around your template src name in ng-include. This is because without the quotes, it is looking for a reference to a scope variable.

<ng-include src="mysrc"></ng-include> - looking for $scope.mysrc

<ng-include src="'mysrc'"></ng-include> - looking for a template named 'mysrc'

The only thing it doesn't do is remove the ng-repeat <div>, which I don't think you are able to do (easily at least).

Matt Way
  • 32,319
  • 10
  • 79
  • 85
  • Hi MWay, thanks for the hint on using the single quotes within the double quotes, I missed that. Your fiddle does not iterate into the hierarchy however. Tried to get that working, but could not get it working. – Serge van den Oever Jan 13 '14 at 10:24
  • Sorry about that, I updated the link to fix my typo :) – Matt Way Jan 13 '14 at 10:27