Search code examples
javascripthtmlangularjsmarkupangularjs-ng-repeat

Rendering conditional markup with ng-repeat


Given this data in my controller :

$scope.data = [
    {id: "1", ElementType: "paragraph", text: "some content"},
    {id: "2", ElementType: "listItem", text: "some list item content"},
    {id: "3", ElementType: "quote", text: "some quote"}
]

An given this ng-repeat in my view:

<div ng-repeat="item in data">{{item.text}}</div>

How can I render this HTML ? :

<p>Some content</p>
<ul>
    <li>some list item content</li>
</ul>
<blockquote>some quote</blockquote>

I've explored ng-switch but it keeps the parent div. In other words I want to replace the HTML produced by ng-repeat with new markup based on an object attribute.


Solution

  • You can do it inside a directive using the $compile angular function like shown in this plnkr.

    UPDATE Here is a plnkr that works better

    Here is the key part:

    link: function (scope, ele, attrs) {
      scope.$watch(attrs.dynamic, function(html) {
    
        var htmlStr = '';
        var repeat = attrs.repeat;
        for(var i = 0; i< repeat; i++){
          htmlStr += html;
        }
    
        ele.html(htmlStr);
        $compile(ele.contents())(scope);
      });
    }
    

    Your controller would look like this:

    function MyController($scope) {
    
    $scope.html = '<p>{{id}}</p>\
                  <ul>\
                   <li>{{ElementType}}</li>\
                  </ul>\
                 <blockquote>{{text}}</blockquote>';
    }
    

    From your example, you'd remove the ng-repeat entirely and just use this directive. One change is that you'd pass in the whole $scope.data and dynamically pull out the bits you wanted to use in your html string. But because it's a string, that should be easy to do with simple string concatenation.

    One final thing - you are probably going to have to put some tags in so you can replace your static content with dynamic data from your array. Kind of like ng-repeat! (but different all the same).

    Finally, you could use interpolate to fill up your html string:

    $interpolate(template)({
      id: id,
      ElementType: ElementType,
      text: text
    });
    

    Where you would get the data for these items from the controller