2

Basically, I am rewriting part of one of my web applications. I had a script that would collapse some or all panels of the interface at once, and another to code them.

However, my old functions looked really ugly, and were annoying to type and not powerful enough:

function collapse_all()
{
    document.getElementById("panel_1").style.display="none"
    document.getElementById("panel_2").style.display="none"
    document.getElementById("panel_3").style.display="none"
}
function expand_all()
{
    document.getElementById("panel_1").style.display=""
    document.getElementById("panel_2").style.display=""
    document.getElementById("panel_3").style.display=""
}

Now I have this:

function panel() //first variable in argument is collapse or expand, all others are panels to act on
{
    var panels = panel.arguments
    alert(typeof panel.arguments)
    var mode = panels.shift() //here's my problem
    if(mode=="collapse") {mode="none"}
    if(mode=="expand") {mode=""}
    var items = panels.length
    for (i = 0;i < items;i++) {document.getElementById(panels[i]).style.display=mode}
}

panel("collapse","panel_1","panel_2","panel_3")

I have a problem though. Firebug tells me panels.shift() is not a function. With some Googling I managed to find out that panel.arguments isn't an array but an object, so I can't use array methods on it. I'm just really confused as to how I could either convert the object into an array or find another workaround, as I know next to nothing about JavaScript objects. Some example code would be highly appreciated.

4
  • 3
    You really should use ; at the end of your statements. Relying on JavaScripts auto-insertion is not what you want. Trust me. Commented Nov 26, 2010 at 18:24
  • Thanks for the suggestion, but I'm not a professional web developer and I've read it's only a problem when you have multiple lines of code squeezed into one line (and I do use semicolons for that) and when the next line starts with (. I've never had problems with it. Commented Nov 26, 2010 at 18:35
  • Well, since you're "not a professional web developer," I would highly recommend taking elusive's advice and use the semi-colons whether you think you need them or not. They improve readability and remove any ambiguity the compiler might run into. Commented Nov 26, 2010 at 18:39
  • Alright, I'll consider it, thanks. Commented Nov 26, 2010 at 18:42

2 Answers 2

4

You can convert the arguments object into an array like this:

var argsArray = Array.prototype.slice.call(arguments);

What this does is use the slice method common to all arrays via Array.prototype to create a genuine Array object from the array-like arguments. call() (a method of all functions) is used to call this slice method with a this value of arguments and no parameters, which has the effect of copying all of the elements of this into a new array. This may seem devious or hacky but it is actually designed into the language: see the note at the bottom of section 15.4.4.10 of the ECMAScript 3rd Edition spec.

Also, within a function you are provided the arguments object as a variable, so you don't need to access it as a property of the function object as you are doing. In your case, just use arguments rather than panel.arguments.

Sign up to request clarification or add additional context in comments.

4 Comments

Thanks, this works great. While my other answers are useful, I'll select this one because it's the first answer to give me exactly what I needed.
Can you perhaps explain in more depth what Array.prototype.slice.call() is actually doing?
Awesome!!! You'd get some points for sure if you added input to my question - stackoverflow.com/questions/4269426/…. I'm trying to figure out what I am missing from my javascript arsenal.
I got a lot of resources/books, but i would have liked some solid language feature examples like this.
4

You could keep it much simpler (cleaned up your formatting, semi-colons, etc.):

function panel() 
{
    var panels = Array.prototype.slice.call(arguments);
    var displayMode = (panels[0] == "collapse" ? "none" : "");

    for (var i = 1; i < panels.length - 1; i++) 
    {
        document.getElementById(panels[i]).style.display = displayMode;
    }
}

Also, if you're rewriting your application, it might be a good time to consider using things like jQuery. You could assign each one of your panels a certain class name, and reduce your code to something like this:

function panel(hide)
{
    $('.className').css({ display: (hide ? 'none' : '') });
}

which you could use like so:

panel(true); // or
panel(false);

Or, because now it's so syntactically simple, you might as well just create two separate functions so that your code is straightforward and you know exactly what it's going to do from the function names alone:

function showPanels() {
    $('.className').css({ display: '' });
}

function hidePanels() {
    $('.className').css({ display: 'none' });
}

And finally, if you don't worry about doing it via CSS, you could really shorten your script to this, which can't be any clearer:

function showPanels() {
    $('.className').show();
}

function hidePanels() {
    $('.className').hide();
}

Cheers!

1 Comment

definitely great advice. This is a perfect example of how jQuery helps clean up javascript code.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.