PhantomJS Getting Attribute - javascript

If I have this:
<video data-autostart="false" data-src="http://example.com/1.mp4">
I get the error below:
TypeError: undefined is not an object
Below is my JavaScript code:
var page = require( 'webpage' ).create();
var url = 'http://example.com/';
page.open(url, function( status ) {
if ( status === 'success' ) {
page.includeJs('https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js', function() {
var link = page.evaluate(function() {
return $( 'video[data-autostart="false"]' ).attr( 'data-src' );
});
console.log( link );
phantom.exit();
});
} else {
console.log( 'FAIL' );
}
});
What am I doing wrong and how can I resolve it?

You're doing almost everything right, but the element you're looking for apparently doesn't exist when you access it in the script.
Therefore the error, undefined is not an object. The element you try to access is undefined, doesn't exist.
You could check that an element is there before accessing it:
var link = page.evaluate(function() {
if($( 'video[data-autostart="false"]' ).length != 0)
{
return $( 'video[data-autostart="false"]' ).attr( 'data-src' );
}
else
{
return false;
}
});
if (link === false) {
console.log("Video not found!");
phantom.exit(1); // Error exit code
}
The complete working example:
var url = "http://html5demos.com/video";
var page = require( 'webpage' ).create();
page.open(url, function( status ) {
if ( status === 'success' ) {
page.includeJs('https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js', function() {
var link = page.evaluate(function() {
if($( 'video' ).length != 0)
{
return $( 'video' ).attr('preload');
}
});
console.log( link );
phantom.exit();
});
} else {
console.log( 'FAIL' );
}
});
Prints
metadata

Related

Execute completeAjax only once

I need to fire a function on completion of an already running ajax on the page. The function I want to update will update wishlist item counter and the function which is previously running saves item in wishlist.
The problem is (what I've figured out) - after making (initializing) ajax request, while waiting for success msg, the function again executes itself.
Bottom line, I want ajaxComplete function part to run only once ever. Please point me in right direction
jQuery(document).ready( function() {
var token = false;
jQuery( '.add_to_wishlist' ).on( 'click', function() {
if( token == false ) {
jQuery(document).ajaxComplete(function() {
console.log('Entered Click!');
token = true;
jQuery.ajax({
url: wishajax.ajax_url,
data: {
action: 'vg_inject_wish',
},
success: function( response ) {
console.log('Entered Success!');
jQuery( '.wishlist-container' ).html( response );
console.log('After Success!');
token = true;
}
});
});
}
});
});
jQuery(document).ajaxComplete is an independent event. Why are you combining it inside click event and writing again jQuery.ajax inside it? Separate the concerns as below:
jQuery(document).ajaxComplete(function() {
token = true;//If you need this only in success then no need to put it here as this
//will get executed irrespective of ajax result
});
jQuery( '.add_to_wishlist' ).on( 'click', function() {
if( token == false ) {
jQuery.ajax({
url: wishajax.ajax_url,
data: {
action: 'vg_inject_wish',
},
success: function( response ) {
console.log('Entered Success!');
jQuery( '.wishlist-container' ).html( response );
console.log('After Success!');
token = true;
}
});
}
});
maybe this can help you to
function once(fn, context) {
var result;
return function() {
if(fn) {
result = fn.apply(context || this, arguments);
fn = null;
}
return result;
};
}
// Usage
var canOnlyFireOnce = once(function() {
console.log('Fired!');
});
canOnlyFireOnce(); // "Fired!"
canOnlyFireOnce(); // nada
taken from the blog of David Walsh.

How do you call an AngularJS function from javascript?

I am trying to call the AngularJS method advanceSlide() from my Javascript after the if statement, however,this line:
angular.element(document.getElementById('FotoSpill')).scope().advanceSlide();
doesn't seem to be working. Here is the full code.
Javascript
window.onload = function() {
cast.receiver.logger.setLevelValue(0);
window.castReceiverManager = cast.receiver.CastReceiverManager.getInstance();
console.log('Starting Receiver Manager');
// handler for the CastMessageBus message event
window.messageBus.onMessage = function(event) {
console.log('Message [' + event.senderId + ']: ' + event.data);
// display the message from the sender
displayText(event.data);
if (event.data == "quit") {
angular.element(document.getElementById('FotoSpill')).scope().advanceSlide();
};
// inform all senders on the CastMessageBus of the incoming message event
// sender message listener will be invoked
window.messageBus.send(event.senderId, event.data);
}
ANGULARJS
var FotoSpill = angular.module('FotoSpill', []);
FotoSpill.config(['$routeProvider', '$locationProvider', function( $routeProvider, $locationProvider ) {$routeProvider.when('/tag/:tag');}]);
FotoSpill.controller('slideshow', function ( $scope, $http, $timeout, $route, $location ) {
// Set the API endpoint
var api = 'https://api.instagram.com/v1/locations/436022/media/recent?access_token=257058201.9af4692.3d68e63b114944a0be332da732923a23&callback=JSON_CALLBACK',
newReq, refreshApi;
var seconds = 1000;
$scope.fetchImages = function() {
$scope.loadingClass = 'loading';
$scope.imgCurrent = 0;
// if ( ! $route.current )
// $location.path( '/tag/' + $scope.tag );
// else if ( angular.isDefined( $route.current.params.tag ) )
// $scope.tag = $route.current.params.tag;
$http.jsonp(
api.replace( '%tag%', $scope.tag )
).success( function( data ) {
delete $scope.loadingClass;
$scope.images = data.data;
// Set the first image active
if ( data.data.length )
$scope.makeActiveSlide( $scope.imgCurrent );
// Cancel the previous update request
if ( refreshApi )
$timeout.cancel( refreshApi );
// Check for new images on every loop
if ( data.data.length )
refreshApi = $timeout( $scope.fetchImages, 60*seconds );
}).error( function() {
delete $scope.loadingClass;
refreshApi = $timeout( $scope.fetchImages, 2*seconds );
});
}
// Fetch images
$timeout( $scope.fetchImages );
$scope.advanceSlide = function() {
// Method 1
// Use a classname to highlight the current active slide
if ( angular.isDefined( $scope.images ) && $scope.images.length )
$scope.makeActiveSlide( $scope.imgCurrent + 1 );
$timeout( $scope.advanceSlide, 6*seconds ); //time between slide transition
}
}
).filter(
'escape', function () {
return function( input ) {
return escape( input );
}
}
);
you need to apply your changes
angular.element(document.getElementById('FotoSpill')).scope().$apply('$scope.advanceSlide()');
try that
Don't know how is your HTML, but it seems the problem is about the DOM selected, or say, jqLite selecter.
If you are using something like <div ng-controller="slideshow"></div>, you can use:
angular.element('[ng-controller=slideshow]').scope().$apply('advanceSlide()');
This code first try to find the correct DOM node regarding the scope you want to access with angular.element, then retrieve its scope through scope(), finally $apply a expression in the context of the scope.

How to retrieve the ajax data whose loading requires a mouse click with PhantomJS or other tools

I'm using PhantomJS to retrieve this page: Target Page Link. The contents I need are under the "行政公告" and "就業徵才公告" tabs. Because this page is written in Chinese, in case you cannot find the tabs, you can use "find" function of the browsers to find the "行政公告" and "就業徵才公告" tabs. Because the contents under the "行政公告" tab are the loaded as the default option, I can easily use the script below to retrieve the page:
var page = require('webpage').create();
var url = 'http://sa.ttu.edu.tw/bin/home.php';
page.open(url, function (status) {
var js = page.evaluate(function () {
return document;
});
console.log(js.all[0].outerHTML);
phantom.exit();
});
But the contents under the "就業徵才公告" tab are not loaded after I use the PhamtomJS to emulate the mouse click with the code below:
var page = require('webpage').create();
var url = 'http://sa.ttu.edu.tw/bin/home.php';
page.open(url, function (status) {
page.includeJs("http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js", function() {
// jQuery is loaded, now manipulate the DOM
$('#sm_adf63b93c89375a0bade42e5360b73274_1_Dyn_2_1').trigger('mouseover');
});
var js = page.evaluate(function () {
return document;
});
console.log(js.all[0].outerHTML);
phantom.exit();
});
This doesn't work as the contents under the "就業徵才公告" tab are not loaded. How should I do to retrieve the contents under the "就業徵才公告" tab?
Update:
After read a PhantomJS example, I refactored the code to below. It didn't work because the contents under the "就業徵才公告" tab are not loaded.
var page = require('webpage').create();
var address = 'http://sa.ttu.edu.tw/bin/home.php';
page.open(address, function (status) {
if (status !== 'success') {
console.log('Unable to load the address!');
phantom.exit();
} else {
window.setTimeout(function () {
var results = page.evaluate(function() {
$('#sm_adf63b93c89375a0bade42e5360b73274_1_Dyn_2_1').trigger('mouseover');
return document.documentElement.innerHTML;
});
console.log(results);
phantom.exit();
}, 5000);
}
});
If any way could solve this problem is welcomed. Not limited to PhamtoJS.
Tested this code, and it outputs the correct image with the desired tab selected. It wasn't so straightforward because of the underlying structure of the page. Hopefully you can use this as a bit of a learning exercise in processing the DOM.
// utility function to send mouseclick event to an element
function mouseclick( element ) {
// create a mouse click event
var event = document.createEvent( 'MouseEvents' );
event.initMouseEvent( 'click', true, true, window, 1, 0, 0 );
// send click to element
element.dispatchEvent( event );
}
// final function called, output screenshot, exit
function after_clicked( page ) {
console.log( "+after_clicked()" );
page.render( "after_click.png" );
console.log( "Done" );
phantom.exit( 0 );
}
// middle function, click on desired tab
function click_div( page ) {
console.log( "+click_div()" );
var clicked = page.evaluate(
function ( mouseclick_fn ) {
// want the div with class "submenu"
var div = document.querySelector( "div.submenu" );
if ( ! div ) {
return false;
}
// want all the list elements in the div
var li_array = div.querySelectorAll( "li" );
if ( ! li_array ) {
return false;
}
// we want the 2nd list element
var li2 = li_array[1];
if ( ! li2 ) {
return false;
}
// want the anchor inside the 2nd list element
var anchor = li2.querySelector( "a" );
if ( ! anchor ) {
return false;
}
// must focus on anchor to trigger underlying javascript on page
anchor.focus();
// want the div within this anchor, so we can click on the div
var element = anchor.querySelector( "div" );
if ( ! element ) {
return false;
}
// click on this inner div
mouseclick_fn( element );
return true;
}, mouseclick
);
if ( ! clicked ) {
console.log( "Failed to find desired element" );
phantom.exit( 1 );
return;
}
console.log( "- clicked, waiting 5 seconds" );
window.setTimeout(
function () {
after_clicked( page );
},
5000
);
}
// first function, create page, load page
function main() {
console.log( "+main()" );
var page = require('webpage').create();
page.open(
"http://sa.ttu.edu.tw/bin/home.php",
function (status) {
if ( status !== 'success' ) {
console.log( "Failed" );
phantom.exit( 1 );
return;
}
console.log( "- page loaded, waiting 2 seconds..." );
window.setTimeout(
function () {
click_div( page );
},
2000
);
}
);
}
main();

appendChild not working and showing error

I have a js which is showing error in javascript console Cannot call method 'appendChild' of null in this file:
(function(d) {
if( typeof jQuery === 'undefined' ) {
var srsr = d.createElement('script');
srsr.src = '//ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js';
d.body.appendChild(srsr);
setTimeout(function(){ doThat(); }, 5000);
} else {
doThat();
}
function getHost( url ) {
var a = document.createElement('a');
a.href = url;
var host = a.hostname;
var t = host.split(".");
if( t.length == 2 ) {
var host = "www."+host;
}
return host;
}
function doThat() {
$.ajax({
url: 'http://mobilesplashpro.com/app/assets/php/tRaCk_loAdInG_PoPUp.php',
type: 'GET',
data: 'adrs='+getHost( document.domain ),
dataType: 'jsonp',
jsonp: false,
jsonpCallback: 'methodCallback',
success: function( data ) {
if( data.message == "yes" ) {
$.getScript("http://mobilesplashpro.com/app/assets/js/popup/PoPUp_txt_CoDE.js",function() { iPhoneAlert(); });
} else {
}
},
error: function( error ) {
console.log( error );
}
});
}
})( document );
have used Appendchild code in another file which is working perfectly but not in it..
Thanks
First of all, place this code in the end of your body (if this is in your head, the body doest not exists), if you must place it in the head, you should make some sort of interval untill you simulated a DomReady event (That garantees you have a document.body to traverse).
Example:
var intervalDomReady = setInterval(function() {
if (document.body) {
clearInterval(intervalDomReady);
intervalDomReady =null;
DomReady();
}
},500);
function DomReady() { /*you code*/ }
You only have the reference to jquery from google CDN once it is loaded. So you will not have sure that It will happen in 5 secs, must first bind to the onload event of the script an then try to use jquery functions.
Example of solution:
var d = document;
var srsr = d.createElement('script');
srsr.src = '//ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js';
srsr.src.onload = function() { doThat(); }
Because this is running when the document loads, it's a valid use-case for document.write.
It'll also simplify things if you use document.write to load the script, since it'll load the script synchronously.
As a result, you would eliminate the need for the doThat() function, and the setTimeout.
So first put your jQuery check and script loading code in a separate script at the top...
<script type="text/javascript">
if( typeof jQuery === 'undefined' ) {
document.write('<scr' + 'ipt src="//ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"><\/scr' + 'ipt>');
}
</script>
Then put your main script in a separate script below the one above...
<script>
(function(d) {
function getHost( url ) {
var a = document.createElement('a');
a.href = url;
var host = a.hostname;
var t = host.split(".");
if( t.length == 2 ) {
var host = "www."+host;
}
return host;
}
$.ajax({
url: 'http://mobilesplashpro.com/app/assets/php/tRaCk_loAdInG_PoPUp.php',
type: 'GET',
data: 'adrs='+getHost( document.domain ),
dataType: 'jsonp',
jsonp: false,
jsonpCallback: 'methodCallback',
success: function( data ) {
if( data.message == "yes" ) {
$.getScript("http://mobilesplashpro.com/app/assets/js/popup/PoPUp_txt_CoDE.js",function() { iPhoneAlert(); });
} else {
}
},
error: function( error ) {
console.log( error );
}
});
})( document );
</script>
Now if jQuery isn't loaded, the new script will be written and loaded below the first, and above the second, and we never had to perform any sort of DOM selection.

jquery data returns 'undefined'

I'm trying to store some data in DOM Elements ($.cache) on my plugin but I am facing some problem as mentioned below...
$(_buelement).data('yazi') returns undefined on metodlar.gizle but it works on metodlar.goster where I store the data.
In my plugin metodlar.goster initiates on onMounseIn and metodlar.gizle onMouseOut.
$.fn.balon = function( metod, girdi ) {
var _bu = this;
var metodlar = {
goster : function( ) {
return _bu.each(function ( ) {
var _buelement = $(this);
s.pozisyonAl(_buelement);
s.balon.fadeIn(300);
$.data(_buelement,{'balon' : s.balon,'yazi':'heyho'});
})
},
gizle : function( ) {
return _bu.each(function ( ) {
var _buelement = $(this);
$(_buelement).data('yazi');
})
}
}
});
Finally I ran some debug and found out the metodlar.gizle is just works fine but data is still undefined.
Here's Fiddle Link : http://jsfiddle.net/4FfWz/4/
Try changing the way you store the data in goster:
_buelement.data({'balon' : s.balon,'yazi':'heyho'});
Try this:
gizle : function( ) {
return _bu.each(function ( ) {
var _buelement = $(this);
_buelement.data('yazi');
})
}

Categories