views:

305

answers:

6

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.

+2  A: 

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!

David Pfeffer
A: 

Use jQuery. It provides a very useful $.css() method, which does what you're looking for in a very simple fashion.

Drew Wills
Stop giving pure javscript answers using JQuery. Use JQuery is not a solution.
Zaje
I disagree with our comment Zaje. For one the OP claims they are not very proficient in Javascript. Because of this, using jquery may be the best/easiest solution. If the user is not interested (because they already know about jquery) then I would assume they would ask for a pure javascript solution. If they do not know about it (or any other js library) then I think they are valid solutions.
sberry2A
Agree with Zaje on this. JQuery is not the end all, be all to every JavaScript question. Saying "use JQuery" is as useful as saying "don't use SharePoint."
Benry
Agree with Benry and Zaje. People really need to rely on JavaScript natively a lot of the time. You can't just tell people who are making a simple web page change to add a huge library to their page.
David Pfeffer
sberry the guy has given you the entire code, why dont you just point out the mistakes in his code rather than telling him to use JQuery. They arent proficient with javascript, why tell them to include more javscript files ? wont it increase their troubles , as to which files to include and which to not, which file does wat etc.??
Zaje
I agree with Zaje, Benry and bytenik. If the OP isn't proficient in JavaScript, he should learn JavaScript, not cover up his short-comings with jQuery, or any other library. That will just lead to more problems with the abuse and inefficient use of a library. I'm not saying that novices shouldn't use a library, I'm just saying that they should understand the language and at least be able to tell spot syntax errors and misuse of native functions.
Justin Johnson
Its a really tough balance. On SO, the answer "Use jQuery" is not fair to the OP since they never will really see why their code didn't work. On the other hand, I think jQuery *should* be used (like a browser reset css -- hot topic alert) to assist with normalizing browser differences. I think as people work with more and more advanced jQuery, they will in turn learn much about JavaScript. That being said, I think JavaScript fundamentals (syntax, loops, etc) are really a must to understand even before using jQuery.
Doug Neiner
Drew Wills
A: 

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.

Andrew Noyes
The OP states he's stuck using IE.
David Pfeffer
@bytenik He's still right about his first comment; which is the OP's main problem aside from your note on syntax.
Justin Johnson
Sure, that's why I mentioned that there are homegrown versions which can bring the convenience of that function to older browsers that don't support it and benefit from the speed of the ones that do. It's not something you can only take advantage of if your target audience is using a newer, non-IE browser.
Andrew Noyes
A: 

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.

atxryan
`documents.getElementsByClassName` does natively exist in JavaScript, just not in IE
Justin Johnson
Thanks for the correction. I'd completely forgotten the 'good' browsers added native support a couple of years ago.
atxryan
document.getElementsByClassName is part of the HTML 5 DOM but not any other standard. For the record.
Benry
+7  A: 

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"&gt;&lt;/script&gt;
<script type="text/javascript" charset="utf-8">
  $(function(){
    $('button.toggle').click(function(){
      $("tr.XmlGridPlannedWork").toggle();
    })
  })
</script>

<button class="toggle">Toggle Planned Line</button>
Doug Neiner
Thanks for not suggesting jQuery Doug ;)
Justin Johnson
LOL... I did mention it at the end, but only after providing the pure version first :)
Doug Neiner
+1 - Just one small point - a `<tr>` element may have more than one CSS class, so may want to use a regex to test whether the className attribute contains a particular CSS class.
Russ Cam
Justin Johnson
@Russ good point. I updated the answer. I chose to use a simple string test vs. a RegEx but the point is still valid, thanks! @Justin Good points as well.
Doug Neiner
@Doug, Agree with Russ, you need a RegExp to check the className (the `indexOf` edit IMHO is not enough, imagine a class named `BarXmlGridPlannedWorkFoo`, the `indexOf` check will wrongly return `true`), and you have a small typo in that `if` also, you refer to `obj` instead of `objs`. And finally when you use the `document.getElementsByClassName` method, you should pass only the name of the class (without the dot). Good work +1
CMS
@CMS Doh! Thanks for catching the typos. I am curious how a RegEx would help a straight string match? @Everyone I think we missed the forest for the trees. I added a new solution to the top of this answer that is way simpler and still does the same thing. Thoughts?
Doug Neiner
@Doug, you have to be sure that you are matching a single and complete className, imagine the `foo` and `fooBar` classes on an element, how do you test if an element contains a `fo` class?. You could use `indexOf` but doing something like this:`var c = " " + node.className + " "; if (c.indexOf(" " + needle + " ") { /*...*/ }` where `needle` is the class you look for, in the `node` element...
CMS
Your original solution worked perfectly. Your simplified solution probably would work too if not for the convoluted combination of Sharepoint and IE. I thank you for a solution that focused on pure JavaScript vs diving into the jQuery that wouldn't readily work on a intranet server (well, I could make a local copy of the library).
entens
@Doug The regular expression typically used to match whole needles in a given string is `className.match(/\bneedle\b/)`. This takes care of all edge cases and is short and elegant.
Justin Johnson
@Justin @CMS Thanks guys, updated my answer. Appreciate the detailed feedback!
Doug Neiner
A: 

Can anyone tell this total noob if (and how) it may be possible to make this script work with checkboxes instead of buttons?

chachi69
<input type="checkbox" onClick="toggle_PlannedLine();">Toggle Planned Line</button>iirc, the checkbox should have the onClick too.
entens
My apologies, I should have mentioned that I was using the jQuery script. After a good night's sleep I realized it was a simple change from: $('button.toggle').click(function(){... to $('input.toggle').click(function(){ AND<button class="toggle">Toggle Planned Line</button> TO<input class="toggle" type="checkbox">Toggle Planned Line</input>//Thanks!
chachi69