I wrote an anonymous javascript function that dynamically loads jQuery and Angular. However, my angular code is not running for some reason. The code works find until i hit my main function. I then try to make an http request and print the results in my angular controller, but theyre not printing for some reason.. Can someone help? Here are my fiddle and code:
https://jsfiddle.net/5f44yb7k/1/
Thanks in advance!
(function() {
var jQuery;
var jquery_tag = document.createElement('script');
var angular_tag = document.createElement('script');
function getJqueryTag() {
console.log('getting jquery tag');
jquery_tag.setAttribute("type","text/javascript");
jquery_tag.setAttribute("src", "https://ajax.googleapis.com/ajax/libs/jquery/1.12.2/jquery.min.js");
jquery_tag.onload = scriptLoadHandler;
(document.getElementsByTagName("head")[0] || document.documentElement).appendChild(jquery_tag);
if(jquery_tag.onload) { //ensure angular loads after jQuery
getAngularTag();
}
}
function getAngularTag() {
console.log('now getting angular tag...');
angular_tag.setAttribute("type","text/javascript");
angular_tag.setAttribute("src", "https://ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.min.js");
angular_tag.onload = scriptLoadHandler;
(document.getElementsByTagName("head")[0] || document.documentElement).appendChild(angular_tag);
}
getJqueryTag();
function scriptLoadHandler() {
if(window.jQuery) {
jQuery = window.jQuery
main();
}
}
function main() {
jQuery(document).ready(function($) {
console.log('now in main function'); //this prints fine
var test = angular.module('test', []);
function main_controller($scope, $http) {
$http.get('https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20weather.forecast%20where%20woeid%20in%20(select%20woeid%20from%20geo.places(1)%20where%20text%3D%22fairfax%2C%20va%22)&format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys')
.success(function(data) {
console.log('---data returned---'); //not printing
console.log(data); //not printing
})
.error(function(data) {
console.log('error: ' + data);
});
}
});
}
})();
Angular is falling out of scope. You'll need to call the bootstrap function to get angular up and running if you're loading it in this fashion.
I've never loaded it this way, but see: https://docs.angularjs.org/guide/bootstrap, specifically the section on Manual Initialization.
Related
I have a local JS file that needs to be called using a script object. However, I am not able to get the functions to run. Here's the code snippet.
<script type="text/javascript">
var x = document.createElement("SCRIPT");
x.type = "text/javascript";
x.src = "file:///C:/scripts/localscript.js";
//one of the functions is loadData();
loadData(); //I'm getting reference error, loadData is not defined.
</script>
Thank you,
You need to create a script element and insert it in DOM (mostly under head) to load the script. When that script is loaded by the browser, whatever you return from that script will be available.
Consider sampleScript.js with below code
(function(window){
'use strict';
window.app = {
sayHi: function() {
console.log('Hey there !');
}
};
})(this);
To load this script, I do
<script>
var node = document.createElement('script');
node.src = 'sampleScript.js';
node.addEventListener('load', onScriptLoad, false);
node.async = true;
document.head.appendChild(node);
function onScriptLoad(evt) {
console.log('Script loaded.');
console.log('app.sayHi ---> ');
app && app.sayHi();
}
</script>
Taking cues, you can fit to your need. Hope this helps.
Use the onload event:
x.onload = function() { window.loadData(); }
I was given a javascript function that I need to inject into a page in order to get a list of values that would be used later on. I can call this function directly on the webpage using the Chrome console but I want to replicate what I did in the Chrome console in nightmareJS on the webpage that is currently loaded.
This is the function:
function getList() {
require(['Service/List'],
function (Service)
{
Service.getList
({
onComplete: function (listOfServices)
{
console.log('List:success:' + JSON.stringify(listOfServices));
},
onFailure: function (error)
{
console.log('List:error:' + error);
}
});
});
}
getList();
I've tried injecting the file but I have had no success, I've also tried adding additional code to that function to write the output to a file but I do not think its being called at all.
Here is the nightmareJS
describe('Open login page', () => {
it('Login', done => {
nightmare
.goto('http://loginURL.com')
.wait('input[type="text"]')
.wait('input[type="password"]')
.insert('input[type="text"]', 'username')
.insert('input[type="password"]', 'password')
.click('input[type="submit"]')
.evaluate(function() {
nightmare.inject('js', 'getList.js' )
})
//.inject('js', 'getList.js' )
.then(function() {
console.log('Done');
})
})
})
})
This is the sample output after injecting the javascript file into the page:
List:success:"Test":"https://someURL.com/resource/test","Design":"https://someURL.com/resource/Design"},"NewSpace":"https://someURL.com/resource/NewSpace","Generator":"https://Generator.someURL.com/resource/test","SomethingElse":"https://someURL.com/SomethingElse/test","Connection":"https://someURL.com/Connection/test","WorldWide":"https://someURL.com/resource/WorldWide","Vibes":"https://Vibes.someURL.com/resource/test","GoogleSearch":"https://someURL.com/resource/GoogleSearch",
I want to be able to get that output from calling the javascript file on the page and save it to a file so that I can use it later to call other services in that list.
You can read the local javascript files that needs to be injected:
var fileData = [];
fileData.push(fs.readFileSync(path.resolve('../getList.js'), 'utf-8'));
It can be loaded into head section of the page via code:
browser.win
.evaluate(function(fileData) {
var elem = null;
for(var ii=0;ii<fileData.length; ii++ ) {
elem = document.createElement('script');
if (elem) {
elem.setAttribute('type', 'text/javascript'); //elem.src = localjs;
//console.log(fileData[ii]);
elem.innerHTML = fileData[ii];
document.head.appendChild(elem);
}
}
console.log("Testing loaded scripts");
console.log(getList());
return "Injected Scripts";
}, fileData)
.then(function(result) {
console.log(result);
}).catch(function(error) {
console.log("Load Error: ", error);
});
I am using the following to detect when my page has finished loading, but it is evidently wrong. The Angular stuff has not been executed yet when document.readyState is complete:
page.open(url, function (status) {
function checkReadyState() {
setTimeout(function () {
var readyState = page.evaluate(function () {
return document.readyState;
});
if ("complete" === readyState) {
// onPageReady();
doRender();
} else {
checkReadyState();
}
});
}
checkReadyState();
});
I didn't get the purpose exactly but you can use $timeout inside angular code which gets executed only after all execution is finished for that particular angular page, and pass a global method which is defined inside your javascript code.
Something like this-
Inside JS file -
var callBack = function(){
console.log('I have finished execution');
}
Inside Angular Controller -
$timeout(function(){
callBack();
});
If it doesn't solve your problem please elaborate more.
I am using sammy.js plugin in my single page application. The plugin is not working, whenever user tries to navigate in the page it is showing the following error on console :
[Tue Dec 04 2012 17:48:13 GMT+0530 (India Standard Time)] #main 404 Not Found get /page_home
Error
arguments: undefined
get stack: function () { [native code] }
message: "404 Not Found get /page_home "
set stack: function () { [native code] }
type: undefined
__proto__: d
What is this issue and how can it be fixed ?
EDIT
Sammy configuration code:
var app = $.sammy('#main', function () {
this.get('#/:name', function () {
var id = this.params['name'];
$.trim(id);
var flag = true;
if ($("#main").hasClass("presentation")) {
$.each(slides, function (i, v) {
if ($(v).attr("class") == id) {
ScanNavigationD(id);
flag = false;
return false;
}
});
if (flag) {
ScanNavigationD($(slides[0]).attr("class"));
}
}
else if ($("#main").hasClass("printdoc") || typeof $("#main").attr("class") == "undefined") {
$.each(Pages, function (i, v) {
if ($(v).attr("class") == id) {
ScanNavigationD(id);
flag = false;
return false;
}
});
if (flag) {
ScanNavigationD($(Pages[0]).attr("class"));
}
}
});
});
$(function () {
app.run();
});
#tom-rider the problem is the app.run called without argument.
The sammy app.run function accept a start_url argument to set (via the _setLocation method) the app current location before call _checkLocation method to check if url is changed...
So try to change
app.run();
with
app.run('#/');
this work for me.
Follow this fiddle for a working demo and look at the console: no error!
will this simple code work?
var app = $.sammy('#main', function () {
this.get('#/:name', function () {
alert(this.params['name']);
});
});
$(function () {
app.run();
});
if this small code alerts 'page_home' there is something wrong with your script inside:
then you should be able to answer these questions: where is the ScanNavigationD-Function? where are the "slides"/"Pages" - arrays defined?
EDIT:
ok, i did another test at my computer. thats what i did:
created a html-document
included first jQuery then sammy.js
<script src="http://code.jquery.com/jquery-1.8.3.min.js" type="text/javascript">
<script src="sammy.js" type="text/javascript">
i filled the vars and functions i asked for with dummy-content:
<script>
var ScanNavigationD = function() {},
slides = ['slide1', 'slide2'],
Pages = ['page1', 'page2'];
<script>
then i copy pasted your code into my html-document.
<script>
//your code
<script>
then i created the div-main container:
everything worked. the last thing i see you are doing wrong is, that you are just on your local filesystem.
sammy.js seems to need a webserver to run! at least localhost!
file://...
WILL NOT WORK
Seems like you are sending in page_home as a parameter when running the script which resolves to a 404 not found error. Try look for 'page_home' throughout your files, recursively to find where this is coming from.
I found a little javascript snippet for including javascripts only if they was not included before.
That is working with my own scripts, but with two third-party libraries it's not working and I really don't know why.
var included_files = new Array();
function include_once(script_filename) {
if (!in_array(script_filename, included_files)) {
included_files[included_files.length] = script_filename;
include_dom(script_filename);
}
}
function in_array(needle, haystack) {
for (var i = 0; i < haystack.length; i++) {
if (haystack[i] == needle) {
return true;
}
}
return false;
}
function include_dom(script_filename) {
var html_doc = document.getElementsByTagName('head').item(0);
var js = document.createElement('script');
js.setAttribute('language', 'javascript');
js.setAttribute('type', 'text/javascript');
js.setAttribute('src', script_filename);
html_doc.appendChild(js);
return false;
}
function loaded() {
include_once("shared/scripts/jquery.min.js");
include_once("shared/scripts/iscroll.js");
$(document).ready(function () {
alert("hello");
});
}
error: $ is not defined.
If I import jQuery the regular way its working and it says "iScroll" is not defined (because I'm using it later).
Any ideas?
include_dom is asynchronous. It loads the scripts in parallel, and you can't really determine when the scripts will be loaded. You try to use jQuery right after you started the download, which doesn't work.
You need to use a script that allows you to specify a callback for loaded scripts. I would recommend require.js
You are adding the scripts to the DOM, but not letting them load before you try to use the functions they provide.
You need to bind a callback to the load event of the script elements you are adding.
(At least in most browsers, you might have to implement some hacks in others; you may wish to examine the source code for jQuery's getScript method).
Did someone say callback?
function include_once(script_filename, callback) {
if (!in_array(script_filename, included_files)) {
included_files[included_files.length] = script_filename;
include_dom(script_filename, callback);
}
}
function include_dom(script_filename, callback) {
var html_doc = document.getElementsByTagName('head').item(0);
var js = document.createElement('script');
js.setAttribute('language', 'javascript');
js.setAttribute('type', 'text/javascript');
js.setAttribute('src', script_filename);
if(callback && callback != 'undefined'){
js.onload = callback;
js.onreadystatechange = function() {
if (this.readyState == 'complete') callback();
}
}
html_doc.appendChild(js);
return false;
}
function loaded() {
include_once("shared/scripts/jquery.min.js", function(){
$(document).ready(function () {
alert("hello");
});
});
include_once("shared/scripts/iscroll.js");
}
Use a script loader. yepnope will do everything you are trying to do and more