3

I am trying to generate a number of classes in a loop based on a number of pre-defined variable snippets.

I have a variables.less document that I am importing at the top of this less file containing my color variables. I then want to generate matching classes for these, but I am unable to get less to compile the variable.

My code:

.loop-class(~"primary", ~"success", ~"info", ~"warning", ~"danger";);
.loop-class(@list, @index: 1) when (isstring(extract(@list, @index))) {
    @status: extract(@list, @index);

    .button-@{status} {
        color: ~'@button-@{status}';
    }
    .loop-class(@list, (@index + 1));
}

Which compiles to:

.button-primary {
  color: @button-primary;
}
.button-success {
  color: @button-success;
}
etc etc

As you can see, I get the variable name to concatenate correctly, but I can not get it to resolve, so I'm guessing that LESS has already done it's variable compilation before getting to this function?

I have already tried moving the variables into this document, as well as wrapping the variables in a mixin and adding that inside the .loop-class, but neither of these seemed to help.

I also tried something like:

@status: extract(@list, @index);
@compileClass: ~'@button-@{status}';

.button-@{status} {
    color: @compileClass;
}

where I am saving the variable in a another one and then referencing that, but it yields the same result.

I looked at less css calling dynamic variables from a loop and tried implementing that as follows:

.loop-class(~"primary", ~"success", ~"info", ~"warning", ~"danger";);
.define(@var) {
    @fallback: ~'@button-@{var}';
}

.loop-class(@list, @index: 1) when (isstring(extract(@list, @index))) {
    @status: extract(@list, @index);

    .button-@{status} {
        .define(@status);
        color: @@fallback;
    }
    .loop-class(@list, (@index + 1));
}

But that gave me the error that @@button-danger (last in the index) is undefined, so it still can't resolve the variable.

Is it obvious to you guys what I'm doing wrong?

Thanks for your help!

Community
  • 1
  • 1
Micke Alm
  • 85
  • 6

1 Answers1

4

Missing Brackets

You are missing a set of needed brackets to resolve the variable:

LESS

//imported from another file
@button-primary: cyan;
@button-success: green;
@button-info: orange;
@button-warning: yellow;
@button-danger: red;

//in your mixin file
.loop-class(~"primary", ~"success", ~"info", ~"warning", ~"danger";);
.loop-class(@list, @index: 1) when (isstring(extract(@list, @index))) {
    @status: extract(@list, @index);

    .button-@{status} {
    color: ~'@{button-@{status}}'; /* two more brackets needed */
              |                |
            here             here
    }
    .loop-class(@list, (@index + 1));
}

CSS Output

.button-primary {
  color: #00ffff;
}
.button-success {
  color: #008000;
}
.button-info {
  color: #ffa500;
}
.button-warning {
  color: #ffff00;
}
.button-danger {
  color: #ff0000;
}

Cleaner More Friendly Code

Also, as a matter of less cluttered and more user friendly code, you can remove your multiple string interpolations needed for the mixing call by changing isstring to iskeyword in your mixin:

.loop-class(primary, success, info, warning, danger;); /* cleaner code on call */
.loop-class(@list, @index: 1) when (iskeyword(extract(@list, @index))) {
    @status: extract(@list, @index);

    .button-@{status} {
    color: ~'@{button-@{status}}';
    }
    .loop-class(@list, (@index + 1));
}
ScottS
  • 71,703
  • 13
  • 126
  • 146
  • Excellent, the solution worked perfectly! Great call on using iskeyword instead, definitely makes it more easy to read and understand. Thanks a bunch, Scott! – Micke Alm Jan 30 '14 at 16:18