0

I'm trying to move from jQuery world to Angular.
One of functionalities that I'm trying to port to Angular is printing using AJAX. Idea was to have template defined on client side, do request to server, fill template and print it. I've done it using Handlebars:

function drukuj(orderId, templateName) {
    var data;

    $.ajax({
        //zapis
        contentType: "application/json; charset=utf-8",
        type: "POST",
        url: "AJAX.asmx/Print",
        data: "{orderId: " + orderId + "}",

        success: function(msg) {
            data = JSON.parse(msg.d);

            var template = Handlebars.getTemplate(templateName).done(function(tpl) {
                var html = tpl(data);
                $.print(html);
            }).fail(function(err) {
                alert(err);
            });
        },
        error: function(XMLHttpRequest, textStatus, errorThrown) {
            alert(textStatus);
        }
    });
};

Now I'm trying to convert this to angular directive. This is what I have:

(function() {
    'use strict';

    angular
        .module('my.directives', [])
        .directive('printMe', ['$timeout', '$window', '$compile', '$rootScope', printMe]);


    function printMe($timeout, $window, $compile, $rootScope) {
        return {
            restrict: 'A',

            compile: function() {
                return function postLink(scope, element, attrs) {

                    var title = "Default title";

                    if (attrs.title) {
                        title = attrs.title;
                    }


                    element.on('click', function() {
                        print();
                    });

                    function print() {

                        var scope = $rootScope.$new();
                        angular.extend(scope, {
                            name: "Me",
                            items: [{
                                data: "One"
                            }, {
                                data: "Two"
                            }, {
                                data: "Three"
                            }]
                        });
                        var template = angular.element('<div ng-repeat="item in items">{{item.data}}</div>');
                        var linkFunction = $compile(template);
                        var result = linkFunction(scope);
                        scope.$apply();

                        console.log(result.html());


                        $timeout(function() {
                            var w = window.open('', '', 'width=595,height=842,scrollbars=1');
                            w.document.open();
                            w.document.write('<html><head>');
                            w.document.write('</head><body>');
                            w.document.write('<h1>' + title + '</h1>');
                            w.document.write(result.html());
                            w.document.write('</body></html>');
                            w.document.close();
                        });

                    }

                    // Cleanup on destroy
                    scope.$on('$destroy', function() {
                        element.off('click');
                    });
                };
            }
        };
    }
})();

Idea is to have template as variable (get if from $templateCache or have it hard-coded), data as variable (from $http request) and them compile them both into final html so I'll be able to put it in new window and call print on it.

I've tried solution from this question and this, but I can't get that html.

I've created Plunker to show what I've created for now.

I'm still new to angular so any comments about my directive are welcome.

Community
  • 1
  • 1
Misiu
  • 4,738
  • 21
  • 94
  • 198
  • Angularjs is for single page application. Instead of openning a new Window, you should use a modal. Take a look at this : https://github.com/dwmkerr/angular-modal-service – Walfrat Mar 11 '16 at 12:08
  • @Walfrat thanks for comment, I'll look into this, but first I must solve printing problem. – Misiu Mar 11 '16 at 12:12
  • You can use the answer on this question to print a content that is currently displayed (ina modal or not) in your page : http://stackoverflow.com/questions/12181760/twitter-bootstrap-print-content-of-modal-window – Walfrat Mar 11 '16 at 12:33
  • @Walfrat I've seen similar approach with https://github.com/samwiseduzer/angularPrint, but thanks for pointing me out. My issue is getting final (compiled) HTML from template. This is my main problem. – Misiu Mar 11 '16 at 12:53
  • I think you have the said html, the problem is that you're trying to put it in a new window. And i don't know if angular can handle this. Angular is suppose to handle what is wrapped in the ng-app, a new window is not in the ng-app. This is why i recommend the modal way. – Walfrat Mar 11 '16 at 12:56
  • @Walfrat please see code I have inside `$timeout` it displays new window, adds content to it (html) last thing to do is to call `win.print()` but I must get html from my template to pass it there – Misiu Mar 11 '16 at 13:08
  • i checked your plunkr, result is a array of 1 JQLite object, the object is of type "comment" not an HTMLNode. This is because of inner mechanics in angular. This is why html() methid is not defined. Element of type comment doesn't not have html method.I think that openning a window and inject angular content just can't work. Angular is not made to create html and inject it wherever you want. It's made to manipulate current DOM within the current page. – Walfrat Mar 11 '16 at 13:23
  • @Walfrat please see http://stackoverflow.com/questions/26660495/can-i-get-the-compiled-html-of-an-angular-element – Misiu Mar 11 '16 at 13:26

1 Answers1

0

Well that was dumb of me, in fact it's work really well even in a new window.

Here is the answer : wrap your current template in a div no other changes needed :

var template = angular.element('<div><div ng-repeat="item in items">{{item.data}}</div></div>');

This is because directive parsed by angular may not create htmlnode but comment node. So your result.html() doesn't work. Just wrap all your template in a DIV tag without any directive bind to it and you'll be fine.

Walfrat
  • 5,363
  • 1
  • 16
  • 35