i need help creating a pdf file off a html page powered by an angularjs controller. the pdf will be created by using phantom module. im able to display and bind data correctly as soon as i navigate to the specific url, but when i call phantom to render the page it doesnt load/initiliaze/call the controller methods i have tried different methods such as doing ng-init from the div or calling a function from the controller once is done loading or even using
$scope.$on('$viewContentLoaded', function(){
//code here...
})
phantom code:
function DoThePDF(){
phantom.create(function(ph){
ph.createPage(function(page) {
page.set("paperSize", { format: "A4", orientation: 'portrait', margin: '1cm' });
page.open(address, function(status) {
if(status !== 'success'){
console.log('unable to open webpage');
}
else{
setTimeout(function() {
page.render("reports.pdf");
console.log("page rendered");
ph.exit();
}, 5000);
}
})
})
});
}
when calling page.open(address, function(status) {...} i can see that the page is been opened but the angular events/methods dont get initialized/called so when the page gets rendered is an empty html template no data gets binded. i have added delays but still it doesnt help.
PhantomJS 1.9.x doesn't support websocket, therefor i have to use PhantomJS 2. there is not an official release yet since is being developed but there a beta version
Here build as specified. Good luck
Related
I'm coding a script in nodejs to automatically retrieve data from an online directory.
Knowing that I had never done this, I chose javascript because it is a language I use every day.
I therefore from the few tips I could find on google use request with cheerios to easily access components of dom of the page.
I found and retrieved all the necessary information, the only missing step is to recover the link to the next page except that the one is generated 4 seconds after loading of page and link contains a hash so that this step Is unavoidable.
What I would like to do is to recover dom of page 4-5 seconds after its loading to be able to recover the link
I looked on the internet, and much advice to use PhantomJS for this manipulation, but I can not get it to work after many attempts with node.
This is my code :
#!/usr/bin/env node
require('babel-register');
import request from 'request'
import cheerio from 'cheerio'
import phantom from 'node-phantom'
phantom.create(function(err,ph) {
return ph.createPage(function(err,page) {
return page.open(url, function(err,status) {
console.log("opened site? ", status);
page.includeJs('http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js', function(err) {
//jQuery Loaded.
//Wait for a bit for AJAX content to load on the page. Here, we are waiting 5 seconds.
setTimeout(function() {
return page.evaluate(function() {
var tt = cheerio.load($this.html())
console.log(tt)
}, function(err,result) {
console.log(result);
ph.exit();
});
}, 5000);
});
});
});
});
but i get this error :
return ph.createPage(function (page) {
^
TypeError: ph.createPage is not a function
Is what I am about to do is the best way to do what I want to do? If not what is the simplest way? If so, where does my error come from?
If You dont have to use phantomjs You can use nightmare to do it.
It is pretty neat library to solve problems like yours, it uses electron as web browser and You can run it with or without showing window (You can also open developer tools like in Google Chrome)
It has only one flaw if You want to run it on server without graphical interface that You must install at least framebuffer.
Nightmare has method like wait(cssSelector) that will wait until some element appears on website.
Your code would be something like:
const Nightmare = require('nightmare');
const nightmare = Nightmare({
show: true, // will show browser window
openDevTools: true // will open dev tools in browser window
});
const url = 'http://hakier.pl';
const selector = '#someElementSelectorWitchWillAppearAfterSomeDelay';
nightmare
.goto(url)
.wait(selector)
.evaluate(selector => {
return {
nextPage: document.querySelector(selector).getAttribute('href')
};
}, selector)
.then(extracted => {
console.log(extracted.nextPage); //Your extracted data from evaluate
});
//this variable will be injected into evaluate callback
//it is required to inject required variables like this,
// because You have different - browser scope inside this
// callback and You will not has access to node.js variables not injected
Happy hacking!
I have a website running on Azure. In there, I'm playing with Knockout.JS components and custom loaders. I've used a very simple example from KO documentation found here:
(A component loader that loads external files using custom code)
http://knockoutjs.com/documentation/component-loaders.html#custom-component-loader
// loader helper
var templateFromUrlLoader = {
loadTemplate: function(name, templateConfig, callback) {
if (templateConfig.url) {
var today = new Date();
var fullUrl = templateConfig.url + "?v=" + today.getTime();
$.get(fullUrl, function(markupString) {
ko.components.defaultLoader.loadTemplate(name, markupString, callback);
});
} else {
callback(null);
}
}
};
// component is registered
ko.components.register('postcode-lookup', {
viewModel: function() {
// component js
},
template: {
url: 'https://www.purplebricks.com/content/lib/component-postcode-lookup/dist/component/templates/postcode-lookup.html'
}
});
ko.components.loaders.unshift(templateFromUrlLoader);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.0/knockout-min.js"></script>
Now, locally, everything works perfectly, each time a page gets refreshed, the component template is fetched:
and the preview of the response is here:
The problem arises when the page is deployed to staging/live production. It will work for every person just fine the first time, but as soon as you refresh the page, the probability of template returning blank response is very very high = almost 90%. It is clearly cached, the response code becomes 304 not modified, but the response is blank. I've tried adding a query string that adds a timestamp to it - it made almost 0 difference. Now I have a 200 status code, but the time of the request goes into pending and seems to last forever:
It almost feels like Azure is caching this incorrectly, perhaps DNS issues?
This appears to be down to an incorrectly set gzip header, try adding the following to your route config to prevent ASP.NET MVC from processing the static content:
routes.IgnoreRoute("Content/{*pathInfo}");
Just a little problem: I'm making a Hybrid app developed in angular with Cordova but when I use a setInterval() function after a $window.open() the setInterval stops working, but in Chrome, it's working (but it's normal, the new window is opened in a new tab).
This is the an extract of my code :
$http.post(url)
.success(function(result, status) {
var windowWithings = $window.open(result.res);
var intervalVerif = $window.setInterval(function (){
$http.get(url)
.success(function(result) {
windowWithings.close();
$window.cancelInterval(intervalVerif);
})
.error(function(error) {
console.log(error);
});
}, 2000);
})
.error(function(error, status) {
console.log(status);
});
Thanks in advance!
EDIT:
What I searching to do with the setInterval is to check each 2000 ms if the server got the information from the new window I have opened. If it's ok for the server I close the window to come back to the previous.
When I say it's not working I want to say that the new window doesn't close but if I change the code with an alert I can see sometimes an alert before the new window had the time to open but nothing after
For Chrome, I just say that if I open the Angular app in Chrome on my laptop it's working, but if I launch my Android app created with Cordova it doesn't work.
please use $timeout and add '$timeout' in injection parameters
$timeout(function (){
$http.get(url)
.success(function(result) {
windowWithings.close();
$window.cancelInterval(intervalVerif);
})
.error(function(error) {
console.log(error);
});, 2000);
I am trying to move from events-push:1.0.M7 (latest released official version) to events-push:1.0.0.BUILD-SNAPSHOT. To obtain the latter version I cloned the https://github.com/smaldini/grails-events-push repo and built the plugin locally. The supposed advantage of the later version of the Grails plugin is that it uses newer versions of Atmosphere JavaScript and Java libraries.
In the README file the plugin refers to the GrailsTodos application at https://github.com/smaldini/grailsTodos. However the configuration and the code in the Todos application has nothing in common with the events-push usage information provided in its README file.
Instead, I am trying to use another sample written to demonstrate events-push plugin: https://www.dropbox.com/s/378bqmbu3ad4fnt/GrailsEventsPush.zip. This is an application running in Grails 2.3.7 and using events-push:1.0.M7. It works correctly out of the box with the released version (M7) of the events-push plugin.
Here are the steps I made to make it compile and run with events-push:1.0.0.BUILD-SNAPSHOT (which I installed locally using 'grails maven-install'):
In BuildConfig.groovy
grails.servlet.version = "3.0"
grails.tomcat.nio = true
...
dependencies {
compile 'org.grails.plugins:events:1.0.0.BUILD-SNAPSHOT'
}
plugins {
...
//compile ":events-push:1.0.M7"
compile ":events-push:1.0.0.BUILD-SNAPSHOT"
}
In MyEvents.groovy
events = {
'bagsUpdated' namespace: 'browser', browser:true // allows browser push on this topic
}
In the EventTestingController:
def updateBags() {
Thread.sleep(3000)
event([namespace: 'browser', topic: 'bagsUpdated']) // will trigger registered browsers on 'bagsUpdated' topic
render "OK"
}
I did not change index.gsp:
<script type="text/javascript">
try {
var grailsEvents = new grails.Events("${createLink(uri:'')}", {transport: "sse"});
grailsEvents.on('bagsUpdated', function (data) {
window.console && console.log("GOT bags!");
$("#waiting").html("Event fired!");
});
} catch (error) {
console.log("ERROR: " + error.toString());
}
$(function () {
// Call controller method that emits event when its done
$.ajax({
url: "${createLink(action:'updateBags')}",
success: function () {
console.log("Event should have been already fired...");
},
error: function () {
console.log("Ops something went wrong... ");
}
});
});
</script>
The code that worked correctly with 1.0.M7 version of the plugin does not work with 1.0.0.BUILD-SNAPSHOT version. Here is what I see in the Chrome console:
defer connecting topic: eventsbus grailsEvents.js:108
defer connecting topic: bagsUpdated grailsEvents.js:108
XHR finished loading: POST "http://localhost:8080/GrailsEventsPush/g-eventsbus/eventsbus?X-Atmosphere-t…sport=polling&X-Cache-Date=0&Content-Type=application/json&_=1416503898595". jquery.atmosphere.js:1691
XHR finished loading: POST "http://localhost:8080/GrailsEventsPush/g-eventsbus/eventsbus?X-Atmosphere-t…sport=polling&X-Cache-Date=0&Content-Type=application/json&_=1416503898598". jquery.atmosphere.js:1691
XHR finished loading: GET "http://localhost:8080/GrailsEventsPush/eventTesting/updateBags". jquery-1.11.0.min.js:4
Event should have been already fired... index:32
There are no errors - the browser simply does not get the event fired by the controller, which would produce "GOT bags!" and "Event fired!" statements in the Console.
The application I am trying to upgrade exhibits the same behavior - the server side events do not reach the browser. What am I missing?
When I call filepicker.pickAndStore() for the first time in a template everything works fine. Also closing the modal and clicking the button again works fine (modal is displayed again). When I click on a link inside my meteor app to get to another page (of course via html5 pushstate like on every meteor page, no standard a links with a real page refresh) and then go back to the page with the filepicker stuff in it, the button does not do anything anymore. The filepicker modal or anything is NOT displayed. And i also tried call back function as given in the documentation. I'am describing my code below
Template.content.events({
'click #top_add_file': function (evt) {
evt.preventDefault();
console.log("upload file button is clicked")
Session.set("widgetSet", false);
if (!Session.get("widgetSet")) {
var cb = function () {
filepicker.pickAndStore(
{
mimetypes: ['application/pdf', 'application/msword', 'application/mspowerpoint', 'text/plain'],
container: 'window',
services: ['COMPUTER'],
folders: true
},
{
location: 'S3'
},
function (InkBlob) {
console.log("InkBlob="+InkBlob)
InkBlob.forEach(function (ib) {
Meteor.call("createContent", ib, Meteor.content_file, function (error, result) {
if (error) {
FlashMessages.sendError("Error in saving file")
} else {
FlashMessages.sendSuccess("Successfully Saved File")
}
})
})
},
function (FPError) {
FlashMessages.sendError("Error in uploading file. Please try again")
}
)
};
loadPicker(Meteor.fpkey, cb);
}
},
The answers to this StackOverflow question may help:
Integrating Filepicker.IO with Meteor
One of them highlights an atmosphere package for filepicker:
https://github.com/guido4000/loadpicker
Also, this example shows integrating a 3rd-party modal component into meteor:
https://github.com/alanning/meteor-modal-example