I've been trying to create an auto complete function for text boxes wherein the user enters the first few characters and the system shows them a list of entries that begin with the user's given input. These entries are fetched from the database and displayed in the UI through javascript. It all works perfectly except in good ol' Internet Explorer where the style sheet properties don't work on the p elements created by javascript. Could anyone please tell me what I'm doing wrong here? Here is the code I'm using
HTML/JSP
<table>
<tr>
<td nowrap>WO Number</td>
<td style="text-align:left;">
<html:text property="won" styleClass="epntextBox" onkeyup="autokom();" styleId="won"/>
<div id="wondiv"></div>
</td>
</tr>
</table>
Javascript (This is some long code. It works fine though...)
function autokom(){
var number = document.getElementById("won").value;
var url = "Fetch_Won?wonnum="+number;
while(document.getElementById("wondiv").hasChildNodes()){
document.getElementById("wondiv").removeChild(document.getElementById("wondiv").childNodes[0]);
}
if(number=="" || number==null){
return false;
}
if(window.XMLHttpRequest)
{
req = new XMLHttpRequest();
try
{
req.open("GET",url,true);
}
catch(e)
{
alert(e);
}
req.onreadystatechange = processfetchWON;
req.send(null);
}
else if(window.ActiveXObject)
{
req = new ActiveXObject("Microsoft.XMLHTTP");
if (req)
{
req.open("GET", url, true);
req.onreadystatechange = processfetchWON;
req.send(null);
}
}
}
function processfetchWON(){
if (req.readyState == 4)
{
if (req.status == 200)
{
try{
var responseXML = req.responseXML;
var parents = responseXML.getElementsByTagName("won");
var won;
var wondiv = document.getElementById("wondiv");
var num = 0;
if(parents.length>=15){
num = 15;
}else {num = parents.length;}
for (var loop = 0; loop < num; loop++)
{
won = parents[loop].childNodes[0].nodeValue;
var p = document.createElement("p");
p.setAttribute("class", "wonp");
p.setAttribute("id", won);
p.onclick = function() { setwon(this.id); };
p.innerHTML = won;
wondiv.appendChild(p);
}
}catch(e){
alert("Exception in fetching WON/ SWON numbers");
}
}
}
}
function setwon(swon){
document.getElementById("won").value=swon;
while(document.getElementById("wondiv").hasChildNodes()){
document.getElementById("wondiv").removeChild(document.getElementById("wondiv").childNodes[0]);
}
}
CSS
#wondiv{ /*This part works just fine*/
position: absolute;z-index:2;
}
.wonp{ /*But the following doesn't*/
display:block;
margin:0px;
padding:4px;
border:1px inset #000000;
cursor: pointer;
background: white;
width:123px;
}
.wonp:hover{
background: #cbcbcb;
}
I haven't had any problems with the javascript code but the style sheet not being applied to the dropdown by IE(8 - 11) is driving me nuts! Someone please help. I'm at the end of my wits here. (The same css works fine for elements that haven't been js created)
Change
p.setAttribute("class", "wonp");
to
p.className = "wonp";
Some versions of IE have a bug in that they expect you to use "className" with setAttribute, even though the attribute's name is class, not className. But all versions of IE and other browsers use className for the reflected property name, so the change above will solve the problem.
It's rare to actually need to use setAttribute. Virtually all of the attributes you might set (with the obvious exception of data-* attributes) have reflected properties on the element instance that are more useful. class and for (as in, on label elements) have slightly odd names (className and htmlFor) because class and for are reserved words in JavaScript and when this was being defined, JavaScript didn't let you use reserved words as property name literals (it does now), but most other reflected properties have the same name as the attribute they reflect:
element.setAttribute("class", x) => element.className = x
labelElement.setAttribute("for", x) => labelElement.htmlFor = x
element.setAttribute("id", x) => element.id = x
formElement.setAttribute("target", x) => formElement.target = x
linkElement.setAttribute("rel", x) => linkElement.rel = x
element.setAttribute("src", x) => element.src = x (script, img, ...)
Sometimes there are slight differences. For instance, element.getAttribute("href") will give you the actual text of the href attribute, but element.href will give you the resolved version (e.g., relative paths expanded to full ones). Similarly, the value property of input elements is only initialized from the "value" attribute, after which it takes on a life of its own (usually, but not always, reflected as defaultValue).
Related
My goal is to have a button (controlled by a javascript function) that would toggle the entire CSS on the website on and off. I thought this was a common practice and was surprised when I couldn't find a complete solution here or on the web.
Here is what I got.
$("#button").click(function() {
var css = (document.styleSheets[0].enabled = true);
if (css == true)
{
document.styleSheets[0].disabled = true;
css = (document.styleSheets[0].enabled = false);
}
else if (css == false)
{
document.styleSheets[0].disabled = false;
}
});
A simple Jquery function that targets the button by ID and performs an if test. I could've ommited the variable, but this way I am able to check the value easily in console.log. I am able to turn the CSS off, but not back on. The program doesn't even get to the else condition.
I am aware that the else if is not really appropriate, but with just else (and even just with another if condition) the function doesn't run at all.
Second option that I thought of, and which might be much easier is just dynamically changing the contents of the link href attribute, where the path to the css file is given.
But I am struggling to target the href element with Javascript.
This is a simple Boolean toggle so write it as a simple toggle
$("#button").click(function() {
var sheet = document.styleSheets[0];
sheet.disabled = !sheet.disabled;
});
As for why your code isn't working as is,
var css = (document.styleSheets[0].enabled = true);
// same as
var css;
document.styleSheets[0].enabled = true;
css = true;
which means
if (css == true)
// same as
if (true == true)
which always holds so you'll always follow this code path
Well, for one you need to loop through all of the stylesheets.
Also, you can save some lines of code by using a counter, then on each button click increment the counter and use the % modulo operator to turn that into a 1 or a 0, which you can then coerce a boolean from using !!.
var count = 0;
var sheets = document.styleSheets;
$("#button").click(function() {
for(var i in Object.keys(sheets)) sheets[i].disabled = !!(++count % 2);
});
.demo {
background: #888;
color: blue;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="demo">Some Text</div>
<button id="button">Click It</button>
Your problem is that you are doing an assignment when you should be doing an equality check.
You have
var css = (document.styleSheets[0].enabled = true);
But you are really trying to do an equality check, i.e.,
var css = (document.styleSheets[0].enabled == true);
Notice the extra =. The single = does an assignment, so your current code is equivalent to this:
document.styleSheets[0].enabled = true
var css = document.styleSheets[0].enabled; // i.e., true
Because you set enabled to true, your if (css == true) condition is always satisfied, so your code always turns the CSS off and never turns it back on.
The fix, as Paul S. wrote in his answer, is just to toggle the value of document.styleSheets[0].disabled, as in:
$("#button").click(function() {
document.styleSheets[0].disabled = !document.styleSheets[0].disabled;
});
There's no need to set and track a new property enabled.
The issue seems to be that you are doing assignment, and not comparison, on this line:
var css = (document.styleSheets[0].enabled = true);
It should be
var css = (document.styleSheets[0].enabled == true);
Probably simpler, since you have a jquery tag on the question, to just do:
$stylesheets = $('link[rel="stylesheet"]');
$("#button").click(function() {
$stylesheets.attr('disabled', !$stylesheets.attr('disabled'));
});
If you want to modify every href in your DOM,
just use
$('a[href*=]').each(function () {
var $this = $(this);
$this.attr('href', $this.attr('href').replace();
});
I'm generating a 'select' element then populating it with options and inserting it into the DOM of my page. Everything's fine in FF, Chrome, Chromium etc. but in IE no options show in the drop-down list but highlights show under the cursor and when I click in the blank list the event handler gets triggered and processes correctly.
Here's the relevant HTML area:
<span id="spn_fyear" style="position:absolute; top:7px; left:200px; height:24px; cursor:pointer; color:#000000;" onclick="spn_fyear_onclick(this)">
<span id="spn_fyearno" style="position:absolute; top:0px; font:italic bold 17px sans-serif; color:#FFFEF2;"><?=$thisPage->getVar('start_year')?></span>
</span>
and here's the javascript in question:
function spn_fyear_onclick(_obj)
{
//make start year list
var lstto = document.getElementById('lst_year');
var topts = new Array();
var nopt = null;
for(i=0; i<lstto.options.length; i++)
{
topts[i] = lstto.options[i].text;
}
var lstf = document.createElement('SELECT');
lstf.id = "lst_fyear";
lstf.style.position = "absolute";
lstf.style.top = "-3px";
lstf.style.left = "1px";
lstf.style.fontFamily = "sans-serif";
lstf.style.fontWeight = "normal";
lstf.style.fontSize = "12px ";
lstf.style.width = "55px";
lstf.style.color = "#000000";
lstf.style.display = "inline";
lstf.onchange = lst_fyear_onchange;
for(i = 0; i < topts.length; i++)
{
if(topts[i] != 'undefined')
{
nopt = document.createElement('OPTION');
nopt.text = topts[i];
nopt.value = topts[i];
lstf.appendChild(nopt);
}
}
document.getElementById('spn_fyear').appendChild(lstf);
}
In this line: var lstto = document.getElementById('lst_year')
I'm creating a reference to an existing select object from which I copy the option data. lst_year gets populated by a php database query when the page first loads. I created the array (var topts = new Array()) in desperation in case IE has a quirk which copies attributes and properties but to no avail. Like I said - everything works like a dream in FF or Chrome both in Linux and Windoze but falls in a heap with IE. I've scoured MSDN etc. for some obscure behaviour but I'm stumped. Any suggestions would be greatly appreciated :)
Kind regards,
Jen
Most likely, your problem is here:
nopt = document.createElement('OPTION');
Try this method mentioned here:
JavaScript: add extra attribute after new Option()
(I've had a lot of problem with <option> elements and IE before until I started using the new Option constructor.
I am new to JavaScript and tried putting together an FAQs section that limits the number of shown answers to just 1 at a time. The JavaScript is here (also live at http://indulge.cc/indulge.js). For the whole live site, check out http://www.indulge.cc. You will see in FF, Chrome, Safari, etc. that the FAQs bit works, but doesn't go in IE. Don't know what I missed. Syntax?
function showonlyone(shownanswer)
{
var faqswitcher = document.getElementsByTagName('div');
for (var x=0; x<faqswitcher.length; x++)
{
name = faqswitcher[x].getAttribute('class');
if (name == 'faqswitcher')
{
if (faqswitcher[x].id == shownanswer)
{
if (faqswitcher[x].style.display == 'block')
{
faqswitcher[x].style.display = 'none';
}
else
{
faqswitcher[x].style.display = 'block';
}
}
else
{
faqswitcher[x].style.display = 'none';
}
}
}
}
Get the class attribute by querying the className property, instead of going after the attribute.
name = faqswitcher[x].className;
It works as well in the other browsers, and older IE's require it.
I have another error caused by IE7 (great program...) I am trying to get a dropdownlist into a javascript function so that i can use it's values to hid some divs which are named after those values. but each time I try to use this dropdownlist I get the following error:
runtime-error microsoft jscript: dropdownlist is not defined
the javascript:
<script src="/Scripts/ShowHide.js" type="text/javascript"></script>
function ShowHideDivByDropDownList(dropdownlist) {
for (i = 0; i < dropdownlist.options.lenght; i++) {
var divId = dropdownlist.options[i].value;
if (divId != "") {
document.getElementById(divId).style.display = "none";
}
}
document.getElementById(drowdownlist.value).style.display = "block";
}
the dropdownlist:
#Html.DropDownList("MainList",
new SelectList(Model.ListCategories,
Model.List,
new { onchange ="ShowHideDivByDropDownList(this)"})
EDIT:
I have made allot of trail adjustments to try and make the script running, allot of people seem to have noticed this :). I have returned to script to it's original state, but the error still occurs.
If it's an ID use getElementById(id), if it's a name use getElementsByName(name)[0].
getElementByName doesn't exist.
Also be careful with your variable names...
In your for loop you have drowdownlish instead of drowdownlist. Just for sanity sake you may want to make those dropdownlist.
function ShowHideDivByDropDownList(dropdownlistid) {
var dropdownlist= document.getElementByName(dropdownlistid);
for (i = 0; i < dropdownlist.options.count; i++) {
var divId = dropdownlist.options[i].value;
if (divId != "") {
document.getElementById(divId).style.display = "none";
}
}
document.getElementById(dropdownlist.value).style.display = "block";
}
You can prevent yourself all this mess - as this answer correctly said, you have to use getElementById but if you change your code to this:
onchange ="ShowHideDivByDropDownList(this)"
Then you pass the actual object to the function then you can safely have such code instead:
function ShowHideDivByDropDownList(drowdownlist) {
for (var i = 0; i < drowdownlist.options.length; i++) {
var divId = drowdownlist.options[i].value;
if (divId !== "") {
var element = document.getElementById(divId);
if (element)
element.style.display = "none";
}
}
var element = document.getElementById(drowdownlist.value);
if (element)
element.style.display = "block";
}
Couple of things I fixed along the way as well:
In JavaScript, array length is .length, not .count
In case there's no element with such ID your code would crash - to avoid such mishap it's always good practice to validate you really have such element - you can add alert("element does not exist"); for debug purpose but having the whole code crash because you have typo is not a good thing.
How can I do this?
I tried
$('link[title="mystyle"]').remove();
and although the element is removed, the styles are still applied to the current page (in both Opera and Firefox).
Is there any other way?
To cater for ie you have to set the stylesheet to be disabled as it keeps the css styles in memory so removing the element will not work, it can also cause it to crash in some instances if I remember correctly.
This also works for cross browser.
e.g
document.styleSheets[0].disabled = true;
//so in your case using jquery try
$('link[title=mystyle]')[0].disabled=true;
I managed to do it with:
$('link[title="mystyle"]').attr('disabled', 'disabled');
it seems this is the only way to remove the styles from memory.
then I added:
$('link[title="mystyle"]').remove();
to remove the element too.
To disable your selected stylesheet:
$('link[title="mystyle"]').prop('disabled', true);
If you never want that stylesheet to be applied again, you can then .remove() it. But don’t do that if you want to be able to re-enable it later.
To re-enable the stylesheet, do this (as long as you didn’t remove the stylesheet’s element):
$('link[title="mystyle"]').prop('disabled', false);
In the code above, it is important to use .prop, not .attr. If you use .attr, the code will work in some browsers, but not Firefox. This is because, according to MDN, disabled is a property of the HTMLLinkElement DOM object, but not an attribute of the link HTML element. Using disabled as an HTML attribute is nonstandard.
no jQuery solution
if you can add id to your link tag
<link rel="stylesheet" href="css/animations.css" id="styles-animations">
document.getElementById("styles-animations").disabled = true;
if you know index position of your css file in document
document.styleSheets[0].disabled = true; // first
document.styleSheets[document.styleSheets.length - 1].disabled = true; // last
if you want to disable style by name you can use this function
/**
* #param [string] [styleName] [filename with suffix e.g. "style.css"]
* #param [boolean] [disabled] [true disables style]
*/
var disableStyle = function(styleName, disabled) {
var styles = document.styleSheets;
var href = "";
for (var i = 0; i < styles.length; i++) {
href = styles[i].href.split("/");
href = href[href.length - 1];
if (href === styleName) {
styles[i].disabled = disabled;
break;
}
}
};
note: make sure style file name is unique so you don't have "dir1/style.css" and "dir2/style.css". In that case it would disable only first style.
Using pure javascript:
var stylesheet = document.getElementById('stylesheetID');
stylesheet.parentNode.removeChild(stylesheet);
To remove a stylesheet:
$('link[src="<path>"]').remove();
To Replace a stylesheet:
$('link[src="<path>"]').attr('src','<NEW_FILE_PATH>');
If you want to do it only with the href attribute:
$('link[href="https://example.com/mycss.css"]').remove()
ES6 solution:
const disableStyle = styleName => {
const styles = document.styleSheets;
let href = "";
for (let i = 0; i < styles.length; i++) {
if (!styles[i].href) {
continue;
}
href = styles[i].href.split("/");
href = href[href.length - 1];
if (href === styleName) {
styles[i].disabled = true;
break;
}
}
};
Use it like disableStyle("MyUnwantedFile.css");.
Here's both an add & remove using the disabling principle mentioned in a number of these other posts to prevent cross browser issues. Note how my add checks to see if the sheet already exists, in which case it just enables it. Also, in contrast to some answers, this is designed to work using the url to a .css file as the sole argument to the functions (insulating the client from the use of id or title attributes).
function element( id ){ return document.getElementById( id ); }
function addStyleSheet( url ){
var id = _styleSheetUrlToId( url );
if( !_enableStyleSheet( id ) ) {
var link = document.createElement("link");
link.href = url;
link.type = "text/css";
link.rel = "stylesheet";
link.id = id;
document.getElementsByTagName("head")[0].appendChild( link );
}
}
function removeStyleSheet( url )
{ _enableStyleSheet( _styleSheetUrlToId( url ), false ); }
// "protected" function
function _styleSheetUrlToId( url ){
var urlParts = url.split("/");
return urlParts[urlParts.length-1].split(".")[0]
+ "-style";
}
// "protected" function
// returns if the sheet was found
function _enableStyleSheet( id, enable ) {
if( typeof(enable) == "undefined" ) enable = true;
var sheet = element( id );
if( sheet ) {
sheet.disabled = !enable;
return true;
}
return false;
}