Alert or Console.log not working from dynamically loaded JavaScript - javascript

I use the following function to dynamically load JavaScript:
function loadJS(file, c)
{
var jsEl = document.createElement("script");
jsEl.type = "application/javascript";
jsEl.src = file;
jsEl.async = false;
document.body.appendChild(jsEl);
if (c) { jsEl.addEventListener('load', function (e) { c(null, e); }, false); }
document.getElementsByTagName("head")[0].appendChild(jsEl);
}
Below is one of the functions contained within a dynamically added file:
function formelements_SELECT_add(x)
{
console.log("add");
alert("add");
var id = x[1];
var value = x[2];
var index = x[3];
var select = document.getElementById(id);
var option;
option = document.createElement("option");
option.text = value;
select.add(option, index);
}
I know the JavaScript file gets added correctly and the function gets executed because an option is added to the select element. Why does the alert and console.log not execute? If I click inspect, then there are no error messages.
EDIT
This is the code I use to call the function:
var typeAndElement = x[0][0] + "_" + x[0][1];
start = i + 1;
if (!window[typeAndElement])
{
loadJS("https://websemantica.org/scripts/" + x[0][0] + "/" + x[0][1] + ".js", continueManipulatingElements(typeAndElement, actions, x, start, total));
return;
}
else
{
fn = window[typeAndElement + "_" + x[0][2]];
if (typeof fn === 'function')
fn(x);
}
I didn't want to include it initially, because I already knew it was working and it will be unclear how it works considering it is using dynamic data.
Also, I have edited the loadJS function:
function loadJS(file, c)
{
var jsEl = document.createElement("script");
jsEl.type = "text/javascript";
jsEl.src = file;
jsEl.async = false;
if (c) { jsEl.addEventListener('load', function (e) { c(null, e); }, false); }
document.getElementsByTagName("head")[0].appendChild(jsEl);
}
The problem appears to be solved now.

Three things jump out:
You're appending the script to the page twice, once to document.body, and the other to document.getElementsByTagName("head")[0]. The second one will move the script from the first place to the second. You really only need to do one of those.
You're looking the load event after appending the element. If the script is in cache, you can miss the event. Hook it before appending the script to the DOM.
You're not doing anything in the quoted code to call the function that's defined by the script you're adding.
Other side notes:
No need to set type, the default is JavaScript.
No need to set async, all dynamically-inserted script elements are async (now, it wasn't always true).
As Jarosław Wlazło points out document.alert isn't a function; just alert is all you need. :-)

In addition: document has no alert method. It belongs to window, so you can call it like this alert('add');

Related

How do I use an array instead of the variables in this repetitive function?

So, I have this little code in my js file:
window.onload = function Equal() {
var a = 'b1'
var b = 'box1'
var bookstorname = localStorage.getItem(a)
if (bookstorname == 1) {
document.getElementById(b).setAttribute('checked','checked');
}
if (bookstorname == 0) {
document.getElementById(b).removeAttribute('checked','checked');
}
var a = 'b2'
var b = 'box2'
var bookstorname = localStorage.getItem(a)
if (bookstorname == 1) {
document.getElementById(b).setAttribute('checked','checked');
}
if (bookstorname == 0) {
document.getElementById(b).removeAttribute('checked','checked');
}
}
The function itself is not important (it equals checkboxvalues set in the localstorage), but I execute it 2 times. First time with var a & b set to 'b1' & 'box1'. Then I run the script again (same script), but with var a & b set to 'b2' & 'box2'. Now, this code works, but my question is if there is a shorter way to write this? I can imagine some sort of array with a loop, but I could not get it to work for some reason. The 2 variables are pairs, and I know this might be a dumb question, but I can't find the answer anywhere.
You can use a second function which will accept the local storage key and the checkbox id like
window.onload = function Equal() {
setCheckboxState('box1', 'b1');
setCheckboxState('box2', 'b2');
}
function setCheckboxState(id, key) {
document.getElementById(id).checked = 1 == localStorage.getItem(key);
}
You might separate common logic into another function
window.onload = function Equal() {
function extractFromStorage(a, b) {
var bookstorname = localStorage.getItem(a)
if (bookstorname == 1) {
document.getElementById(b).setAttribute('checked','checked');
}
if (bookstorname == 0) {
document.getElementById(b).removeAttribute('checked','checked');
}
}
extractFromStorage('b1', 'box1');
extractFromStorage('b2', 'box2');
}
function doTheStuff(a, b) {
var bookstorname = localStorage.getItem(a)
if (bookstorname == 1) {
document.getElementById(b).setAttribute('checked','checked');
}
if (bookstorname == 0) {
document.getElementById(b).removeAttribute('checked','checked');
}
}
window.onload = function Equal() {
doTheStuff('b1', 'box1');
doTheStuff('b2', 'box2');
}
?
This is how I would do it.
There are several problems with your code.
You do not check that the element you are stetting an attribute to
exists. You do not check if the localStorage item you get is
defined.
You pollute the global name space with the function name Equal.
That function should not be named with a capital as it is not a Object generator.
There is no need to use setAttribute and removeAttribute, in
fact removeAttribute makes no sense in this case as you can not
remove the checked attribute from the element. BTW why use setAttribute here and not for window.onload?
The checked attribute is either true or false, it does not use the
string "checked"
Binding the load event via the onload attribute is not safe as you may
block 3rd party code, or worse 3rd party code may block you.
There is no error checking. DOM pages are dynamic environments, pages
have adverts and content from many places that can interfer with your
code. Always code with this in mind. Check for possible errors and deal with them in a friendly way for the end user. In this case I used an alert, not friendly for a normal user but for you the coder.
My solution.
// add an event listener rather than replace the event listener
window.addEventListener(
"load", // for the load event
function(){
// the update function that is called for each item;
var update = function(item){
// the right hand side equates to true if the localstorage
// is equal to "1". LocalStorage allways returns a string or
// undefined if the key is not defined.
item.element.checked = localStorage[item.storageName] === "1";
}
// safe element getter
var getElement = function(eId){
var e = document.getElementById(eId); // try and get the element
if(e === null){ // does it exist?
throw "Missing element:"+eId; // no then we can not continue
// the program stops here unless
// you catch the error and deal with
// it gracefully.
}
return e; //ok return the element.
}
// Item creator. This creates a new item.
// sName is the local storage name
// eId id the element ID
var item = function(sName, eId){
return {
storageName: sName, // set the loaclStorage name
element:getElement(eId); // get the element and check its safe
};
}
// make it all safe
try{
// create an array of items.
var items = [
item("b1","box1"),
item("b2","box2")
];
// for each item update the element status
items.forEach(update);
}catch(e){
alert("Could not update page?");
}
}
);

misunderstood Javascript functions call

I trying to customize HTML file input and wrote simplest jquery API function:
(function($)
{
$.fn.selectFileInputGUI = function()
{
var outerWrapper = $('<div>').css({'display':'inline-block'});
var innerWrapper = $('<div>').css({'width':'0', 'height':'0', 'overflow':'hidden'});
var fileInput = $('<input>').attr({type:'file'});
var fileNameHTML = $('<div>').css({'display':'inline-block', 'margin-left':'3px'});
var selectBtnGUI = $('<button>').addClass('btn btn-success btn-sm').text('Select file').click(function()
{
$.fn.selectFileInputGUI.resetInput();
fileInput.trigger('click');
});
fileInput.on('change', function()
{
$.fn.selectFileInputGUI.displayFileName();
});
$(this)
.append(outerWrapper.append(innerWrapper.append(fileInput)).append(selectBtnGUI))
.append(fileNameHTML);
$.fn.selectFileInputGUI.displayFileName = function()
{
var fileName = fileInput.val();
if(fileName.length > 0)
{
var pos = fileName.lastIndexOf("\\");
if(pos != -1) fileName = fileName.substr(pos + 1);
if(fileName.length > 14) fileName = fileName.substr(0, 14) + '...';
} else
{
fileName = 'File not selected';
}
fileNameHTML.text(fileName);
};
$.fn.selectFileInputGUI.resetInput = function()
{
fileInput.wrap('<form>').parent('form').trigger('reset');
fileInput.unwrap();
};
}
})(jQuery);
When I trying to apply selectFileInputGUI api function to the several selectors, only last selector handles well - http://jsfiddle.net/URKM5/5/
How to implement it correctly?
Looks like your problem is in how you reuse the variable fileInput and fileNameHTML, after user selecting the file, and you call this $.fn.selectFileInputGUI.displayFileName(); the fileInput and fileNameHTML always refer to the fileInput and fileNameHTML of the second fileDialog (because the second fileDialog is initialized after the first and all these variables are overridden). So to solve this problem, you have to pass these variables via the so-called event data, it's much helpful in this case:
//Note the second argument, it's passed in as event data
//You can access the event data via e.data
fileInput.on('change', fileNameHTML, function(e) {
$.fn.selectFileInputGUI.displayFileName($(this), e.data);
});
Your displayFileName need to accept 2 arguments, the first refers to the fileInput (which can be passed in as $(this) in the onchange event handler of the fileInput), the second refers to the fileNameHTML (which is passed in as e.data).
//note about the change of the arguments
$.fn.selectFileInputGUI.displayFileName = function(fileInput, fileNameHTML) {
//the code is unchanged here ...
}
Now selecting the files between the 2 dialogs is independent.
Demo.
After some deeper looking into the problem, looks like you don't need to use event data here. Just pass the fileNameHTML right as the second argument into displayFileName(...) function. Updated Demo

javascript api simplified

Was using fourquare api to get venue, had previously had a clickable list written out from api but cut it down to just one venue name written to screen. Then decided it'd be best to just send it over to php. So when I did what I thought was logical cutting of the code, it stopped working completely.
My program has this, working:
$(document).ready(function doEverything(element) {
$.getJSON("https://api.foursquare.com/v2/venues/search?ll=" + lat + "," + lng + "&client_id=L2VWBKPOW45D5X3FJ3P4MJB5TGVJ4ST2J005RIVAFIWG44ND%20&client_secret=ZKDAOLHASCA31VUOGMBTAS3RFYUOMXL4IFFYPRURIDQA3QMA%20&v=20111107", function(data) {
one = data.response.venues[0].name;
var list = [];
list[0] = [one];
function Make() {
for (var i = 0; i < 1; i++) {
var div = document.createElement("div");
div.style.margin = "-435px 100px 0px 110px";
div.innerHTML = list[i];
!
function() {
var index = 0;
div.onclick = function() {
doSomething(this);
};
}();
document.body.appendChild(div);
}
}
function doSomething(element) {
var value = element.innerHTML;
switch (value) {
case one:
break;
}
}
Make();
});
});
Then I decided I wanted to pass a variable over to php using this:
theVar = 10; //just to make things simple.
urlString = "cookiestesttwo.php?var=" +theVar;
window.location = urlString;
So I tried to simplify my api code to this, and it stopped working:
$(document).ready() {
$.getJSON("https://api.foursquare.com/v2/venues/search?ll=" + lat + "," + lng + "&client_id=L2VWBKPOW45D5X3FJ3P4MJB5TGVJ4ST2J005RIVAFIWG44ND%20&client_secret=ZKDAOLHASCA31VUOGMBTAS3RFYUOMXL4IFFYPRURIDQA3QMA%20&v=20111107", function(data) {
one = data.response.venues[0].name;
document.write(one)
theVar = one
urlString = "cookiestesttwo.php?var=" + theVar;
window.location = urlString;)
};
};​
$(document).ready() { is not proper syntax and does throw errors.
Furthermore there was another syntax error at the end of the function. you reversed } and )
$(document).ready(function() {
$.getJSON("https://api.foursquare.com/v2/venues/search?ll=" + lat + "," + lng + "&client_id=L2VWBKPOW45D5X3FJ3P4MJB5TGVJ4ST2J005RIVAFIWG44ND%20&client_secret=ZKDAOLHASCA31VUOGMBTAS3RFYUOMXL4IFFYPRURIDQA3QMA%20&v=20111107", function(data) {
one = data.response.venues[0].name; // if one is local to this function then use VAR otherwise you'll leak it globally.
document.write(one);
theVar = one; // same here for the VAR keyword.
urlString = "cookiestesttwo.php?var=" + theVar; // and here as well. NO GLOBAL LEAKS!
window.location = urlString;
});
});
I threw a few more hints in the comments.
Your problem might be that you use document.write() when the DOM is already complete. You are not supposed to do that. Create an element document.createElement( "div" ) and set the innerText() and then append it to the dom. Much like you did before the refactor.
EDIT
I understand that it wasn't the document.write() but just do clarify what I was talking about I wrote a little refactor. I also threw out the theVar = one since that is redundant. Also make sure to declare your variables in the right scope. Therefore I added a var in front of the one.
$(document).ready(function() {
$.getJSON("https://api.foursquare.com/v2/venues/search?ll="+lat+","+lng+"&client_id=L2VWBKPOW45D5X3FJ3P4MJB5TGVJ4ST2J005RIVAFIWG44ND%20&client_secret=ZKDAOLHASCA31VUOGMBTAS3RFYUOMXL4IFFYPRURIDQA3QMA%20&v=20111107",
function(data){
var one = data.response.venues[0].name;
var div = document.createElement( "div" );
div.innerText( one );
document.appendChild( div );
window.location = "cookiestesttwo.php?var=" + one;
});
});
But if you change the location of the window. There is no point to document.write() or appending a new div since you leave the site anyways.

Customer JQuery Plugin

I am learning JQuery. I have a need to create a custom control. This control is going to basically render some HTML. Sometimes, I want to just get the HTML. My hope is to use the following syntax:
// Put generated html inside of "myElement". "myElement" is a div element.
$("#myElement").myPlugin({ value: 10 });
// Retrieve the html that myPlugin would place of a div element.
// Basically, I want the javascript equivalent of a C# static function here.
// But I think the following approach is wrong:
var html = myPlugin().getHtml(10);
alert(html);
In an attempt to accomplish this, I'm using the following:
(function ($) {
$.fn.myPlugin = function (element, options) {
var defaults = { theValue: 0 }
var plugin = this;
plugin.settings = {};
var $element = $(element),
element = element;
plugin.init = function () {
plugin.settings = $.extend({}, defaults, options);
var html = createHtml(defaults.theValue);
$(element).html(html);
}
plugin.getHtml = function (v) {
return createHtml(v);
}
var createHtml(v) {
return "<span>" + v + "</span>";
}
})(jQuery);
I have two problems: 1) I can see that the HTML is being generated, but it does not appear to be added to the DOM. 2) I can't statically call the function. How can I make my function statically visible?
Thank you!
There are a few tweaks you need to make:
(function($) {
$.fn.myPlugin = function(options) {
var defaults = {
theValue: 0
},
settings = $.extend({}, defaults, options);
this.html($.myPlugin.getHtml(settings.theValue));
};
$.myPlugin = {
getHtml: function(value) {
return "<span>" + value + "</span>";
}
};
})(jQuery);
Usage:
$("#foo").myPlugin({ theValue: 10 });
var html = $.myPlugin.getHtml(10);
First off, you were never calling the init method, so nothing was going to work. It isn't going to be called automatically. Perhaps you were thinking of the jQueryUI widget factory?
Additionally, element doesn't get passed to the plugin, this refers the the element the plugin was called on. You only get passed options.
Finally, to create a static jQuery method, just attach it right to $.
Example: http://jsfiddle.net/xF2S6/

In JQGrid add onclick event on img

I'm very new to JQuery, and I'm having some trouble
function Clients(guid)
{
var that = this;
this.guid = guid;
this.container = $("#Clients_" + that.guid);
this.LoadClients = function () {
var ids = that.container.find("#clients-tbl").getDataIDs();
for (var i = 0; i < ids.length; i++) {
var row = that.container.find("#clients-tbl").getRowData(ids[i]);
var imgView = "<img src='../../Content/Images/vcard.png' style='cursor:pointer;' alt='Open case' onclick=OnClickImage(" + ids[i] + "); />";
that.container.find("#clients-tbl").setRowData(ids[i], { CasesButtons: imgView });
}
}
this.CreateClientsGrid = function () {
var clientsGrid = that.container.find("#widget-clients-tbl").jqGrid({
.....
ondblClickRow:function(rowid)
{
---
}
loadComplete: function () {
that.LoadClients();
}
}
this.OnClickImage=function(idClient){
....
}
this.Init = function () {
that.CreateClientsGrid();
};
this.Init();
}
The problem is with onclick, because OnClickImage is not global function.
How can I use OnClickImage function?
You can bind to the click event in different ways. For example you can follow the way from the answer. By the way, it works much more quickly as getRowData and setRowData. Moreover you should save the result of that.container.find("#clients-tbl") operation in a variable outside of the loop and use use the variable inside the loop. JavaScript is dynamic language and every operation even ids.length will be done every time.
One more way would to use onCellSelect event without click event binding. See the answer which describe the approach and gives the corresponding demo.

Categories