Javascript not working in IE8, not sure why - javascript

I have this code. I apologize for it being messy. I am a novice, hence the problem.It is supposed to populate checkboxes from the querystring. It works in Chrome, Safari, Firefox. Just started testing on IE and in IE 8 it doesn't work. The clicks are registered, but the checkboxes don't populate. No errors are thrown, it seems to simply ignore it.
//set var for queryString - "?"
var queryString = window.location.search.substring(1);
var parameters = queryString.split('&');
var paramObject = new Object();
for( var i =0; i < parameters.length; ++i){
var equalsPos = parameters[i].indexOf('=');
var key = decodeURIComponent(parameters[i].substring(0,equalsPos));
var stringLength = parameters[i].length;
var value = decodeURIComponent(parameters[i].substring(equalsPos + 1, stringLength).replace(/\+/g,' '));
if(!paramObject[key]) {
//console.log('paramObject[key] =' + paramObject[key]);
paramObject[key] = value;
//console.log('paramObject[key] = value = ' + value + paramObject[key]);
//console.log(paramObject[key]);
}else if(paramObject[key] instanceof Array){
paramObject[key].push(value);
//console.log(paramObject[key]);
} else {
var newArray = [];
var existingValue = paramObject[key];
//console.log('existing value: '+ existingValue);
//console.log('value: ' + value);
newArray.push(existingValue);
newArray.push(value);
paramObject[key] = newArray;
}
}
//console.log(paramObject);
for (key in paramObject) {
$('input[name="' + key + '"]').each(function(){
var obj = paramObject[key];
for(prop in obj){
if(obj instanceof Array){
if(obj.hasOwnProperty(prop)){
//console.log(key + '=' + obj[prop]);
if($(this).attr('value') == obj[prop]){
$(this).attr('checked','checked');
}
}
}else{
if(obj.hasOwnProperty(prop)){
if($(this).attr('value') == obj){
$(this).attr('checked','checked');
}
}
}
}
});
}

As answered here IE8 doesn't support the hasOwnProperty() method on host objects. There's a comment there with the answer you're looking for. Good luck!

Related

Column filtering and stacking on table not working on backspace in input

I have created my table with jQuery and have it using filtering on the column. However, ran into something interesting.
Below is my fiddle
https://jsfiddle.net/4sy5dweg/1/
So my issue is as follows -
Once I find what I am looking for by filtering. If I decided to start backspacing I want it to continue searching that column and obviously start going backwards on searching.
I hope that makes sense.
$.extend($.expr[":"], {
"containsIN": function (elem, i, match, array) {
return (elem.textContent || elem.innerText || "").toLowerCase().indexOf((match[3] || "").toLowerCase()) >= 0;
}
});
$("[id*=TXTSEARCH]").keyup(function () {
tablename = $(this).closest('table').attr('id');
mytd = $(this).closest('th');
var indexColumn = mytd.index();
var data = this.value.toLowerCase().split(" ");
var jo = $("[id*=" + tablename + "]").find("tr:not(:first)");
jo.filter(function (i, v) {
var $t = $(this).children(":eq(" + indexColumn + ")");
for (var d = 0; d < data.length; ++d) {
if ($t.is(":not(:containsIN('" + data[d] + "'))")) {
console.log(data[d]);
return true;
}
}
return false;
}).hide();
})
I know the issue has to do with hiding that row on initial search. However, somehow for isntance if someone has a typo and goes to backspace it wont show anything because that row is still hidden. Is there a way to keep the other filters in place and basically remove the filter from the row being corrected?
I hope I am making sense.
Update I have attempted the following -
$("[id*=TXTSEARCH]").keyup(function () {
var tablename = $(this).closest('table').attr('id');
console.log(tablename);
var FindMyRow;
$("#" + tablename).find('th:visible').find($("[id*=TXTSEARCH]")).each(function () {
FindMyRow = $(this).closest('th:visible');
var indexColumn = FindMyRow.index();
console.log($(this).attr('id') + " " + indexColumn);
var data = this.value.toLowerCase().split(" ");
var jo = $("[id*=" + tablename + "]").find("tr:not(:first)");
jo.show().filter(function (i, v) {
var $t = $(this).children(":eq(" + indexColumn + ")");
for (var d = 0; d < data.length; ++d) {
if ($t.is(":not(:containsIN('" + data[d] + "'))")) {
console.log(data[d]);
return true;
}
}
return false;
}).hide();
});
to no avail.
Decided to change my way of doing it.
I added a button to each column header that the user can click on so that if they make a type they just check it before clicking it.
$("[id*=BTNSEARCH]").click(function (e) {
e.preventDefault();
var tablename = $(this).closest('table').attr('id');
mytd = $(this).closest('th');
var TextBoxToSearch = ($(this).prev('input').val());
var indexColumn = mytd.index();
FindMyRow = $(this).closest('th:visible');
var indexColumn = FindMyRow.index();
var data = TextBoxToSearch.toLowerCase().split(" ");
var jo = $("#" + tablename).find("tr:not(:first)");
jo.filter(function (i, v) {
var $t = $(this).children(":eq(" + indexColumn + ")");
for (var d = 0; d < data.length; ++d) {
if ($t.is(":not(:containsIN('" + data[d] + "'))")) {
return true;
}
}
return false;
}).hide();
})

How can I get complex URI query string parameters in native JavaScript like in PHP?

My question is about full power solution for parsing ANY complex URI parameters using just normal browser's Javascript. Like it do PHP, for simple code compatibility between JS and PHP sources.
But the first, let us see some particular known decisions:
1.
There is popular question and answers on StackOverflow, see How can I get query string values in JavaScript?
You can find there quite simple solutions for common SIMPLE cases. For example, like handling this scalar parameters like this one:
https://example.com/?name=Jonathan&age=18
It has no answers for handling complex query params. (As far as I could see for answers with source codes and author comments)
2.
Also you may use an URL object in modern browsers, see https://developer.mozilla.org/en-US/docs/Web/API/URL, or exactly https://developer.mozilla.org/en-US/docs/Web/API/URL/searchParams
It is enought powerful and you don't need to write or load any code for parsing URI parameters - just use
var params = (new URL(document.location)).searchParams;
var name = params.get("name"); // is the string "Jonathan"
var age = parseInt(params.get("age")); // is the number 18
This approach has such disadvantage that URL is available only in most of modern browsers, - other browsers or outdated versions of browsers will fail.
So, what I need. I need parsing any complex URI params, like
https://example.com/?a=edit&u[name]=Jonathan&u[age]=18&area[]=1&area[]=20&u[own][]=car&u[own][]=bike&u[funname]=O%27Neel%20mc%20Fly&empty=&nulparam&the%20message=Hello%20World
to
{
'a': 'edit',
'u': {
'name': 'Jonathan',
'age': '18',
'own': ['car', 'bike'],
'funname': 'O\'Neel mc Fly'
},
'area': [1, 20],
'empty': '',
'nulparam': null,
'the message': 'Hello World'
}
Preferrable answer is just plain readable javascript source. Simple and small wide-used library can be accepted too, but this question is not about them.
`
PS:
To start I just publish my own current solution for parsing URI params and vice versa for making URI from params. Any comments for it are welcome.
Hope this helps to save time for lot of coders later.
My solution
Usage:
var params = getQueryParams(location.search);
var params = getQueryParams();
var params = {...};
var path = '...';
var url = path;
var urlSearch = getQueryString(params);
if (urlSearch) {
url += '?' + urlSearch;
}
history.replaceState({"autoUrl": url}, "autoreplace", url);
Code:
function getQueryParams(qs) {
if (typeof qs === 'undefined') {
qs = location.search;
}
qs = qs.replace(/\+/g, ' ');
var params = {},
tokens,
re = /[?&]?([^=]+)=([^&]*)/g;
while (tokens = re.exec(qs)) {
var name = decodeURIComponent(tokens[1]);
var value = decodeURIComponent(tokens[2]);
if (value.length == 0) {
continue;
}
if (name.substr(-2) == '[]') {
name = name.substr(0, name.length - 2);
if (typeof params[name] === 'undefined') {
params[name] = [];
}
if (value === '') {
continue;
}
params[name].push(value);
continue;
}
if (name.substr(-1) == ']') {
var nameParts = name.split('[');
name = nameParts[0];
for (var i = 1; i < nameParts.length; i++) {
nameParts[i] = nameParts[i].substr(0, nameParts[i].length - 1);
}
var ptr = params;
for (var i = 0; i < nameParts.length - 1; i++) {
name = nameParts[i];
if (typeof ptr[name] === 'undefined') {
ptr[name] = {};
}
ptr = ptr[name];
}
name = nameParts[nameParts.length - 1];
ptr[name] = value;
continue;
}
params[name] = value;
}
return params;
}
function getQueryString(params) {
var paramsStringParts = [];
for (var name in params) {
if (params[name] instanceof Array) {
paramsStringParts.push( name + '[]=' + params[name].join('&' + name + '[]=') );
} else if (typeof params[name] === 'object') {
var makeFlattern = function(obj){
var result = [];
if (obj instanceof Array) {
for (var i = 0; i < obj.length; i++) {
result.push('[]=' + obj[i]);
}
return result;
}
for (var i in obj) {
if (typeof obj[i] === 'object') {
var subResult = makeFlattern(obj[i]);
for (var j = 0; j < subResult.length; j++) {
result.push('[' + i + ']' + subResult[j]);
}
continue;
}
result.push('[' + i + ']=' + obj[i]);
}
return result;
};
paramsStringParts.push( name + makeFlattern(params[name]).join('&' + name) );
} else {
paramsStringParts.push( name + '=' + params[name] );
}
}
return paramsStringParts.join('&');
}
A bit late, but just struggled over the same problem, solution was very simple:
use encodeURIComponent(...) for the stringified complex objects, the result can then be used as normal queryString-Part.
In the result-side the query-string-parameters have to be un-stringified.
Example:
var complex_param_obj = {
value1: 'Wert1',
value2:4711
};
console.log(restored_param_obj);
var complex_param_str = encodeURIComponent(JSON.stringify(complex_param_obj));
console.log(complex_param_str);
var complex_param_url = 'http://test_page.html?complex_param=' + complex_param_str;
//on the result-side you would use something to extract the complex_param-attribute from the URL
//in this test-case:
var restored_param_obj = decodeURIComponent(complex_param_str);
console.log(restored_param_obj);

Splitting out xml result into dropdownlist

Hope someone can help - I'm new to js/jQuery so I'm hoping it's something really simple I'm missing here.
I'm trying to populate a dropdownlist with the xml result from below. The parseXML function works great and the result.push(valueid + "," + value) leaves me with the following:
1,Service
2,Breakdown
How do I get this into a dropdownlist please? Using the below, I get the error "Object doesn't support property or method 'split'"
Many thanks
leddy
function testFunction() {
var jobresults = "<resultset morerecords='0'> " +
"<result> " +
"<itt_jobtypeid>1</itt_jobtypeid> " +
"<itt_name>Service</itt_name> " +
"</result> " +
"<result> " +
"<itt_jobtypeid>2</itt_jobtypeid> " +
"<itt_name>Breakdown</itt_name> " +
"</result> " +
"</resultset> ";
var xml = parseXML(jobresults);
var jobid = xml.getElementsByTagName("itt_jobtypeid");
var jobname = xml.getElementsByTagName("itt_name");
var result = [];
for (var i = 0; i < jobid.length; i++) {
var valueid = jobid[i].childNodes[0].nodeValue;
var value = jobname[i].childNodes[0].nodeValue;
// add longitude value to "result" array
result.push(valueid + "," + value);
}
var jobtype = $("#ddlJobType");
$.each(result, function () {
var arr = result.split(',');
for (var i = 0; i < arr.length; i++) {
jobtype.append($("<option />").val(arr[0]).text(arr[1]));
}
});
}
function parseXML(text) {
if (window.DOMParser) {
parser = new DOMParser();
doc = parser.parseFromString(text, "text/xml");
}
else { // Internet Explorer
doc = new ActiveXObject("Microsoft.XMLDOM");
doc.async = "false";
doc.loadXML(text);
}
return doc;
}
It can be simpler and cleaner if you optimize data structure for result array. Push an object with value and label so that you can simply use attr method directly after:
for (var i = 0; i < jobid.length; i++) {
var valueid = jobid[i].childNodes[0].nodeValue;
var value = jobname[i].childNodes[0].nodeValue;
// add longitude value to "result" array
result.push({value: valueid, label: value});
}
var jobtype = $("#ddlJobType");
$.each(result, function (i, obj) {
$('<option>').attr(obj).appendTo(jobtype);
});
See https://api.jquery.com/jquery.each/. The callback function gets each jobtype as parameter to the function.
Try changing the code to:
$.each(result, function (idx, value) {
var arr = value.split(',');
for (var i = 0; i < arr.length; i++) {
jobtype.append($("<option />").val(arr[0]).text(arr[1]));
}
});

building a database string

I'm trying to build a database based on some arbitrary data on a website. It's complex and changes for each site so I'll spare the details. Here's basically what I'm trying to do
function level0(arg) { textarea.innerHTML += arg + ' = {'; }
function level1(arg) { textarea.innerHTML += '\n\t' + arg + ': ['; }
function level2(arg) { textarea.innerHTML += arg + ', '; }
And so on. The thing is some level1's don't have any children and I can't get the formatting right.
My three problems are as follows.
The ending commas are going to break in IE (thank you MS)
Empty level1's shouldn't be printed if they don't have any children
Closing /curly?brackets/
HERE'S A DEMO of what I have so far. Notice the ending commas, the empty sub2 which shouldn't be printed, and no closing brackets or braces
Do I need to redesign the entire thing?
Is there also a way to have this all in one function so I don't have to worry if I add another layer?
EDIT
This needs to be done in a string format, I can't build an object and then stringify it, mostly because I need to know which element I'm in the middle of adding to.
Overall it looks that you still might want to build an object, but in case you insist on not building it - here is some sample solution:
function Printer() {
var result = '',
lastLevel = null,
close = {0:'\n}', 1:']', 2:''},
delimiter = {0: ',\n', 1:',\n', 2:','};
function closeLevel(level, noDelimiter) {
if(lastLevel === null)
return;
var l = lastLevel, d = level == lastLevel;
while(l >= level) {
result += close[l] + (l == level && !noDelimiter ? delimiter[l]:'');
l--;
}
}
this.level0 = function(arg) {
closeLevel(0);
result += arg + ' = {\n';
lastLevel = 0;
};
this.level1 = function(arg) {
closeLevel(1);
result += '\t' + arg + ': [';
lastLevel = 1;
};
this.level2 = function(arg) {
closeLevel(2);
result += arg;
lastLevel = 2;
};
this.getResult = function() {
closeLevel(lastLevel, true);
return result;
}
}
var p = new Printer();
p.level0('head');
p.level1('sub1');
p.level2('item1');p.level2('item2');p.level2('item3');
p.level1('sub2');
p.level1('sub3');
p.level2('newthing');
p.level0('head2');
document.getElementById('textarea').value = p.getResult();
You could see it in action here.
I'm not sure why you're building what looks like objects with nested arrays, using string concatenation. Something like this would be much simpler, since it wouldn't require fixing trailing commas, etc:
Edit: I've updated the code to make it keep track of the last level put in.
function Db() {
var level0, level1;
var data = new Object();
this.level0 = function(arg) {
level0 = new Object();
data[arg] = level0;
}
this.level1 = function(arg) {
level1 = new Array();
level0[arg] = level1;
}
this.level2 = function(arg) {
level1.push(arg);
}
this.toString = function() {
var s = '';
for(i in data) {
s += i + '\n';
for(j in data[i]) {
if(data[i][j].length>0) {
s += '\t' + j + ': [' + data[i][j] + ']\n' ;
}
}
}
return s;
}
}
Use like this:
var db = new Db();
db.level0('head');
db.level1('sub1');
db.level2('item1');db.level2('item2');db.level2('item3');
I've tested this in the demo you linked and it works just fine.

JS: Can not convert to object, childNodes related

Ok, feeling stupid here, but wondering what the problem is here exactly.
Although the function works as it should, I get this JS Error in Opera. Not sure about other browsers...
Uncaught exception: TypeError: Cannot
convert
'document.getElementById("shoutbox_area"
+ moduleId)' to object
oElement = document.getElementById("shoutbox_area"
+ moduleId).childNodes;
Here is the relevant code:
function appendShout(XMLDoc)
{
var shoutData = XMLDoc.getElementsByTagName("item");
var oElement = [];
if (shoutData.length > 0)
{
var moduleId = shoutData[0].getAttribute("moduleid");
if (shoutData[shoutData.length - 1].getAttribute("lastshout") != "undefined")
{
for (var i = 0; i < shoutData.length; i++)
if (shoutData[i].firstChild.nodeValue != 0)
document.getElementById("shoutbox_area" + moduleId).innerHTML += shoutData[i].firstChild.nodeValue;
oElement = document.getElementById("shoutbox_area" + moduleId).childNodes;
var i = oElement.length;
while (i--)
{
if (i % 2 == 0)
oElement[i].className = "windowbg2";
else
oElement[i].className = "windowbg";
}
oElement[oElement.length - 2].style.borderBottom = "1px black dashed";
}
}
}
Can someone please help me to understand why it is giving me an error here:
oElement = document.getElementById("shoutbox_area" + moduleId).childNodes;
Can I not assign an array to the childNodes?
EDIT:
This JS Error occurs when I try and delete a shout. The JS function for deleting a shout is this:
function removeShout(shout, moduleID)
{
var shoutContainer = shout.parentNode.parentNode;
var send_data = "id_shout=" + shout.id;
var url = smf_prepareScriptUrl(smf_scripturl) + "action=dream;sa=shoutbox;xml;" + "delete_shout;" + "canmod=" + canMod[moduleID] + ";" + sessVar + "=" + sessId;
sendXMLDocument(url, send_data);
var shoutID = 0;
while (shoutID !== null)
{
var shoutID = document.getElementById(shout.parentNode.id);
var moduleID = shoutID.parentNode.getAttribute("moduleid");
if (shoutID.parentNode.lastChild)
{
var url = smf_prepareScriptUrl(smf_scripturl) + "action=dream;sa=shoutbox;xml;get_shouts=" + (shoutID.parentNode.lastChild.id.replace("shout_", "") - 1) + ";membercolor=" + memberColor[moduleID] + ";maxcount=" + maxCount[moduleID] + ";shoutboxid=" + shoutboxID[moduleID] + ";textsize=" + textSize[moduleID] + ";parsebbc=" + parseBBC[moduleID] + ";moduleid=" + moduleID + ";maxcount=" + maxCount[moduleID] + ";canmod=" + canMod[moduleID] + ";" + sessVar + "=" + sessId;
getXMLDocument(url, appendShout);
}
element = shoutID.parentNode.childNodes;
var i = element.length;
while (i--)
{
if (i % 2 == 0)
element[i].className = "windowbg2";
else
element[i].className = "windowbg";
}
shoutID.parentNode.removeChild(shoutID);
}
}
Am using the following functions for the sending and getting the XMLHttpRequest as you may have noticed already in the removeShout function above:
// Load an XML document using XMLHttpRequest.
function getXMLDocument(sUrl, funcCallback)
{
if (!window.XMLHttpRequest)
return null;
var oMyDoc = new XMLHttpRequest();
var bAsync = typeof(funcCallback) != 'undefined';
var oCaller = this;
if (bAsync)
{
oMyDoc.onreadystatechange = function () {
if (oMyDoc.readyState != 4)
return;
if (oMyDoc.responseXML != null && oMyDoc.status == 200)
{
if (funcCallback.call)
{
funcCallback.call(oCaller, oMyDoc.responseXML);
}
// A primitive substitute for the call method to support IE 5.0.
else
{
oCaller.tmpMethod = funcCallback;
oCaller.tmpMethod(oMyDoc.responseXML);
delete oCaller.tmpMethod;
}
}
};
}
oMyDoc.open('GET', sUrl, bAsync);
oMyDoc.send(null);
return oMyDoc;
}
// Send a post form to the server using XMLHttpRequest.
function sendXMLDocument(sUrl, sContent, funcCallback)
{
if (!window.XMLHttpRequest)
return false;
var oSendDoc = new window.XMLHttpRequest();
var oCaller = this;
if (typeof(funcCallback) != 'undefined')
{
oSendDoc.onreadystatechange = function () {
if (oSendDoc.readyState != 4)
return;
if (oSendDoc.responseXML != null && oSendDoc.status == 200)
funcCallback.call(oCaller, oSendDoc.responseXML);
else
funcCallback.call(oCaller, false);
};
}
oSendDoc.open('POST', sUrl, true);
if ('setRequestHeader' in oSendDoc)
oSendDoc.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
oSendDoc.send(sContent);
return true;
}
Hopefully this is good enough, you can do a view source on it to see the actual HTML, but there are attributes that get added to the Shoutbox tags at runtime so as to be XHTML compliant, etc..
Please let me know if there is anything else you need?
Thanks :)
The code is breaking because shoutID is null in the second of these two lines, the second time through the loop:
var shoutID = document.getElementById(shout.parentNode.id);
var moduleID = shoutID.parentNode.getAttribute("moduleid");
The first of those lines is strange. Why not just use var shoutID = shout.parentNode;?
Also, the moduleId attribute seems to be nowhere around.
What are you trying to achieve with the while loop?

Categories