Nested directive with no template but ng-repeat in parent directive

561 Views Asked by At

I try to explain my problem:

I have a custom directive that contains a list of elements (in this moment the elements are custom directives, but I don't know if it is correct). For each element, I need to take some values and put the values inside the parent directive, where I have two different ng-repeat. Perhaps someone is thinking that I should use those values inside the nested directive and use ng-transclude in the parent. But I can't, because nested directive should have two different templates. Perhaps it's not clear, so I let you see my code:

Index.html(where I use the directive)

<rh-portfolio>
    <rh-portfolio-image id="portfolio-item-six" url="images/portfolio/thumbnail/img-01.jpg" description="" category="construction"></rh-portfolio-image>
    <rh-portfolio-image id="portfolio-item-seven" url="images/portfolio/thumbnail/img-02.jpg" description="" category="construction"></rh-portfolio-image>
    <rh-portfolio-image id="portfolio-item-eight" url="images/portfolio/thumbnail/img-03.jpg" description="" category="construction"></rh-portfolio-image>
    <rh-portfolio-image id="portfolio-item-nine" url="images/portfolio/thumbnail/img-04.jpg" description="" category="construction"></rh-portfolio-image>
    <rh-portfolio-image id="portfolio-item-ten" url="images/portfolio/thumbnail/img-05.jpg" description="" category="construction"></rh-portfolio-image>
</rh-portfolio>

portofolio.js (where there the parent and nested directives are)

.directive('rhPortfolio', function () {
    return {
        restrict: 'E',
        replace: true,
        templateUrl: '/partial_views/directives/templates/portfolio.html',
        scope: {},
        controller: ['$scope', function ($scope) {
            var images = $scope.images = [];

            $scope.select = function (image) {
                angular.forEach(images, function (image) {
                    image.selected = false;
                });
                image.selected = true;
            };

            this.addImage = function (image) {
                if (image.length === 0) {
                    $scope.select(image);
                }
                images.push(image);
            };
        }]
    };
})
.directive('rhPortfolioImage', function () {
    return {
        restrict: 'E',
        replace: true,
        require: '^^rhPortfolio',
        link: function (scope, element, attrs, portfolioCtrl) {
            portfolioCtrl.addImage(scope);
        }
    };
});

And in the end, the template of the directive

...
<div class="tab-content tg-img-border"><!--portfolio-item-one-->
    <div role="tabpanel" class="tab-pane fade in active" ng-repeat="image in images" id="{{ image.id }}">
        <figure><img src="{{ image.url }}" alt="{{ image.description }}"></figure>
    </div>
</div>
... <!-- Here in the middle, there is a lot of code that must not be replicated -->  
<div role="presentation" ng-repeat="image in images" class="active portfolio-item grid-item {{ image.category }}">
    <div class="product-box">
        <a href="#{{ image.id }}" aria-controls="{{ image.id }}" role="tab" data-toggle="tab">
            <figure><img src="{{ image.url }}" alt="{{ image.description }}"></figure>
            ...
        </a>
    </div>
</div>
...

As you can see, the nested directive would not have a unique template.. so I decided to use two different ng-repeat. In between the two ng-repeat, there is code that should not be repeated, so It means, that in any case must be inside the parent directive.

In anyway, my code does not work... I neither understand why.. perhpas because try to use the attribute of the "image" element that is defined in the controller of the parent, but it is filled from the nested directive.

EDIT Here you can see the problem.. In the bottom of the page, you should see the portfolio, with the images... but something does not work: http://simonerh.altervista.org/_test/

Here you can see the versione without Angularjs (so, what I expect to see): http://simonerh.altervista.org/

EDIT2 Here a Plunker version http://plnkr.co/edit/nf2bVkNujtb69WRfs0I7?p=preview

Can anyone help me? thanx

1

There are 1 best solutions below

0
On

You have three problem.

  1. You do not pass parameters in the directive rh-portfolio-image. Such as id, an URL, etc.
  2. Your directive rh-portfolio-image do not invoke, because directive rh-portfolio has property replace:true.
  3. You do not use transclude:true. More detail about ng-transclude.

I'm change your template portfolio.html. Please check punker. It's not finish solution, but it show you, how create directive.

var renovahaus = angular.module("renovahaus", [])
.directive('rhPortfolio', function () {
        return {
            restrict: 'E',
            replace:true,
            transclude:true,
            template: '<section class="tg-main-section tg-haslayout bg-white">  <pre>images = {{images|json}}</pre><div  ng-transclude></div></section>',
            scope: {},
            controller: ['$scope', function ($scope) {
                var images = $scope.images = [];

                $scope.select = function (image) {
                    angular.forEach(images, function (image) {
                        image.selected = false;
                    });
                    image.selected = true;
                };

                this.addImage = function (image) {
                    if (image.length === 0) {
                        $scope.select(image);
                    }
                    images.push(image);
                };
            }]
        };
    })
    .directive('rhPortfolioImage', function () {
        return {
            restrict: 'E',
            //replace: true,
            require: '^^rhPortfolio',
            scope: {id:"="},
            template:'<span>{{id}}</span>',
            link: function (scope, element, attrs, portfolioCtrl) {
                console.log(1);
                portfolioCtrl.addImage(scope);
            }
        };
    }) .directive('rhPortfolioIm', function () {
        return {
            restrict: 'E',
            scope: {id:"@"},
            require: '^rhPortfolio',
            template:'<span>{{id}}</span>',
            link: function (scope, element, attrs,portfolioCtrl) {
                portfolioCtrl.addImage(scope);
            }
        };
    });
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<!DOCTYPE html>
<html class="no-js" lang="">

<head>
  <meta charset="utf-8" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <title>BootStrap HTML5 CSS3 Theme</title>
  <meta name="description" content="" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <link rel="apple-touch-icon" href="apple-touch-icon.png" />
  <script data-require="[email protected]" data-semver="1.11.3" src="http://code.jquery.com/jquery-1.11.3.min.js"></script>
  <link data-require="[email protected]" data-semver="3.3.5" rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" />
  <link data-require="[email protected]" data-semver="3.3.5" rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootswatch/3.3.5/cosmo/bootstrap.min.css" />
  <link data-require="[email protected]" data-semver="3.3.5" rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css" />
  <script data-require="[email protected]" data-semver="3.3.5" src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
  <script data-require="[email protected]" data-semver="1.4.8" src="https://code.angularjs.org/1.4.8/angular.js"></script>

  <link rel="stylesheet" href="style.css" />
  <script src="app.js"></script>
  <script src="portfolio.js"></script>
</head>

<body class="home" ng-app="renovahaus">
  <rh-portfolio>
    <rh-portfolio-im id="'portfolio-item-six'"></rh-portfolio-im>
    <rh-portfolio-im id="'portfolio-item-seven'"></rh-portfolio-im>
  </rh-portfolio>
</body>

</html>

P.S. In tag <div ng-transclude></div> contain directive rhPortfolioIm.