0

At the moment I use php to collect data needs to be printed in one pdf and open pdf in new browser tab. The problem is that it generate to much traffic as soon as I've a lot of users and a lot of docs to be printed in a same time. So I'm looking for a way to collect everything in one html, open it in new tab, fill with data from back-end and print it after. My issue is to initialize VueJS for the new browser tab. I always have the following warning in console: vue.js:1141 [Vue warn]: Cannot find element: #app

I guess the reason is that VueJS works with SPA. Is there any way to implement my idea?

Here is template for a new tab needs to be opened in a new tab.

<div id="app">
 <printing-form v-for="printedForm in printedForms" track-by="id" :printed-form="printedForm"></printing-form>
</div>

<template id="printingForm-template">
  Some HTML need to be printed in new tab.
</template>

Below my JS code to init VueJS

  var printButton = $('#print-button');
  printButton.on('click', function(e) {
    e.preventDefault();
    printButton.unbind('click');
    printButton.css('color', '#008000');
    var idNumbers = TopPanel.getArrayOfId();
    if (idNumbers == '') {
      idNumbers = TopPanel.getIdNumber();
    }
    var url = window.location.href + '/form';

    $.ajax({
     url: url,
     data: 'id=[' + idNumbers + ']',
     success: function(data) {
       var newWindow = window.open(url); //Open URL in new tab
       var printedIds = $.parseJSON('[' + idNumbers + ']');
       printedIds.forEach(function(item, i, arr) {
         var printedField = $('#top-row-'+item).find('.table-field-printed');
         if (!printedField.hasClass('true-value')) {
             printedField.addClass('fa');
             printedField.addClass('fa-check');
             printedField.addClass('true-value');
         }
       });
       printButton.css('color', '#4f5762');
       printButtonInit();
       newWindow.onload = function() {
        VuePrinting.vueInit(newWindow); //Here I initialize VueJS module
       }
     },
     error: function(xhr, textStatus, errorThrown) {
      alert($.parseJSON(xhr.responseText));
      printButton.css('color', '#4f5762');
      printButtonInit();
     },
   });
 });
 }

This separate module for VueJs

  var VuePrinting = (function() {
  return {
   vueInit: function() {
    Vue.component('printingForm', {
     temlate: newWindow.document.getElementById('printingForm-template')
    });

    var vm = new Vue({
     el: newWindow.document.getElementById('app'),
     data: {
       printedForms: [
         { obj1 },
         { obj3 },
         { obj3 }
        ]
      }
     });
    }
  }
 })();

UPDATE: I've corrected my code after RoyJ comment, so now it works correct. Only one note... template should also be changed from selector to:

newWindow.document.getElementById('printingForm-template')
Evgeny Ladyzhenskiy
  • 151
  • 1
  • 3
  • 15
  • I read somewhere, but have not verified it myself, that you can't mount on the body tag. Try putting a div inside the body and mount that instead. –  Oct 06 '16 at 16:57
  • Search for "body" here: http://vuejs.org/api/ –  Oct 06 '16 at 17:28

1 Answers1

0

When you specify a selector for your el, Vue will look in the current document for it. The new tab will not be part of the current document.

Save a reference when you open the tab. Write the HTML into its document. Query the #app out of the document, and use the actual element instead of a selector in your Vue setup:

var vm = new Vue({
  el: newWindow.document.getElementById('app')
});
Community
  • 1
  • 1
Roy J
  • 42,522
  • 10
  • 78
  • 102
  • I corrected the code above according your recommendation but now I have: vue.js:1141 [Vue warn]: Invalid template option: #printingForm-template – Evgeny Ladyzhenskiy Oct 09 '16 at 12:56