jQuery(formElement).val(null) : inconsistent results in different browsers - javascript

The code is here:
http://jsfiddle.net/jf7t2/1/
Please run it on the latest versions of all browsers, and see for yourself. When the button is clicked, on:
on Chrome (and Safari of course) it just doesn't select anything, instead creates some ghostly empty option
on Firefox and Opera, it works the way I expect and want it to work, de-selects all options
on Internet Explorer, it does nothing
So, which one is the expected behaviour?

If you look at the jQuery 1.5.1 source code line 1970 you'll see this:
// Treat null/undefined as ""; convert numbers to string
if ( val == null ) {
val = "";
So the expected behavior is the same as if you gave the empty string as argument.
If you continue to line 1984 you'll see this:
} else if ( jQuery.nodeName( this, "select" ) ) {
var values = jQuery.makeArray(val);
jQuery( "option", this ).each(function() {
this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0;
});
if ( !values.length ) {
this.selectedIndex = -1;
}
So the expected behaviour is:
if there is an option with an empty string value, choose that.
if not set selectedIndex = -1
From here on it is up to the browser to determine what to do if selectedIndex is set to -1
Looking at the msdn library it says:
The selectedIndex property returns -1
if a select object does not contain
any selected items. Setting the
selectedIndex property clears any
existing selected items.
So in ie the expected behavior seems to be that it will de-select all options
The same goes for the MDC documentation and thus firefox, where theya re very explicit about it
Returns the index of the currently
selected item. You may select an item
by assigning its index to this
property. By assigning -1 to this
property, all items will be
deselected.
It seems webkit based browsers have a different take on things.
If you google "webkit selectedIndex" you will see quite a few bug report regarding the select tag, so maybe it's just funky ;)
Come to think of it, this is a bug in jQuery since it is a library that should be able to behave the same across browsers - it should be reported ;)

which one is expected behaviour?
jQuery's val() function is documented to take a string value or an array of string values, so there is no defined behaviour.
Try val([]) to select nothing, or to restore the original value use the defaultSelected property:
$('#select option').each(function() {
this.selected= this.defaultSelected;
});

I forked your jsfiddle with one that I think can help you:
http://jsfiddle.net/marcosfromero/AYLrT/
I tested it in IE, Firefox and Chrome
jQuery("#button").click(function(event){
var select = jQuery("#select");
// Button click will try to find a "none" option (with no value)
if(select.find('option.none').length===0) {
// If it's not found, it creates the option
select.prepend('<option value="" class="none"></option>');
}
// And then it selects it
select.val('');
});
// When select value is changed...
jQuery('#select').change(function() {
var me = $(this);
// ... to something different than empty ("")...
if(me.val() !== '') {
//... it removes that option
me.find('option.none').remove();
}
});

None of those behaviors are unreasonable.
In Chrome, it makes sense because you are setting the value to nothing, so it displays nothing.
In IE, it makes sense because you are not changing to a valid value, so it changes nothing.
If you want all the browsers to behave like Firefox, just set the value to 1.

Related

Array.from() with HTMLcollection does not seem to work in Chrome browser

I have a JavaScript piece of code that works on all browsers (even IE) but fail with Chrome on my HUAWEI P8 Lite with Android 6.
Chrome is version 71.0.3578.99.
The faulty code is var class_arr = Array.from(class); where class is a HTMLcollection.
It seems like Array.from() is failing although it should be supported by Chrome on mobile.
Also, I've noticed that this same code used to work one update ago, and not two updates ago strangely.
You can test the problem with this URL (of course this won't be valid as long as if I'll find a solution to my problem). You need to open the sidebar on the left and try to zoom in the map with the Plus or Minus button.
EDIT
Here is the code where I use Array.from():
export function updateSlider(all_sliders, ol_layers, class_layers) {
// updates slider with the actual opacity of the layers
for (var i = 0, len_i = all_sliders.length; i < len_i; ++i) {
var curr_slider = all_sliders[i];
// get layer from ol_layers whose title is equal to current slider id
// Find the value of the first element/object in the array, otherwise undefined is returned
// (https://stackoverflow.com/a/13964186/1979665)
var lyr = ol_layers.find(obj => {
return obj.values_["title"] === curr_slider.getAttribute("id")
});
// get class_layer (layerswitcher) from class_layers whose title is equal to current slider id
// (first we need to convert class_layers from HTMLCollection to array otherwise .find will fail)
var class_layers_arr = Array.from(class_layers);
var class_elem = class_layers_arr.find(obj => {
return obj.innerText.replace('\t','') === curr_slider.getAttribute("id")
});
// get current layer opacity and set it as the value of current slider
var curr_opacity = lyr.values_["opacity"];
curr_slider.setAttribute("value", curr_opacity);
// create new li element
var li_elem = document.createElement("LI");
// add slider input to li elem
li_elem.appendChild(curr_slider);
// add li with layer legend after layer li
insertAfter(li_elem, class_elem);
changeOpacity(curr_slider, ol_layers);
}
}
class_layers is first defined in another script as var class_layers = document.getElementsByClassName("layer");
EDIT 2
Ok, so apparently the problem is related to Chrome in general, not only on mobile. In fact, if you try the above URL in Chrome Desktop, you can reproduce the error by opening the sidebar (on the left), then closing it and pressing the + or - symbol to zoom in the map. I guess it has to do with the way click events are treated by either my code and OpenLayers. I am probably deleting this question as it sounds like I need to dig further in problematic.
SOLUTION
Not deleting because I think it maybe useful for others to see the solution.
Here is the link to the OpenLayers github issue I created and closed: https://github.com/openlayers/openlayers/issues/9105.
The problem was the event "change:resolution" fired by the View class of OL (v5.3.0) that is emitted multiple times during animation (problem also quoted here).
NEW CONSIDERATION
Turns out that I still had the problem on mobile devices.
The real fix was not to use innerText in my code and switch to innerHTML, as it was always empty in (and only in) Chrome, while with the other browsers it was not (I could actually see the string). If you are interested I can try to provide an example, but unfortunately I could not find much on this problem in the web...
It's not Array.from() problem.
Check your class_elem variable
It's undefined (because no element found for your conditions) and then it fails when your trying to get parentNode of undefined in:
export function insertAfter(newNode, referenceNode) {
referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
}

For loop index undefined in IE9 for initial pass

On this page: http://koncordia.marketingassociates.com/19892arc/
I have a slideshow that I created custom prev/next links for. Each selection you make on the page advances it one slide forward. The progress bar at the top allows you to click a previous slide, and jump more than one back if you want (you can go from step 4 or step 1 for example).
This multi-step jump works fine in all the current major browsers, but the client uses IE9, and this is where I do not understand the source of the issue.
The following are the relevant methods in this issue. To mimic a user jumping back one or more slides I have a for loop iterate over simulatePrevClick() as many times as necessary; it's not sexy but it works.
The issue arises on the initial pass in IE9. The console spits out "undefined" for the first pass, but it says 0 for all other browsers (including IE 10 and 11) which is correct. If I remove the method call within the loop the iteration works perfectly, so it has something to do with the .click() event or way the method is called, but I don't know what.
No matter what, IE9 will show the immediate previous slide no matter how many they click back; the progress bar be out of sync if they click back more than one in this instance. The undefined result is not showing as an error, either.
//Highlight the right number of progress buttons
highlightProgressBar: function( slideNumber ) {
$(".btn-progress").attr('disabled', 'disabled').removeClass('active'); //Disabled all
$("#progress-wrapper a:lt(" + slideNumber + ")").removeAttr('disabled'); //Disable select number
$("#progress-wrapper a:eq(" + (slideNumber - 1) + ")").addClass('active'); //Add active to the specified button clicked
},
simulateNextClick: function () {
//The value of this must match what the responsiveslides function creates for the prev/next buttons (seen when you inspect element)
$(".transparent-btns_nav.transparent-btns1_nav.next").click();
},
simulatePrevClick: function () {
//The value of this must match what the responsiveslides function creates for the prev/next buttons (seen when you inspect element)
$(".transparent-btns_nav.transparent-btns1_nav.prev").click();
},
toggleProgressBar: function( clickedSlideNumber, activeSlideNumber ) {
var numSlides = activeSlideNumber - clickedSlideNumber;
for (var i=0; i < numSlides; i++) { //Anticipate user may click more than one step back
this.simulatePrevClick();
console.log(i); // **shows "undefined" on first pass in IE9 only**
}
this.highlightProgressBar(clickedSlideNumber);
}
Try to move the var i = 0 declaration out of the loop.
var i = 0;
for (; i < numSlides; i++) {}
It's really strange that that should happen.
This is just a guess, but I looked through the rest of your source code, and its possible that the root of your problem could be due to whenever you actually implement your toggleProgressBar function, in this area:
$(".btn-progress").click(function() {
var currentSlideID = $("#progress-wrapper").find('a.active').attr('id').split("-");
var clickedSlideID = $(this).attr('id').split("-");
slideFn.toggleProgressBar( clickedSlideID[1], currentSlideID[1] );
});
If I see right, your toggleProgressBar wants to accepts two numbers. However, what you're passing in are string literals:
slideFn.toggleProgressBar( "2", "1" );
ID attributes are output as strings, not numbers. I just tested the following in Chrome, and it worked:
"2" - "1" === 1 //true
This is because I guess V8 (Chrome's JS engine) coerces the two string literals into numbers. However, (while I have not tested it), this tells me that it's possible that IE might not be coercing the two strings into numbers (like I said, I don't know this for a fact, but this is something you might try debugging). Try this and see if it has any effect:
//first option
slideFn.toggleProgressBar( +clickedSlideID[1], +currentSlideID[1] );
//the + sign will typecast your strings into numbers
//second option
slideFn.toggleProgressBar( parseInt(clickedSlideID[1]), parseInt(currentSlideID[1]) );
However, in my experience, parseInt runs a little bit slower than using + to typecast the strings into numbers.
IE uses the Chakra JS engine, which I believe follows the standards of ECMAScript 3, which is from 1999. I haven't read through the standard, but it's worth considering the possibility that it has something to do with the issue.
Edit
Here's your problem:
$("#progress-wrapper").find('a.active') ==> []
The first time, there are no a.active elements. Thus, whenever you try to call split on an empty array, it throws a TypeError.
You need to give your first .btn-progress the class active, because the first time around, your first .btn-progress looks like this:
1
There's no active class. Only subsequent .btn-progress elements receive the class active whenever you click the .btn-continue. Your first one never does. Therefore, clickedSlideID[1] and currentSlideID[1] are undefined the first go around. It probably breaks in IE9 because IE9 doesn't understand i < undefined, but it's possible that other more modern browsers go ahead and execute anyway.
Somewhere in the beginning of your code, then, you need to do something like this:
$('.btn-progress').eq(0).addClass('active');
I just tried this in the console on your page, and it worked just fine. After I added the class active to the fist .btn-progress, currentSlideID[1] was now 1, and not undefined.

How do you programmatically clear HTML5 date fields?

I'm looking for a way to programmatically clear HTML5 date fields with Javascript (specifically jQuery). So far I have tried two methods which I thought obvious:
$('input[type=date]').val('');
$('input[type=date]').val('0000-00-00');
But neither of them work on the latest version of Chrome for PCs at least, haven't tried them with other browsers or platforms yet. Is there an API call or something that can clear date fields in a cross-browser way? Solutions I have searched for like this require the user to clear the date field whereas I need this to be done programmatically.
$("input[type=date]").val("") works for me in chrome. It sets the input field to dd/mm/yyyy.
Maybe it's browser specific. Most browsers have only partial or no support for this input: http://caniuse.com/input-datetime
If you can't clear a date field, this could also depend on a browser bug.
I spend some time until I found out that you cannot reset the date in Firefox if the date control is disabled.
See: https://bugzilla.mozilla.org/show_bug.cgi?id=1465979
Without the bug, I am able to clear the date like that:
document.getElementById("myDate").value = "";
I needed to do it recently and i've made this little hack... Seems to do the job.
It was just with JavaScript, but the jQuery version is pretty the same...
function reset_date_native() {
var date_input = document.getElementById('date-id');
//erase the input value
date_input.value = '';
//prevent error on older browsers (aka IE8)
if (date_input.type === 'date') {
//update the input content (visually)
date_input.type = 'text';
date_input.type = 'date';
}
}
function reset_date_jquery() {
$('#date-id').val('')
.attr('type', 'text')
.attr('type', 'date');
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input id="date-id" type="date" />
<button onclick="reset_date_native()">Trigger the reset function (native)</button>
<button onclick="reset_date_jquery()">Trigger the reset function (jQuery)</button>
document.getElementById("datePicker").valueAsDate = null;
this line of code works with my browser (chrome) , didn't tested in other browsers
You can change the date as empty
$('#invoiceDate').val(new Date())
You can restore the placeholder;
$('input[type=date]')[0].valueAsDate = '';
this line works with my browser (chrome, latest version)
$('input[type=date]')[0].value = 0;
Can you use the reset function of your form ?
You can do this with reset button :
<button type="reset" value="Reset">Reset</button>
or programmaticaly :
$("#yourFormId").reset();
or
$('input[type=date]').reset();
Use the native defaultValue property:
$('input[type=date]').each( function resetDate(){
this.value = this.defaultValue;
} );
This works as long as the form doesn't have an initial value specified, as demonstrated in this fiddle.
This solution checks if a default value exists and, if so, uses it to reset the input. Otherwise, it clears the input it by updating value and valueAsDate.
Info on valueAsDate available at: w3c.org.
var dateEl = element.find('input#myDateInput[type="date"]');
dateEl[0].value = ('undefined' !== typeof dateEl[0].defaultValue) ? dateEl[0].defaultValue : '';
if (dateEl[0].value !== '') {
dateEl[0].valueAsDate = new Date(dateEl[0].value);
} else {
dateEl[0].valueAsDate = null;
}
I had a similar issue with the value.
I wanted the onchange() function to run when I set the value to empty. Normally, this always works but for date it didn't even if the value appeared to be blanked and you blurred the input
I discovered that I had to force the onchange() function to trigger the value change too.
document.getElementById('mydate').value='';
document.getElementById('mydate').onchange();
It worked for me and now my form fades out when the value is blanked.
I do not know why that works. I tried blur() and focus() but nothing else seems to work.
Set myDate = one space.
I like simple solutions.

ExtJS4 Change TextField emptyText on the Fly

How do I change my textfield's emptyText field on the fly?
I've tried:
myTextField.emptyText = 'new empty text';
myTextField.emptyText = 'new empty text';
myTextField.applyEmptyText();
myTextField.emptyText = ['new empty text'];
myTextField.emptyText = ['new empty text'];
myTextField.applyEmptyText();
I realize that applyEmptyText() is not listed in the API docs but I thought I'd give it a shot as this worked in previous versions. I've also read that one needs to add the brackets too.
I've printed myTextField to the console and I see the emptyText property set to what I want but the field in the browser is not updating.
I love ExtJS and all that it brings to the table but nuances like this (trying to get dynamically updated emptyText to work) really slow down development. None of the other SO posts on this issue have resolved the problem for me (emptyText just wouldn't update).
After several hours "fighting with my tools" and dozens of different permuations I came up with the following simple fix - just add a myTextField.reset(); to your code block.
myTextField.emptyText = 'new empty text';
myTextField.applyEmptyText();
myTextField.reset();
Hope this saved someone else some time.
Your first attempt should work as expected. However, as you can see in the source, there are certain criteria to be met before the placeholder is set. Your best bet is to place a breakpoint in the applyEmptyText function and debug it.
applyEmptyText : function(){
var me = this,
emptyText = me.emptyText,
isEmpty;
if (me.rendered && emptyText) {
isEmpty = me.getRawValue().length < 1 && !me.hasFocus;
if (Ext.supports.Placeholder) {
me.inputEl.dom.placeholder = emptyText;
} else if (isEmpty) {
me.setRawValue(emptyText);
me.valueContainsPlaceholder = true;
}
//all browsers need this because of a styling issue with chrome + placeholders.
//the text isnt vertically aligned when empty (and using the placeholder)
if (isEmpty) {
me.inputEl.addCls(me.emptyCls);
}
me.autoSize();
}
}
Through debugging it seems like the Text.inputEl.dom.placeholder property was not being set during my event in time to update the field. Based on the reset source above, I found that just setting the Text.inputEl.dom.placeholder in my code worked.
This applyEmptyText method is definately buggy!!
Look at the code, and imagine you want to set a zero as emptyText....
Look at the if conditions:
if (me.rendered && emptyText)
when emptyText = 0 , in the condition it will be as a false interpretated..... it's then with this code impossible to set the zero as emptyText!!!!

Works in firefox but not IE8

This is working fine in firefox but only closes the first page and then breaks in IE8. Firebug in IE8 says that x.item(o) is null. I can't figure out why this works in firefox but not IE. Thanks for any help.
pager(x=document.getElementsByName("pg1"));
function pager( x ) {
var curr = document.getElementById('showing');
$(curr).fadeOut('fast');
curr.id = 'hide';
$(x).fadeIn('slow');
x.item(0).id ='showing';
}
if(x.item(0).id = NULL )
That's an assignment. You wanted == for comparison.
(What's NULL in capital letters? An element's id property won't be null; if it's not set, it'll be an empty string.)
It seems to me you'd be better off using jQuery's toggle method.

Categories

Resources