Stack Overflow is a community of 4.7 million programmers, just like you, helping each other.

Join them; it only takes a minute:

Sign up
Join the Stack Overflow community to:
  1. Ask programming questions
  2. Answer and help your peers
  3. Get recognized for your expertise

Inside AngularJs app, I want to inject generated content inside printDiv on certain on event. This printDiv is styled using and should be displayed on print only.

Below is the code snippet:

@media print {    
    body > #printDiv{
        display:block;
    }
    body > #screenContent{
        display:none;
    }        
}
@media screen {
    body > #printDiv {
        display: none;
    }
    body > #printContent{
        display:block;
    }
}

On certain event like (ng-click) like below example it calls function GenerateContent() on controller.

$scope.GenerateContent = function () {
   $("#divOne").text(data.FirstName);
   $("#divTwo").text(data.LastName);
   ...
     $scope.Print();
}

Here, I tried to fetch previously injected content using plain JS and then printed using window.print() like below:

$scope.Print = function () {
    var content = document.getElementById("printContent").innerHTML;            
    document.getElementById('printDiv').innerHTML = content;
    window.print();
}

And, finally on html page div structure is like below:

<html>
   <body>
       <div id="screenContent">
           // html content for screen only
       </div>
       <div id="printDiv"></div>
       <div id="printContent">
          <div id="divOne"></div>
          <div id="divTwo"></div>
       </div>
   </body>
</html>

On first attempt content is generated correctly and printed well. On every other attempt content is not injected, it always prints content generated on first attempt.

Is this correct way of injecting and printing div using AngularJs SPA? How can my example be fixed to work in expected manner?

Update:

I tried with ng-bind instead of using jquery like this

<div id="printContent" ng-controller="myController">
    <div id="divOne" ng-bind="firstName"></div>
    <div id="divTwo" ng-bind="lastName"></div>
</div>

and inside controller

$scope.firstName = data.FirstName;
$scope.lastName = data.LastName;

but this doesnt inject anything into dom.

I tried also with ng-model instead of ng-bind that also doesnt work.

Update 2

myController
(function () {
    "use strict";
    app.controller('myController',
       ....
        $http({
             method: 'POST',
             url: '/SomeService',
             data: ....,
           }).success(function (data) {
              $scope.firstName = data.FirstName;
              $scope.lastName = data.LastName;
          }
       });
    ...
}());

Update 3

<div id="printDiv">
   <div id="printContent" ng-app="myApp" ng-controller="myController">
      <div id="divOne" ng-bind="data.firstName"></div>
      <div id="divTwo" ng-bind="lastName"></div>
   </div>
</div>

myController code

angular.module('myApp', [])
.controller('myController', function ($scope) {
   $scope.firstName: "Bob";
   $scope.lastName: "Smith";
   window.print();
});

I'm calling window.print to print content inside printDiv where elements are binded to controller properties, yet this not working. When I look inside firebug content is not binded at all (html structure looks ok with ng-bing, but there is no actual content binded to that element).

What I'm doing wrong here?

share|improve this question
    
Never modify the DOM directly in Angular. Let Angular do it for you. For example $("#divOne").text(data.FirstName); should just be <div id="divOne" ng-bind="data.FirstName"> in a directive. I suggest you work through some getting-started-with-angular tutorials, it really requires a completely different mindset from what you're used to in jQuery. – Daniel Beck Jul 9 '15 at 17:35
    
What does your controller code look like? – Daniel Beck Jul 9 '15 at 17:56
    
Re your update 3: you've got ng-app="myApp" but angular.module('foo', []) -- switch "foo" to "myApp" (or vice-versa). – Daniel Beck Jul 9 '15 at 21:13
    
ok, do you have idea why I have this behaviour, it doesnt bind anything to div from controller properties? – user1765862 Jul 9 '15 at 21:19
    
Because you've got syntax errors. $scope.firstName: "Bob"; should be $scope.firstName="Bob";, $scope.lastName: "Smith"; should be $scope.lastName ="Smith";, and you should be watching the javascript console to catch trivial errors like that. – Daniel Beck Jul 9 '15 at 21:52

Can't tell from your disconnected bits and pieces where you're going off track (where is GenerateContent located relative to everything else for example?) but here is a very simple example of a controller doing what you're asking for without jQuery:

DOM:

<div ng-app="foo">
     <div id="printContent" ng-controller="demoController">
        <div id="divOne" ng-bind="data.firstName"></div>
        <div id="divTwo" ng-bind="data.lastName"></div>
    </div>
</div>

Controller:

angular.module('foo', [])
    .controller('demoController', function ($scope) {
    $scope.data = {
        firstName: "Bob",
        lastName: "Smith"
    };

})

https://jsfiddle.net/m10ojexn/

share|improve this answer
    
thanks Daniel, but how would you from here, after $scope.data inside controller code inject this printContent div content inside #printDiv? – user1765862 Jul 9 '15 at 19:28
    
The same way -- put the data on $scope and bind to it from the DOM. It's really best to get out of the habit of thinking in terms of rummaging around directly in the DOM copying nodes here and injecting them there; angular really demands that you think in terms of modifying the underlying data and binding to it instead. – Daniel Beck Jul 9 '15 at 19:48
    
(If both printDiv and printContent are always going to contain the same html, then you'd be best off encapsulating this as a directive and embedding that directive twice. If they need to contain the same data in different html structure, then you can bind the same bits of data to multiple DOM nodes and angular will keep track of updating them all as needed.) – Daniel Beck Jul 9 '15 at 19:49
    
I dont know what I'm doing wrong, I bind div with ng-app="myApp" and each div with corresponding property inside controller like in your code example and yet on click event this divs are not populated with wired content. I will update in a min with code example – user1765862 Jul 9 '15 at 20:58

So injecting content using jQuery in an angular app like this isn't going to work as Angular currently has no idea that things have changed and it needs to update the UI. The quick fix for this is using Angular's $timeout which is setTimeout that has been modified to work in conjunction with the Angular digest cycle. Any functions that use jQuery to update the UI should be wrapped in $timeout, like this:

$scope.GenerateContent = function () {
  $timeout(function () {
    $("#divOne").text(data.FirstName);
    $("#divTwo").text(data.LastName);
    ...
    $scope.Print();
  }, 0);
}

This should cause angular to evaluate your DOM updates. PS: Don't forget to inject $timeout into your controller.

share|improve this answer
1  
This is not a good idea. Any functions that use jQuery to update the UI should be rewritten to not use jQuery to update the UI. Seriously, if you're going to do this there's no point in using Angular in the first place. – Daniel Beck Jul 9 '15 at 17:34

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.