-2

firstly I'm a novice at jQuery so please bear with me :)

I'm trying to switch multiple stylesheets at the same time on a button click, here is the code I'm using... Not sure why it doesn't work :( Can anyone help?

Here is the CSS:

<link title="default" rel="stylesheet" type="text/css" href="_includes/css/default_style.css" />
<link media="print" href="_includes/css/print.css" rel="stylesheet" type="text/css" />

Javascript:

<script>
$('#default').click(function (){
    $('link[title="theme"]').removeAttr('href').attr('href','_includes/css/default_style.css');
    $('link[media="print"]').removeAttr('href').attr('href','_includes/css/print.css');
});
$('#monochrome').click(function (){
    $('link[title="theme"]').removeAttr('href').attr('href','_includes/css/mono_style.css');
    $('link[media="print"]').removeAttr('href').attr('href','_includes/css/print.css');
});
$('#annotation').click(function (){
    $('link[title="theme"]').removeAttr('href').attr('href','_includes/css/acrf_style.css');
    $('link[media="print"]').removeAttr('href').attr('href','_includes/css/acrfprint.css');
});
</script>

and the HTML

<button id="default">Default</button>
<button id="monochrome">Monochrome</button>
<button id="annotation">Annotations</button>
Dave Burns
  • 327
  • 1
  • 2
  • 14
  • 1
    Define _it doesn't work_. – emerson.marini Mar 11 '15 at 10:23
  • Try not removing the href attribute before changing it, just change it. – Matt.C Mar 11 '15 at 10:23
  • 1
    Side note: You don't need to use `.removeAttr()` before using `attr()`. – emerson.marini Mar 11 '15 at 10:24
  • 4
    You are better off defining your stylesheets as classes in a single stylesheet and then switching classes, it's faster and looks better (as the switch is instant) – somethinghere Mar 11 '15 at 10:24
  • @MelanciaUK - Nothing happens when the buttons are clicked, I've removed the .removeAttr() from the string and still nothing :( – Dave Burns Mar 11 '15 at 10:33
  • @somethinghere this is not an option for me as the css is hugely different for the print css files. – Dave Burns Mar 11 '15 at 10:33
  • @DaveBurns Media queries to the rescue. Anyhow, my answer covers both ways. – somethinghere Mar 11 '15 at 10:46
  • You said nothing is happening when you click any of the buttons. Are they being added dynamically? When you debug your script using the browser dev tools, are the event handlers being hit? I can't see any mention to the document ready event handler in your code. You may need to use event delegation here, but that's a shot in the dark without more information from you. – emerson.marini Mar 11 '15 at 10:51
  • Possible duplicate of: [How do I switch my CSS stylesheet using jQuery?](http://stackoverflow.com/questions/7846980/how-do-i-switch-my-css-stylesheet-using-jquery) – emerson.marini Mar 11 '15 at 11:01
  • @MelanciaUK it's actually a different question because I wanted to swap multiple stylesheets in this instance. I have thanked you for your help in my answer post. – Dave Burns Mar 11 '15 at 11:07

2 Answers2

0

I am unsure what your problem is as there could be many, so I'll outline a few here. I've also tried to improve it a bit.

First off, you haven't mentioned where your script is in your page. If you put this in the head, then you need to wrap it in a $("document").ready(function(){}); listener, otherwise your buttons won't be found.

Secondly, you don't need it but it's best practise to pass the event and prevent the default action on buttons. It won't matter now, but just keep doing it.

Thirdly, you are repeating yourself a bit, so why not wrap it in a function you can call easily? Heres what all this looks like:

function switchStyleSheets(theme, print){
  $('link[title="theme"]').attr('href', theme);
  $('link[media="print"]').attr('href', print);
}

$(document).ready(function(){
    $('#default').click(function(event){
        event.preventDefault();
        switchStyleSheets(
            '_includes/css/default_style.css',
            '_includes/css/default_print.css'
        );
    });
    $('#monochrome').click(function(event){
        event.preventDefault();
        switchStyleSheets(
            '_includes/css/print_style.css',
            '_includes/css/print_print.css'
        );
    });
    $('#annotation').click(function(event){
        event.preventDefault();
        switchStyleSheets(
            '_includes/css/annoted_style.css',
            '_includes/css/annoted_print.css'
        );
    });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.0/jquery.min.js"></script>
<button id="default">Default</button>
<button id="monochrome">Monochrome</button>
<button id="annotation">Annotations</button>

But this is not good practise either! You are switching our files that need to be loaded in every time you switch. The reason this is bad is that the file needs time to load, and in the meanwhile you lose all your styling! It might not seem like much if your files are a couple of kilobytes, but larger files and slower connections start making this bad! So here a better solution:

$(document).ready(function(){
    /* To easily remove all styles later, lets make a string that lists them all */
    var allStyles = "";
    $("button[data-style]").each(function(){
        /* Add the data-style attribute to the all string */
        allStyles += $(this).data("style") + " ";
    }).click(function(event){
        /* Get the class from the button */
        var style = $(this).data("style");
        /* Remove all the classes, then add this single on */
        $("body").removeClass(allStyles).addClass(style);
    });
});
/* Define all your classes as body classes */
body.default {
    background: red;
}
body.mono {
    background: black;
}
body.annotated {
    background: blue;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.0/jquery.min.js"></script>
<!-- Give every button a data-style attribute or value that we can read on click. -->
<button id="default" data-style="default">Default</button>
<button id="monochrome" data-style="mono">Monochrome</button>
<button id="annotation" data-style="annotated">Annotations</button>

You also mention that the CSS is hugely different for the print files. Well, thats what media queries are made for. The following will allow you to define everything in one file:

body.default {
    background: red;
}
body.mono {
    background: black;
}
body.annotated {
    background: blue;
}
@media print {
    body.default {
        background: red;
    }
    body.mono {
        background: black;
    }
    body.annotated {
        background: blue;
    }
}

The whole purpose is to learn to use media queries efficiently. Now, there are limitations to this (IE has rule limitations), but it is better practise than switching out files on the fly.

somethinghere
  • 16,311
  • 2
  • 28
  • 42
  • Many thanks for the in-depth reply, I am running the script in the head tags so I have now included the $("document").ready(function(){ wrapper. However this still hasn't proved fruitful. As for the page size/file size comment this is for an intranet site so we don't have to worry about internet speeds and such. It still doesn't appear to be working regardless of each of the methods used. I'm going to spend some more time on it and see what I can come up with using the methods you have suggested. Cheers. – Dave Burns Mar 11 '15 at 10:52
  • Apologies, on running debug I can see that the print css is being changed but the title="theme" isn't running, is it possible that title="theme" is not being looked at properly? – Dave Burns Mar 11 '15 at 10:57
  • @DaveBurns They both changed in my testing. You could always try changing this to media="all" and check for that, as it appears that the media-specific one does work! – somethinghere Mar 11 '15 at 10:59
  • I've just solved it, adding the answer now, thanks for your help! – Dave Burns Mar 11 '15 at 11:00
0

I managed to solve it with help from @somethinghere and @MelanciaUK

I changed the Javascript to this:

<script>
$("document").ready(function(){
    $('#default').click(function (){
        $('link').first().attr('href','_includes/css/default_style.css');
        $('link[media="print"]').attr('href','_includes/css/print.css');
    });
    $('#monochrome').click(function (){
        $('link').first().attr('href','_includes/css/mono_style.css');
        $('link[media="print"]').attr('href','_includes/css/print.css');
    });
    $('#annotation').click(function (){
        $('link').first().attr('href','_includes/css/acrf_style.css');
        $('link[media="print"]').attr('href','_includes/css/acrfprint.css');
    });
});
</script>

Basically I added the $("document").ready(function(){ to the top of the script as it's being called in the head tags, I then changed the reference ('link[title="theme"]') to ('link').first(), I noticed in the debugger that the print css files were being swapped but the script wasn't actively changing the theme, I solved this by getting the script to look at the first reference of the link tag and change the reference in there.

thanks for your help everyone and a massive thanks for those that downvoted.

Dave Burns
  • 327
  • 1
  • 2
  • 14