0

I'm struggling with closure scope in a JavaScrit function. The function below should create three swatches with different images (which works), then when these are clicked, should switch the stylesheet.

The problem is that the same object is passed to the switchTheme function even though stepping through shows the theme variable in the first function does change.

var switcherConfig = {
    themes: 
        {
            'Orangeness': {
                folder: 'ui-lightness'
            },
            'Red Matter': {
                folder: 'blitzer'
            },
            'Flubber': {
                folder: 'south-street'
            }
        }
}
function createThemeSwitcher(placeholderSelector) {
    for (var themeName in switcherConfig.themes) {
        var theme = switcherConfig.themes[themeName];
        var anchor = $('<a/>')
            //.text(theme.title)
            .attr('title', theme.title)
            .attr('href', '#')
            .on('click', function () { switchTheme(theme); })
            // append to DOM etc
    }
}
function switchTheme(theme) {
    var themeDirectory = switcherConfig.baseDirectory + '/' + theme.folder + '/';
    // 'theme' variable is always the last in my 'themes' config object
}

3 Answers 3

3

The value used by switchTheme(theme) will be the state that theme is in when the function is called, the value is not bound at the moment you create that anonymous callback. Use a closure to bind that particular value:

.on('click', (function (t) {
    return function () { switchTheme(t); };
})(theme))
Sign up to request clarification or add additional context in comments.

2 Comments

That piece of code makes an anonymous function which takes a value t and returns a function that calls switchTheme with that value. You're then immediately calling that anonymous function, passing it the current value of theme. Hope that helps.
Yes, I am quite confused, but this looks correct. Can you explain?
0

Move

var theme = switcherConfig.themes[themeName];

to click function

function createThemeSwitcher(placeholderSelector) {
    for (var themeName in switcherConfig.themes) {

        var anchor = $('<a/>')
            //.text(theme.title)
            .attr('title', theme.title)
            .attr('href', '#')
            .on('click', function () { 
                         var theme = switcherConfig.themes[themeName];
                         switchTheme(theme); 
            })
            // append to DOM etc
    }
}

1 Comment

the theme.title will fail while setting attribute title
0

Instead of making closure you can use .data like below (just an alternative):

var switcherConfig = {
    themes: 
        {
            'Orangeness': {
                title:"Orangeness",
                folder: 'ui-lightness'
            },
            'Red Matter': {
                                title:'Red Matter',
                folder: 'blitzer'
            },
            'Flubber': {
                title:'Flubber',
                folder: 'south-street'
            }
        }
}
function createThemeSwitcher(placeholderSelector) {
    for (var themeName in switcherConfig.themes) {
        var theme = switcherConfig.themes[themeName];
        var anchor = $('<a/>')
            .data("theme",theme)
            .attr('title', theme.title)
            .attr('href', '#')
            .html(theme.title)
            .on('click', function () { switchTheme($(this).data("theme")); })
            $("body").append(anchor);
    }
}
function switchTheme(theme) {
    alert(theme.title)
}

Demo

Comments

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.