Grid not rendering in firefox - javascript

I am working with EditableGrid to generate and manipulate column models dynamically. Everything has gone according to the plan, except for just one compatibility issue with Firefox (..yes not IE -_-). I understand this is some sort of Closure issue maybe? I cannot seem to work a way around this. This is where something goes wrong:
EditableGrid.prototype.initializeGrid = function () {
with (this) {
//apply cell validators and inforenderers in headers
var regex = [];
for (var count = 0; count < selectedColumnNames.length; ++count) {
var columnObj = findSelectedColumnObject(selectedColumnNames[count]);
//check if regex is provided
if (!(columnObj[0].validationRegex == "")) {
// add a cell validator
var expression = new RegExp(columnObj[0].validationRegex);
regex[columnObj[0].name] = new RegExp(columnObj[0].validationRegex);
var valObj = GetValidatorObject(expression);
addCellValidator(columnObj[0].name, valObj);
}
}
function GetValidatorObject(regObj){
var obj = {
isValid: function (value) {
return value == "" || (regObj.test(value));
}
};
return new CellValidator(obj);
}
}
The exception it throws is:
ReferenceError: GetValidatorObject is not defined [var valObj =
GetValidatorObject(expression);]
Any ideas?

Thanks to epascarello, the work around was simple, I moved the method of GetValidatorObject out of the scope of with (this). Now it works with FF. When I further digged into the matter, I found avoid using 'with' keyword in JS really interesting. This might clear grey areas.

Related

Chrome 57 making .data() not function well

This part of an .on("change") event is not working properly when users are working in Chrome 57. This is only a Chrome 57 issue.
The userId variable in the if is set and has a value before it gets to this piece of code.
However, the conditional is not being found true when it should.
But if I am debugging and have a break point set I think on the if and I stop at the break point and linger for a while does this work properly.
This is not affecting everyone using 57.
I've only been able to recreate this issue twice and after debugging, it goes away.
Any idea on what's going on and how to fix it?
I will also note that we are using a very old version of jquery - 1.11.1 and upgrading will not be easy.
var selected = $(this).children("option:selected");
var name = selected.html();
var userId = selected.attr("value");
var personInList;
$("li", "#list1").add("li.person", "#list2").each(function () {
if ($(this).data("userId") == userId) {
personInList = $(this);
return;
}
});
if (userId && userId!= "default" && !personInList) {
//some code that gets triggered that shouldn't because this "if" is turning up true
}
For me, this did the trick:
In the place that the .data() is set, just save the element or the result of data somewhere.
$('#someElem').data('userId', '1234');
var elemData = $('#someElem').data('userId');
window['someUniqueKey'] = elemData;
//or
console.log(elemData);
Then, the call to $('#someElem').data('userId') should return valid data in your event handler.
As to why this happens: I would be very gratefull for an answer. A colleague of mine suggested it might be something with the Garbage Collection in the new Chrome. But if so, it looks like it's a bug in the GC.
I don't know the exact cause, but this seems related to garbage collection.
Also, Chrome has started doing some aggressive Javascript throttling.
https://blog.chromium.org/2017/03/reducing-power-consumption-for.html
https://docs.google.com/document/d/1vCUeGfr2xzZ67SFt2yZjNeaIcXGp2Td6KHN7bI02ySo
https://docs.google.com/document/d/18_sX-KGRaHcV3xe5Xk_l6NNwXoxm-23IOepgMx4OlE4
I have been trying a very hacky fix, but it seems to improve things:
var _oldjQueryData = jQuery.fn.data;
var _chrome57Fix = {};
jQuery.fn.data = function(key, value){
if(key && value) {
var resultElem = _oldjQueryData.call(this, key, value);
var resultData = _oldjQueryData.call(this, key)
var cacheKey = key + '_' + 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
return v.toString(16);
});
_chrome57Fix[cacheKey] = resultData;
return resultElem;
}
return _oldjQueryData.call(this, key);
}
Load this piece of Javascript after jQuery and before you own code.
It should work.
Note that this prevents objects from being garbage collected, therefore it has memory impact.

IE9 Compatibility Mode Error: Unable to get value of the property '0': object is null or undefined

I am trying to get the children of a <tr> element in a table. I need to get each of the individual <td> cells. I cannot use jQuery, only JavaScript for infrastructure reasons. My JavaScript looks like this:
var feeTable = document.getElementById("feeTable");
function gatherRowData() {
console.log("gathering row data");
var rows = this.parentNode.children; //This is where it fails.
var state = rows[0].innerText;
var county = rows[1].innerText;
var city = rows[2].innerText;
console.log("state: " + state);
document.getElementById("state_code").value = state;
document.getElementById("county_name").value = county;
document.getElementById("city_name").value = city;
}
//Loop through Vehicle Fee Changes to find any empty cells in county, city, or start date.
for (var i = 0; row = feeTable.rows[i]; i++) {
var county = row.cells[1];
var city = row.cells[2];
var startDate = row.cells[6];
if (county.innerText == "") {
county.style.backgroundColor = "#FF0000";
showError(invalidCells);
}
if (city.innerText == "") {
city.style.backgroundColor = "#FF0000";
showError(invalidCells);
}
if (startDate.innerText == "") {
startDate.style.backgroundColor = "#FF0000";
showError(invalidCells);
}
if (document.addEventListener) {
row.cells[8].addEventListener("click", gatherRowData);
} else if (document.attachEvent) { //Support for IE
row.cells[8].attachEvent("onclick", gatherRowData);
}
}
The onClick listeners work just fine, but when I try to get the children of the table row, it gives me the error: Error message: Unable to get value of the property '0': object is null or undefined It works fine in all other browsers, and IE9 without compatibility mode on (it is required to function with compatibility mode). What am I missing that would allow me to get the children of the tr element?
This error may occur when the feeTable has null value
var feeTable = document.getElementById("feeTable");
Try writing values of feeTable in console, and check it has proper value other than null.
I found a solution to my problem. It turns out that when you use attachEvent to attach an event listener, the reference to this in the JavaScript event handler function doesn't actually reference the object that is being clicked on. It represents the Window object as a whole. I had to use a slightly less elegant solution:
row.cells[8].onclick = gatherRowData;
This is the only solution that would work for the versions of IE that don't support addEventListener. Using this solution, the rest of my code worked fine and this referenced the <td> element as it was supposed to.

Javascript Invalid left-hand side in assignment

In an attempt to add queue type functionality to nodejs's Buffer class, I have constructed the following function:
Buffer.prototype.popleft = function(n) {
tRet = this.slice(0,n);
this = this.slice(n,this.length-1); // error here
return tRet;
};
however, this code yields the following error:
"ReferenceError: Invalid left-hand side in assignment"
I know that the issue is with the assignment of 'this' within the function, what I dont know is better way of accomplishing this same type of logic.
EDIT:
Ended up writing an object around the Buffer as shown below:
sPort.vBuffer = {}
sPort.vBuffer.buff = new Buffer(0);
sPort.vBuffer.off = 0;
sPort.vBuffer.expect = -1;
sPort.vBuffer.ReadChr = function() {
this.off ++;
return this.buff[this.off - 1];
};
sPort.vBuffer.ReadUInt32LE = function() {
this.off += 4;
return this.buff.readUInt32LE(this.off - 4);
}
sPort.vBuffer.ReadInt32LE = function() {
this.off += 4;
return this.buff.readInt32LE(this.off - 4);
}
sPort.vBuffer.Write = function(aData) {
this.buff = Buffer.concat([this.buff.slice(this.off),aData])
this.off = 0;
};
You can't assign to this. You can assign to a copy of it, but in your case it looks like that won't do any good.
According to the Node documentation, Buffer instances cannot be resized. Now, whether that's because Node simply provides no APIs to do that, or because of some set of internal implementation assumptions/dependencies, I don't know. There sure doesn't look like any way to alter the length of a Buffer instance.
You could use .copy to shift the contents, and then fill the last position(s) with some dummy value (null or undefined I guess).

JavaScript/jQuery equivalent of LINQ Any()

Is there an equivalent of IEnumerable.Any(Predicate<T>) in JavaScript or jQuery?
I am validating a list of items, and want to break early if error is detected. I could do it using $.each, but I need to use an external flag to see if the item was actually found:
var found = false;
$.each(array, function(i) {
if (notValid(array[i])) {
found = true;
}
return !found;
});
What would be a better way? I don't like using plain for with JavaScript arrays because it iterates over all of its members, not just values.
These days you could actually use Array.prototype.some (specced in ES5) to get the same effect:
array.some(function(item) {
return notValid(item);
});
You could use variant of jQuery is function which accepts a predicate:
$(array).is(function(index) {
return notValid(this);
});
Xion's answer is correct. To expand upon his answer:
jQuery's .is(function) has the same behavior as .NET's IEnumerable.Any(Predicate<T>).
From http://docs.jquery.com/is:
Checks the current selection against an expression and returns true, if at least one element of the selection fits the given expression.
You should use an ordinary for loop (not for ... in), which will only loop through array elements.
You might use array.filter (IE 9+ see link below for more detail)
[].filter(function(){ return true|false ;}).length > 0;
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter
I would suggest that you try the JavaScript for in loop. However, be aware that the syntax is quite different than what you get with a .net IEnumerable. Here is a small illustrative code sample.
var names = ['Alice','Bob','Charlie','David'];
for (x in names)
{
var name = names[x];
alert('Hello, ' + name);
}
var cards = { HoleCard: 'Ace of Spades', VisibleCard='Five of Hearts' };
for (x in cards)
{
var position = x;
var card = card[x];
alert('I have a card: ' + position + ': ' + card);
}
I suggest you to use the $.grep() method. It's very close to IEnumerable.Any(Predicate<T>):
$.grep(array, function(n, i) {
return (n == 5);
});
Here a working sample to you: http://jsfiddle.net/ErickPetru/BYjcu/.
2021 Update
This answer was posted more than 10 years ago, so it's important to highlight that:
When it was published, it was a solution that made total sense, since there was nothing native to JavaScript to solve this problem with a single function call at that time;
The original question has the jQuery tag, so a jQuery-based answer is not only expected, it's a must. Down voting because of that doesn't makes sense at all.
JavaScript world evolved a lot since then, so if you aren't stuck with jQuery, please use a more updated solution! This one is here for historical purposes, and to be kept as reference for old needs that maybe someone still find useful when working with legacy code.
Necromancing.
If you cannot use array.some, you can create your own function in TypeScript:
interface selectorCallback_t<TSource>
{
(item: TSource): boolean;
}
function Any<TSource>(source: TSource[], predicate: selectorCallback_t<TSource> )
{
if (source == null)
throw new Error("ArgumentNullException: source");
if (predicate == null)
throw new Error("ArgumentNullException: predicate");
for (let i = 0; i < source.length; ++i)
{
if (predicate(source[i]))
return true;
}
return false;
} // End Function Any
Which transpiles down to
function Any(source, predicate)
{
if (source == null)
throw new Error("ArgumentNullException: source");
if (predicate == null)
throw new Error("ArgumentNullException: predicate");
for (var i = 0; i < source.length; ++i)
{
if (predicate(source[i]))
return true;
}
return false;
}
Usage:
var names = ['Alice','Bob','Charlie','David'];
Any(names, x => x === 'Alice');

Javascript: Seemingly valid code causing Uncaught Error: NOT_SUPPORTED_ERR: DOM Exception 9 on line 3

var returned = values.make(function (value, index) {
return items[index].value = value;
});
I have the above snippet.
Values is an array of values to be assigned to different elements.
Make is essentially the equivalent of Array.prototype.map.
Array.prototype.make = function (loop, playground) {
var loop = loop || function (value) { return value },
playground = playground || this;
if (loop.Type !== "Function") throw "Loop [0] is not a function.";
var returned = [];
for (var i = 0; i < this.length; i++)
returned[i] = loop.apply(playground, [this[i], i, this]);
return returned;
};
Also, I have Function.prototype.Type = "Function"; in the same file, so it's not .Type throwing an error. .Type works perfectly.
Along with Function, these also have .Type's.
Object.prototype.Type = "Object";
Array.prototype.Type = "Array";
RegExp.prototype.Type = "RegExp";
String.prototype.Type = "String";
Number.prototype.Type = "Number";
Boolean.prototype.Type = "Boolean";
XMLHttpRequest.prototype.Type = "XMLHttpRequest";
Date.prototype.Type = "Date";
Items is the array of different elements.
[<input type="text" />, <input type="text" />, <input type="text" />]
I keep getting this error.
Uncaught Error: NOT_SUPPORTED_ERR: DOM Exception 9 on line 3
I get that error and it doesn't make any sense, because there isn't any code on that line.
I'm at a total loss.
Does anyone notice anything wrong with that code?
Update: I don't know what happened, but I fixed it.
Since no one gave the correct answer, I'll just give it to the only guy who tried.
*clap clap clap*
Can you post a small example that reproduces this error?
Other than that, there are a few errors in your Javascript:
I added a semicolon here:
var loop = loop || function (value) { return value; },
playground = playground || this;
Although semicolons are not necessary, I like to use them because otherwise you can be bitten by subtle errors.
And, you need to use typeof not .Type:
if (typeof loop !== "function") throw "Loop [0] is not a function.";
Also, if items is just an array of strings as you have, then items[index].value doesn't make sense, since strings don't have a value property. This part looks particularly suspicious to me. Although I didn't get the same error you did when I left that bit in, I think it would merit closer examination.
You mentioned that you're using a 3rd-party library so the part about typeof doesn't matter. You also mentioned that you were using actual input elements in your array so the second part doesn't matter either.
I tried out your code again, this time creating input elements with document.createElement:
Array.prototype.make = function (loop, playground) {
var loop = loop || function (value) { return value; },
playground = playground || this;
if (typeof loop !== "function") throw "Loop [0] is not a function.";
var returned = [];
for (var i = 0; i < this.length; i++)
returned[i] = loop.apply(playground, [this[i], i, this]);
return returned;
};
var items = [];
items.push(document.createElement("INPUT"));
items.push(document.createElement("INPUT"));
items.push(document.createElement("INPUT"));
var values = [4, 5, 6];
var returned = values.make(function (value, index) {
return items[index].value = value;
});
console.log(items[0].value, items[1].value, items[2].value);
//firebug shows: 4 5 6
So it appears that your code is working by itself. Can you try this code out by itself on a fresh page? That way you can verify if it is something on the original page that is interacting with your code and causing this error.
I was having the same issue in a different scenario, but using the latest version of Prototype (1.7 instead of 1.5) fixed it.

Categories