I'm trying to modify the behavior of some web parts in Sharepoint (thus forcing IE down my throat) for our users who use the Project server pages. I'm not really the best JavaScript guy, and this is driving me nuts.
On one webpart to display the work from Project, there is a subrow 'Planned' shown below the actual data entry row that clutters the view. We want to turn the 'Planned' row off.
I can do it with a simple three liner like this:
<style type="text/css">
.XmlGridPlannedWork {display:none;}
</style>
But the users want to toggle the lines on and off.
So I thought I'd try reading then writting the current CSS value like so:
<script type="text/javascript">
function toggle_PlannedLine()
var ObjPlanned = Document.getElementById("tr").getElementsByTagName("XmlGridPlannedWork");
for(var i=0;i<ObjPlanned.length;i++)
{
if (OjbPlanned[i].display != "none")
{
// toggle the 'Planned' line off
ObjPlanned[i].style.display = "none";
}
else
{
// toggle the 'Planned' line on
ObjPlanned[i].style.display = "inline";
}
}
return;
}
</script>
<button onClick="toggle_PlannedLine();">Toggle Planned Line</button>
The actual segment I'm targeting looks like this:
<tr class="XmlGridPlannedWork" RowID="694810f9-e922-4321-9236-e495dd5048d9B" ID="GridDataRow">
Of course, when you click the button, the rows don't disappear.
At this point, I'm pretty sure I'm missing something obvious, but like I mentioned, I'm no JavaScript guru.
Easiest Solution
Ok, so my answer below should help you out, but here is another way to approach it that is much simpler:
CSS
<style type="text/css">
.XmlGridPlannedWork {display:none;}
body.showPlanned .XmlGridPlannedWork { display: block}
</style>
HTML/JavaScript
<script type="text/javascript">
function toggle_PlannedLine() {
if(document.body.className.match(/\bshowPlanned\b/) > -1)
document.body.className = document.body.className.replace(/\bshowPlanned\b/,'');
else
document.body.className += " showPlanned";
}
</script>
<button onClick="toggle_PlannedLine();">Toggle Planned Line</button>
Original Answer
You were really close in the concepts you wanted, but as the other answers point out a number of things were missing. I rewrote your function to work cross browser, and please ask if you have any questions about it:
<script type="text/javascript">
function toggle_PlannedLine() {
var objs = [];
if( document.querySelector){
objs = document.querySelectorAll('tr.XmlGridPlannedWork');
} else if (document.getElementsByClassName) {
objs = document.getElementsByClassName('XmlGridPlannedWork');
} else {
var temp = document.getElementsByTagName('tr');
for(var j = 0; j < temp.length; j++){
if(temp[j].className.match(/\bXmlGridPlannedWork\b/) > -1){
objs.push(temp[j]);
}
}
}
for(var i=0;i<objs.length;i++)
{
if (objs[i].style.display != "none")
{
// toggle the 'Planned' line off
objs[i].style.display = "none";
}
else
{
// toggle the 'Planned' line on
objs[i].style.display = "inline";
}
}
}
</script>
<button onClick="toggle_PlannedLine();">Toggle Planned Line</button>
For those arguing that jQuery is not a valid answer, please take the following code as an example of why jQuery is so easy to use. All of the previous code is summed up like this:
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/javascript" charset="utf-8">
$(function(){
$('button.toggle').click(function(){
$("tr.XmlGridPlannedWork").toggle();
})
})
</script>
<button class="toggle">Toggle Planned Line</button>
You forgot the opening brace for your function.
You are using getElementByTagName incorrectly. This function gets elements that match based on tag name (a, img, etc.) not CSS class. You can use jquery to accomplish what you want, or you can enumerate through every element on the page until you find the one you want. There are some open-source implementations of this available online. Your best bet, though, would be to add an id to the tag you care about, and then use getElementById.
Finally, Document should be document, and JavaScript is case sensitive.
Hope this helps!
document.getElementsByTagName looks for elements based on the name of their HTML tag, not their class attribute. Newer (not IE) browsers have support for document.getElementsByClassName(), and there are open source functions that do the same thing, falling back on the browser-native versions where available. This function will return a NodeList containing all the elements that use that class, and you can access each element and hide it through that list.
First, document should be lowercase in your var ObjPlanned declaration.
Second, getElementById returns an element based on a unique ID and you're passing it the element, or tag, name. getElementsByTagName returns an array of elements matching a certain tag but you're passing it a className. There is no 'getElementsByClassName' built in to JavaScript, but you can easily use Google to find a solution.
Use jQuery. It provides a very useful $.css() method, which does what you're looking for in a very simple fashion.
Related
I have a problem, I wanted to create a div in html as a container and in javascript create new divs within the container based on a number input from a user prompt.
My html and javascript look like this.
HTML:
<!doctype html>
<html>
<head>
<link rel="stylesheet" href="stylesheet.css">
<title>Sketchpad</title>
</head>
<body>
<button type="button">Reset</button>
<div class= "container">
</div>
<script src="javascript.js"></script>
<script src="jQuery.js"></script>
</body>
JS
var row = prompt("Enter number of rows:");
var column = prompt("Enter number of columns:");
function createGrid(){
var cont = document.getElementsByClassName('container');
for(i=1; i<column; i++){
var sketchSquare = document.createElement('div');
cont.appendChild(sketchSquare);
}
}
createGrid(column);
I end up with this error: Uncaught TypeError: cont.appendChild is not a function.
I imagine this is something to do with the getElementsByClassName?
I do have a solution which involves creating the container div in javascript and appending the smaller squares inside the container div. I was just curious as to why my first soltuion didn't work?
cont[0].appendChild(myDiv) is a function.
When you document.getElements By Class Name as the name implies you are getting many elements (an array of sorts) of elements and this array don't have the same functions as each of its elements.
Like this:
var thinkers = [
{think: function(){console.log('thinking');}
];
thinkers don't have the method .think
but thinkers[0].think() will work.
try this: open your javascript console by right clicking and doing inspect element:
then type:
var blah = document.getElementsByClassName('show-votes');
blah[0].appendChild(document.createElement('div'));
It works!
also if you want to use jQuery which I do see you added...
you can do:
var cont = $('container');
cont.append('<div class="sketchSquare"></div>');
Try that out by doing this:
First get an environment that has jQuery.
Hmm maybe the jQuery docs have jQuery loaded!
They do: http://api.jquery.com/append/.
Open the console there and at the bottom where the console cursor is type:
$('.signature').append('<div style="background: pink; width: 300px; height: 300px"></div>');
You'll notice that you add pink boxes of about 300px^2 to 2 boxes each of which have the "signature" class.
By the way, prompt gives you a string so you'll have to do row = Number(row); or row = parseInt(row, 10); and another thing don't use that global i do for(var i = 0; ...
var cont = document.getElementsByClassName('container');
Because that^ doesn't return a node, it'll return an HTMLCollection.
https://www.w3.org/TR/2011/WD-html5-author-20110705/common-dom-interfaces.html#htmlcollection-0
You need to pick an individual node from that collection before appending.
There could be a couple of issues that could cause this. Without fully giving the answer here's what it could be at a high level.
Your script is ran before the DOM is fully loaded. Make sure that your script is ran after the DOM is present in the page. This can be accomplished using either the DOMReady event ($(document).ready equivalent without jQuery) or simply making sure your script tag is the last element before the closing body tag. (I usually prefer the former)
When you utilize document.getElementsByClassName('container') (https://developer.mozilla.org/en-US/docs/Web/API/Document/getElementsByClassName) this method returns an array therefore you would either need to apply the operation to all elements of the result or just select the zero-th as document.getElementsByClassName('container')[0]. As an alternative, if you would like to be more explicit you could also place an id on the container element instead to more explicitly state which element you would like to retrieve. Then, you would simply use document.getElementById([id]) (https://developer.mozilla.org/en-US/docs/Web/API/Document/getElementById) and this would get back a single element not a collection.
The result of prompt is a string. Therefore you would have to first parse it as an integer with parseInt(result, 10) where 10 is simply the radix or more simply you want a number that is from 0-10.
You should include jquery library before your script, it`s important
<script src="jQuery.js"></script>
<script src="javascript.js"></script>
How can i hide a the text under class named amount using javascript or php?
<span class="amount">$0.00</span>
I tried the following but no luck
<script language="javascript">
$(".amount:has(a:contains('$0.00'))").hide();
</script>
Assuming jQuery based on code in original question.
Your original script was close. All you really need is:
$('.amount:contains($0.00)').hide()
Documentation: https://api.jquery.com/contains-selector/
Bonus
If you can't use jQuery, here's how to do it the old fashioned way.
Array.prototype.forEach.call(document.getElementsByClassName('amount'), function (e) {
if (e.innerText == '$0.00') {
e.style.display = 'none';
}
})
Setting styles is JavaScript isn't too clean, so the better thing to do would be to set a class, with corresponding CSS to hide elements matching that class. For example e.classList.add('hidden'); and .hidden { display: none; }
Documentation: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach (IE 9+)
https://developer.mozilla.org/en-US/docs/Web/API/Element/classList (IE 10+)
Try something like:
<script>
// Assign object
var AmtObj = $(".amount");
// Get contents
var Amount = AmtObj.html();
// If equals '$0.00', hide
if(Amount == '$0.00') {
AmtObj.hide();
}
</script>
try with this code:
var item = $(".amount");
if(item.html() === "$0.00"){
item.hide();
}
Its a lot of trouble for what you want especially if you wanna extract the numbers without the formatting.
If you control the data add a data-value to your attribute and put the raw number their such as <span class="amount" data-value='0.00'>$0.00</span> and then select it and hide it.
$(document).ready(function(){
$(".amount:contains('$0.00')").hide();
});
I'm far from an expert at Javascript, and self taught, and I think this is probably Javascript 101, but I must have missed that lesson.
I've come up with the following code to make 7 rows in a table appear when I click the row in from of them (so every other row). I know it's not neat, but I was quite pleased with myself and it actually worked in the offline preview. However, when I upload my website, all the rows appear by default, and I have to click the rows above to make them disappear. They are supposed to all be hidden by default.
Thanks
This is the code:
<script>
$('.openRow1').click(function(){
$('.hiddenRow1').toggle();
})
</script>
<script>
$('.openRow2').click(function(){
$('.hiddenRow2').toggle();
})
</script>
<script>
$('.openRow3').click(function(){
$('.hiddenRow3').toggle();
})
</script>
<script>
$('.openRow4').click(function(){
$('.hiddenRow4').toggle();
})
</script>
<script>
$('.openRow5').click(function(){
$('.hiddenRow5').toggle();
})
</script>
<script>
$('.openRow6').click(function(){
$('.hiddenRow6').toggle();
})
</script>
<script>
$('.openRow7').click(function(){
$('.hiddenRow7').toggle();
})
</script>
Here is a better way to do this: http://jsfiddle.net/8fwdf/
DOM:
<div class="openRow">Open</div>
<div class="hiddenRow">Hidden</div>
<div class="openRow">Open</div>
<div class="hiddenRow">Hidden</div>
...
JS:
$('.hiddenRow').hide();
$('.openRow').click(function(){
$(this).next('.hiddenRow').toggle();
})
You don't need to make a separate bind for each individual. You can use the jquery selector to select and apply a single bind on all of the elements. I used divs for this example but you can apply the same thing for other element types.
Note that I don't know what your DOM looks like so the $(this).next() part might need to be tweaked. Maybe you can figure that part out, or post your DOM and I can update.
Also, you could do this css and remove the hide() line:
.hiddenRow {
display: none;
}
To make this code more neat you can replace it with:
<script>
for(var i=1; i<=7; i++) {
$('.openRow'+i).click(function(){
$('.hiddenRow'+i).toggle();
});
}
</script>
You can do something like this:
<script>
for(var i=1; i<=7; i++) {
$('.openRow'+i).click(function(){
$('.hiddenRow'+i).toggle();
}).css('visibility', 'hidden'); //this will make them invisible, but
} //the elements will still take up that
//same amount of space. to completely remove
//use *.css('display', 'none');
</script>
A jQuery is a live representation of the data that is in the DOM, so at any time you change a jQuery element, the webpage changes with it.
I got a quick question. If I want to compare a style left / right value with another coordinates (lets say mouse) how do I do it?
Here is what I tried without mouse coordinates but for some reason my condition never executes...
<style>
#container
{
position:absolute;
left:400px;
top:200px;
}
</style>
<script>
function moveExit(){
var containerId = document.getElementById("container").style;
if(containerId.left == 400 + "px")
containerId.left = 395 + "px";
}
</script>
And here is my body:
<body>
<div id="container">
<img
src="Images/image.jpg"
onmouseover="moveExit();"
/>
</div>
</body>
This is my first time playing around with javascript.. Thanks!
you need to use computed style for this purpose.
How do I get a computed style?
var left = window.getComputedStyle(document.getElementById("container")).left
for IE8 you have to use currentStyle proeprty as computed style is not supported.
document.getElementById("container").currentStyle.left
Cross-browser (IE8-) getComputedStyle with Javascript?
Try something like this:
http://jsfiddle.net/xtJA4/
$(document).ready( function() {
$("#container").mouseleave(function() {
if ($(this).css("left")=="400px") {
alert("Left = 400px");
}
});
});
There are of course changes that can be made to this, but for what you're needing this should work fine. You can of course go and change the alert() function to match what you need (modifying the left offset), but hopefully this helps!
While I'm not 100% sure what exactly you are looking to accomplish, here are a few comments, and suggestions for your code.
Rather than user javascript, I would use jQuery. This is something that David has suggested previously. One of the great advantages of jQuery is that it gets around most browser incompatibility issues.
To do this with jQuery you'll need to import jquery, and then you can use it like so:
<script type="text/javascript" src="./jquery/jquery.js"></script>
<script type="text/javascript">
function moveExit(){
var $element = jQuery('#container');
$element.css('left', '350px');
}
</script>
Please also notice that I have added the "type" attribute to the script elements.
As a side-note I would also remind you to add "alt" attributes to img elements. Good for accessibility and for when the images are blocked for whatever reason.
With greater understanding about what you are trying to accomplish a better answer can be provided.
I would like to create a widget that could be placed in another websites/forums.
<script type="text/javascript" src="http://example.com/x.js" />
<div id="myid"></div>
But there is a problem - when someone put on one website two or more such widgets they will not work correctly because of the ID.
What can I do to prevent such situation?
I can't use class because I need to have access to this div from JS.
I thought about adding a random-generated number to the end of ID, but there will be still possibility of ID-collision (small, but there will be).
The best way is to be more flexible. So, instead of having a defined html id and force the user to have it, you should provide a way to let user choose its id. And so, a call must be done.
Something like this is cleaner :
<script type="text/javascript" src="http://example.com/x.js"></script>
<script type="text/javascript">
X.callMethod("myId");
</script>
<div id="myid"></div>
This method has two advantages :
it lets user define its own id
the user specifies what behavior he wants from your script. With, that, you could add other methods which can be used in same way : user doesn't have the feeling that your code is intrusive, it's him who decides if he wants a feature or not.
You could just include the script... which at processing time generates a div and assigns it a unique ID. (Within that logic, you could check for duplicates)
Presuming you don't expect your widget to be included 1,000's of times... something like this (untested) should work.
var uniqueID;
var foundUniqueID = false;
var idx = 0;
while(foundUniqueID != true){
uniqueID = 'myID_' + idx;
if(document.getElementById(uniqueID)){
idx++;
} else {
foundUniqueID = true;
}
}
//create your DIV with your uniqueID etc.