Chrome 57 making .data() not function well - javascript

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.

Related

Setting a Javascript if statement with 2 requirements to one line

var status = result.locations[index].status;
var operator = result.locations[index].operator;
var original = result.locations[index].original;
var produced = result.locations[index].produced;
var href = result.locations[index].more;
I have the above which each need to be an if statement to check if there is content and my output is the below code.
if (result.locations[index] && result.locations[index].status){
var status = result.locations[index].status;
} else {
var status = '';
}
I would need to reproduce this per line from the code at the top of the post. What would be the best method to simplify each down to keep the code neater and not produce 5 lines of if statement when 1 or 2 would do.
var status = (result.locations[index] && result.locations[index].status ? result.locations[index].status : '');
Not sure why you want to, but:
var status = (result.locations[index] && result.locations[index].status) ? result.locations[index].status : ""
Your problem is trying to access a property of a "deep" javascript object using its path.
This is a common question :
Javascript: Get deep value from object by passing path to it as string
Accessing nested JavaScript objects with string key
There is no built-in way to do this in javascript.
There are plenty of libraries to do that, for example, with selectn, this would become something like (I have not tested it, so I don't know if the index part will work, but you get the idea) :
var status = selectn("locations." + index + ".status", result) || ''
If the structure of your objects is always the one above (that is, the property is just at one level of depth), and you're not expecting 'falsy', you could simply write the 'test' function yourself :
function safeGet(instance, propertyName, defaultValue) {
// As pointed by AlexK, this will not work
// if instance[propertyName] can be anything Falsy ("", 0, etc...)
// If it's possible, get a library that will do
// the full series of insane checks for you ;)
if (instance && instance[propertyName)) {
return instance[propertyName];
} else {
return defaultValue;
}
}
var location = result.locations[index]; // Potentially undefined, but safeGet will deal with it
var status = safeGet(location, "status", "");
var operator = safeGet(location, "operator", "DEFAULT_OPERATOR");
...
var status = result.locations[index] && result.locations[index].status || '';
However, better maje sure before, if result.locations[index] exists... else do whatever is to be done in your code..

javascript: not having to use all the IDs in a html file?

I want to use the same .js for a bunch of html pages, but not necessarily all the ID's from this .js in every single page. Right now, if I don't use one ID; no ID's are showing at all.
var yes = 'Yes';
var no = 'No';
var available = 'Available: ';
document.getElementById("001").innerHTML=available+yes;
document.getElementById("002").innerHTML=available+no;
document.getElementById("003").innerHTML=available+yes;
A html with this works fine:
<div id="001"></div>
<div id="002"></div>
<div id="003"></div>
A html with this, not so fine:
<div id="002"></div>
<div id="003"></div>
What to do to make it run even though some ID's arn't being used?
Complete noob to this, there's probably a super simple solution to it(?) - but I can't find it. Hopefully, someone here can help me - without totally bashing me, or telling me how much of a bad praxis this is and that I should rewrite it in some mega haxxor language that I havn't even heard of :D
Thanks in advance!
While I'd question why you'd need incrementing numeric IDs like that, one solution would simply be to keep an map of IDs to values, then iterate the map checking for null.
var m = {
"001":yes,
"002":no,
"003":yes
};
for (var p in m) {
var el = document.getElementById(p);
if (el) // or if (el !== null)
el.innerHTML = available + m[p];
}
The document.getElementById() function returns null if no matching element is found. null.innerHTML is an error that stops the current script executing. So you just have to test for null:
var el = document.getElementById("001");
if (el != null) el.innerHTML = available + yes;
The null test can be simplified to:
if (el) el.innerHTML = available + yes;
If element "001" is always going to be "yes", "002" is always going to be "no" and so forth then you can do this:
var results = {"001" : yes, "002" : no, "003" : yes};
var el, k;
for (k in results) {
el = document.getElementById(k);
if (el) el.innerHTML = available + results[k];
}
wrap it with if(document.getElementById("id")!==null) ?
Just wrap the whole thing in a try statement to avoid any issues and put code afterwards into a finally statement::
try{
document.getElementById("001").innerHTML=available+yes;
document.getElementById("002").innerHTML=available+no;
document.getElementById("003").innerHTML=available+yes;
//etc
}
finally{
//any other code that there is after the id stuff
}
that'll prevent errors, so if something fails, it will still continue

css to json parser freezes the browser-window

I found some days ago a really nice approach to parse css-strings (even nested) to json. However, it seems, that there's somewhere a big problem in it.
https://github.com/csvplot/cml-parse
If we try to parse a css-string, it will kill the browser window, don't know what's going on here... I already opend an issue but there's no one to answer the issue, since the maintainer David Ellis is lost.
Any ideas/suggestions?
function parse(data) {
var stateStack = [];
var scopeStack = [];
var outObj = {};
while(data) {
// Grab current number of indentation characters
/^(\s*)/.test(data);
// If we've entered any state, and that state is not an explicit block declaration ( {}'s ) and we have an indent level smaller than the most recent indent level,
// then remove the most recent scope level and recall the state back to the previous scope's state
if(stateStack.length &&
stateStack[stateStack.length-1] !== 'explicitBlock' &&
scopeStack.length &&
RegExp.$1.length < scopeStack[scopeStack.length-1].indent) {
scopeStack.pop();
while(stateStack.length && (stateStack[stateStack.length-1] !== 'block' || stateStack[stateStack.length-1] !== 'explicitBlock')) {
stateStack.pop();
}
}
// If current chunk is the key to an object
if(/^(\s*)([^:]*)\s*([{\n])/.test(data)) {
// Grab the indent size of the key and the current outObj position from the scope stack
var indentLength = RegExp.$1.length;
var currScope = (scopeStack.length ? scopeStack[scopeStack.length-1].ref : outObj);
// Split the identifier by spaces and construct/traverse down the defined path
// TODO: Figure out how to handle commas that define the same inner content along multiple paths
RegExp.$2.split(/\s*/).forEach(function(scope) {
if(scope !== '') {
currScope[scope] = currScope[scope] || {};
currScope = currScope[scope];
}
});
// Push the deepest scope and the current indent length onto the scope stack, and push the explicitBlock vs block state onto the state stack
// TODO: Work on a state diagram to truly handle all of the possible states involved properly
scopeStack.push({ref: currScope, indent: indentLength});
stateStack.push(RegExp.$3 === '{' ? 'explicitBlock' : 'block');
// Rip out the handled chunk of data from the string
data = data.replace(/^\s*[^:]*\s*[{\n]/, '');
}
}
return data;
}
http://fiddle.jshell.net/5pTBr/
Running the code, it looks like it just does not work.
It reaches an infinite loop since this regex is failing after the first run:
if(/^(\s*)([^:]*)\s*([{\n])/.test(data)) {
Hence why the browser is stuck. It also does not return the correct JSON.
I'd advise on writing something like this by yourself, or trying to debug and fix the existing code.

Grid not rendering in firefox

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.

Mootools 1.3.2 & IE8 Only Error, Object doesn't support property/method

My script is throwing an error only in IE8. I'm using Mootools 1.3.
The error thrown is:
Object doesn't support this property/method.
The IE8 debugger is telling me that the error is this (line with **):
append: function(original){
for (var i = 1, l = arguments.length; i < l; i++){
var extended = arguments[i] || {};
**for (var key in extended) original[key] = extended[key];**
}
return original;
}
The above code is around line 380 in the uncompressed version. It's part of Object.extend.
Now I am suspecting this is happening when I do a each on an array like object. This is the code I'm suspecting is triggering this:
var self = this,
c = certManager.addedCerts,
e = window.expManager.workExp,
cA = this.cA = [],
eA = this.eA = [];
c.each(function(x){
cA.push(x.value);
});
e.each(function(x){
eA.push(x.retrieve('info'));
});
The first array (c) is populated with numbers only. The second one (e) is populated with objects that have a store/retrieve going on.
The array like objects are declared like so:
addedCerts = this.addedCerts = []
workExp = this.workExp = []
in their respective modules (certManager & expManager).
Does anyone has any idea why this is happening?
EDIT:
As requested, here's how workExp is populated:
var r = $('resumeContent'),
h = "<div class=\"contentRowRight\"><a href=\"#\" class=\"xHover remove\" > </a><br/>" + yV + " " + mV + "</div><strong>" + pV + "</strong><br />" + cV,
n = new Element('div', {html: h, 'class': 'contentRow'}).inject(r, 'top');
n.getElement('.remove').addEvents({
'click': function (e) {
e.preventDefault();
self.removeExp(this);
},
'mouseover': function(){
var el = this;
this.store('mO', true);
(function() {
if (el.retrieve('mO')){
el.fieldToolTip('Remove Experience',false,false);
el.store('mO', false);
}
}).delay(500);
},
'mouseout': function(){
this.store('mO', false);
this.removeToolTip();
}
});
n.store('info', {'p': pV, 'c': cV, 'y': yV.replace(' year', '').replace('s', '').replace(' and', ''), 'm': mV.replace('month', '').replace('s', '')});
this.workExp[this.workExp.length] = n;
What I have going on is part of a form. I have a few fields inside a form, you fill them in and then click the Add button and it creates a new 'row'. Those rows contain information about a users work experience. Once the user as added all his work experience, he can keep filling the form. Once the form is all filled out, I iterate over the array object and transform the values into a JSON object which I then put in a hidden value and pass it to the back end.
If you guys want to see the script in action, you can visit http://www.oilforce.com/user-signup.php. You will be forced to fill the first page which is personal info (you can type in garbage, it's not like you're gonna submit it anyways) and then press next 3 times. On the fourth page, the work experience form is there. That's what the code above is doing.
The error was stemming from a field I had in my form. The id of the field was 'position' which apparently clashed with something in ie8. Renamed my field to 'pos' and everything seems to work now.
I'm getting the exact same error.
My code is very simple:
alert(document.id('YouTubeFlashPlayer').get('id'));
However it is run via Element.addEvent() inside a MooTools Class object. The offending method above is
.get()
It's as if IE8 is completely ignoring the MooTools extended methods, since
document.id('YouTubeFlashPlayer')
will in fact alert an HTML object.
I'm almost at the end of my rope with IE8. I'm considering banishing it via
if(Browser.ie8) document.getElement('body').dispose();
ok i was debugging the code a little bit.. and i think your problem is when you try to display the tooltip for the validation message. My guess is that there's a problem with the sound that the tooltip has to play.
My advice would be to change this line:
validateStep: function(x) {
...
// line 6230
this.fields[i].fieldToolTip('Your ' + names[i] + ' should be a minimum of ' + (lengths[i]+1) + ' characters.');
to a simple alert() (or maybe just comment this line) just to see if this is the problem. If this is the problem, you can disable the sound and hopefully you wont have this problem
Good Luck!
If you use compilation for your project you may consider to try at the top of your entry point (file)
import 'core-js'
At the moment core-js polyfill library is the easiest way to make Cross Browser Support

Categories