0

I would like to make an universal directive in which the user can easily insert any HTML for the header and footer.

This is my HTML code:

<datagrid 
    id="testing" 
    url="google.com/test">
    <header>
        <p>header</p>
    </header>
    <footer>
        <p>footer</p>
    </footer>
</datagrid>

And I would like to get the inner HTML and parse it on my own.

directive('datagrid', function () {
    return {
        restrict: 'E',
        templateUrl: 'datagrid.htm',
        scope: true,
        transclude: true,
        link: function ($scope, $el, $attr) {

            // get inner HTML, separate header and footer HTML to the variables
            // and add that HTML later in the template

        } 
    };
});

My template:

<script type='text/ng-template' id='datagrid.htm'>
  <table class="datagrid table table-hover table-condensed table-striped">
        <thead>
            <tr class="top-actions-container">
                <!-- INJECT HEADER HTML -->
                <th></th>
            </tr>
        </thead>
        <tbody>
            <tr>
                <!-- RESULTS -->
                <td></td>
            </tr>
        </tbody>
        <tfoot>
            <tr>
                <!-- INJECT FOOTER HTML -->
                <td></td>
            </tr>
        </tfoot>
    </table>
</script>

I'm new to the Angular so I'm open to other suggestions. If that's possible is this a good way to do it?

6
  • 2
    you could use: template: function (tElement) { return 'template-string'; }, with tElement giving you access to the unparsed html, and work from there. Commented Jul 20, 2014 at 16:09
  • interesting, thank you.. I'm still hoping that there is a better way. I will leave this solution as a backup. Commented Jul 20, 2014 at 16:12
  • why aren't you just data binding and using <p>{{header}}</p> and let angular do the compiling? Commented Jul 20, 2014 at 17:34
  • I'm not exactly sure what do you have on your mind. I want to be able to put a custom HTML code for the header and footer in the initial HTML of directive and then inject it to the template. Commented Jul 21, 2014 at 8:33
  • Could you include a result html that you are expected? Commented Jul 21, 2014 at 8:44

2 Answers 2

1

You can try this:

Usages (in main html)

<datagrid 
    id="testing" 
    url="google.com/test">
    <!--In HEADER I used <table> tag because for some reasons (?) <tr>, <td> tags do not work without <table> tag.-->
    <header>
        <table><tr><td>One</td><td>Two</td><td>Three</td></tr></table>
    </header>
    <footer>
        <p>footer</p>
    </footer>
</datagrid>

Directive JS

app.directive('datagrid', function(){
    return {
        restrict: 'EA',
        scope: true,
        transclude: true,
        templateUrl: '../../datagrid.html',
        link: function(scope, element, attr){
            var header = element.find('header').html();
            element.find('header').remove();
            element.find('thead').html(header);
        }
    };
});

You can write same code for footer.

datagrid.html

<table class="datagrid table table-hover table-condensed table-striped">
    <!-- Keep thead tag empty -->
    <thead></thead>
    <tbody>
        <tr>
            <!-- RESULTS -->
            <td></td>
        </tr>
    </tbody>
    <tfoot></tfoot>
</table>
<div ng-transclude></div>
<!-- ng-transclude will include all custom html defined under <datagrid> directive -->

I hope this will help you.

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you for the response but in the link method, the "element" argument contain the template element, not the "datagrid" element. So far I have managed to get the elements in the controller method ($transclude arg) but I'm still having some problems selecting the elements (footer and header). Looks like jquery find method doesn't work on that obj. If I will manage to solve this I will post it in here. Probably it's something basic...
Brother, "element" will get both element and dynamic html inside "datagram". The tag <div ng-transclude></div> in template (datagrid.html) will copy that dynamic html of datagrid on the fly and make it available with "element". I test the code before posting here. If you still find it difficult then I can send you the working codes again with fiddle.
0

I just had to use an arg $transclude in the controller of the directive.

// declaration of DataTable directive
.directive('datagrid', function () {
    return {
        restrict: 'E',
        templateUrl: 'datagrid.htm',
        scope: true,
        transclude: true,
        link: function ($scope, $el, $attr) {
            var dtData = {
                id: $attr.id,
                url: $attr.url
            };

            if ($scope['datagrid'] === undefined) $scope['datagrid'] = [];
            $scope['datagrid'].push([$attr.id, dtData]);
        },
        controller: function ($scope, $transclude) {
            $transclude(function (clone, scope) {
                console.log($(clone).find('header')); // don't work
                $.each(clone, function (i, e) {
                    if ($(e).is('header')) console.log(e); //works
                });
            });

        }
    };
});

From this I believe that I can accomplish my goal. Only questions that are still there are if this is a good way to do this, will that confuse other users of my plugin and why the hell can't I select the "header" element with the jQuery find method? :)

Thank you all for the help. Hope I will soon finish the rest of the goal so I can post it here. There shouldn't be any more problems to accomplish it.

4 Comments

The jQuery .find() will search through descendents of the element, not including the element itself, that why it doesn't work.
FYI, your solution is pretty similar to what angular-bootstrap's tabs have done. See tabs.js
Thanks for the link, I will try to analyze it deeper. Maybe I will find some other tricks. Regarding ".Find()", "clone" should be a root element and it should contain the "header" and "footer" element. Maybe I'm wrong so I will try to research this further. Ty
If you expect the clone to be the root element, you can use transclude: 'element' instead of trasclude: true. By default, only the element contents are trascluded.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.