XF 2.1 How can I exclude a nested html tag from <xf:foreach>?

Brad Padgett

Well-known member
Okay I have a simple question. The below code may seem complicated but the only part I want you to pay attention to is the <a><img></a> tags.

I want to run a foreach block for the <a> link tag but exclude the image from it where it only displays once. I have been at this for a week so if you could take a moment to help me it would be worth it. Normally I would just take the image out of the foreach block but in this case the functionality is inside the link so this is impossible.

@Sim was kind enough to suggest I don't use <xf:foreach> but this seems to be the easiest way as the code I was working with prior did not work. This code actually functions correctly but repeats the image 5 times. Each image links to the appropriate link but I want it all inside a single image. I really appreciate your help. I would have used another method but this seems to be the best way as I have a hunch there is a simple way to escape a <xf:foreach> for a nested tag that I'm just not seeing or found.

HTML:
<xf:if is="property('LightSwitch_On') == 'Enabled'">

    <xf:set var="$dark" value="{{ [ property('Dark_Switch'), property('Dark_Switch2'), property('Dark_Switch3'),  property('Dark_Switch4'), property('Dark_Switch5')] }}" />
    <xf:set var="$image" value="{{ base_url('styles/default/BP/LightSwitch/bulb-off.png', true) }}" />
            <xf:if is="property('styleType') == 'light'">
         
                <xf:foreach loop="$dark" key="$key" value="$style" i="$i">

<div style="float: left;">
           <a href="{{ link('misc/style', null, {'style_id': $style,'_xfRedirect': $xf.fullUri,'t': csrf_token()}) }}">
 
               <img src="{$image}" alt="turn the lights off">
          
            </a>
        </div>
                                                                                                     
                                                                                                             
    </xf:foreach>
         
                     
    </xf:if>
 
    <xf:set var="$light" value="{{ [ property('Light_Switch'), property('Light_Switch2'), property('Light_Switch3'),  property('Light_Switch4'), property('Light_Switch5')] }}" />
<xf:set var="$image" value="{{ base_url('styles/default/BP/LightSwitch/bulb-on.png', true) }}" />
     
    <xf:if is="property('styleType') == 'dark'">

     
<xf:foreach loop="$light" key="$key" value="$style" i="$i">


<div style="float: left;">
           <a href="{{ link('misc/style', null, {'style_id': $style,'_xfRedirect': $xf.fullUri,'t': csrf_token()}) }}">

                <img src="{$image}" alt="turn the lights on">
            
            </a>
        </div>
                                                                                 
    </xf:foreach>
     
 
        </xf:if>
    </xf:if>
 
So you want one link with an image in it and four completely empty link tags? I honestly have absolutely no idea what you're trying to do. Aren't you building a switch between light and dark style? If so, shouldn't you only ever need one link to the respective counterpart? Either way, why not an active state and hide the images inside the inactive links? What're the other links even for? Questions over questions... 🤔
 
So you want one link with an image in it and four completely empty link tags? I honestly have absolutely no idea what you're trying to do. Aren't you building a switch between light and dark style? If so, shouldn't you only ever need one link to the respective counterpart? Either way, why not an active state and hide the images inside the inactive links? What're the other links even for? Questions over questions... 🤔

Hey thanks for the quick response @Lukas W.

Yes I'm trying to make a light/dark switch add-on as well as a style chooser. Going to release it free when I'm finished. Style chooser is ready (separate code) and yes I did do separate links for those but I wasn't sure the best way to go about this one in particular or if making separate links was a good idea. Personally my site has 5 light and 5 dark styles so I wanted to give users 5 options for style_ids entries in style properties for each light and dark style. Should they leave an entry blank then it won't be hooked up.

Is there a better way to go about this? Maybe foreach is not the right option but I remember having trouble using separate links, possibly because I did not have the right conditional. If you think about it using <xf:if is="property('myProperty')"> would work but because there's more than one entry I'd have to somehow find a way to weed out the other 4 entries from showing.

If you have a tip on that then I got this down. Thank you btw.
 
Style properties doesn't seem to be appropriate at all for this. Style properties can vary depending on the style, and unless people have one main style and each other style is a descendant of that, they'll have to configure your stuff in multiple places. Plus, options, where it should go anyway, also gives you the flexibility to make the set arbitrarily large.

That said, use php code. Sticking with template mods and style properties may seem nice and shiny, but I think you noticed that you've reached the boundaries already. Do a template listener, there you can check for the active style and pick the corresponding alternate style, then display that link in the template. Pretty straightforward, no weird template loops or hacks required.
 
Style properties doesn't seem to be appropriate at all for this. Style properties can vary depending on the style, and unless people have one main style and each other style is a descendant of that, they'll have to configure your stuff in multiple places. Plus, options, where it should go anyway, also gives you the flexibility to make the set arbitrarily large.

That said, use php code. Sticking with template mods and style properties may seem nice and shiny, but I think you noticed that you've reached the boundaries already. Do a template listener, there you can check for the active style and pick the corresponding alternate style, then display that link in the template. Pretty straightforward, no weird template loops or hacks required.

The point of the style property/template mods was to make the add-on as simple as possible. Seems like overkill to use php code on something so simple. Was the main reason I did it that way. I wanted to setup style properties vs options because it gives the user the ability to do other things like possibly choose an icon for the light bulb or choose the style chooser preview color. Where if I used an option then it would be in 2 different places.

It may be possible with PHP code but this is a very simple add-on (with some added features) and it's not needed.

The way you describe it seems like it's easier but it may not be needed. Though I will take a look at some php code and see if there's a better way. I'm not against using php code for this but I have to wrap my head around whether or not it's going to be a realistic option for a simple style link.... :p
 
So.... you basically want 5 "color pickers", and a lightbulb to go with each color, is that correct?

If you want to stick to style properties, why not just do the following

custom_style_1 light
custom_style_1 dark
custom_style_2 light
custom_style_2 dark
custom_style_3 light
custom_style_3 dark
custom_style_4 light
custom_style_4 dark
custom_style_5 light
custom_style_5 dark

Then do a check if there's a value filled out for each property using individual style property checks. Although.... if I'm being honest this setup seems like a very.... "unique" setup, most forums do not run 10 different styles, 5 light, and 5 dark. Also, why not use the Font Awesome light bulb so users can easily resize/color it or use another icon if they want.
 
So.... you basically want 5 "color pickers", and a lightbulb to go with each color, is that correct?

If you want to stick to style properties, why not just do the following

custom_style_1 light
custom_style_1 dark
custom_style_2 light
custom_style_2 dark
custom_style_3 light
custom_style_3 dark
custom_style_4 light
custom_style_4 dark
custom_style_5 light
custom_style_5 dark

Then do a check if there's a value filled out for each property using individual style property checks. Although.... if I'm being honest this setup seems like a very.... "unique" setup, most forums do not run 10 different styles, 5 light, and 5 dark. Also, why not use the Font Awesome light bulb so users can easily resize/color it or use another icon if they want.

I'm happy you replied. Your always a nice face to see around here 😁

So basically yes I have tried this but something went wrong. Not sure what.

Tried something like this:

HTML:
<xf:if is="property('styleType') == 'dark'">
<xf:if is="property('custom_style_1')">
  <a href="{{ link('misc/style', null, {'style_id': property('custom_style_1'),'_xfRedirect': $xf.fullUri,'t': csrf_token()}) }}">

                <img src="{$image}" alt="turn the lights on">
            
            </a>
</xf:if>
</xf:if>

<xf:if is="property('styleType') == 'light'">
<xf:if is="property('custom_style_1')">
  <a href="{{ link('misc/style', null, {'style_id': property('custom_style_1'),'_xfRedirect': $xf.fullUri,'t': csrf_token()}) }}">

                <img src="{$image}" alt="turn the lights on">
            
            </a>
</xf:if>
</xf:if>

Of course put in their respective places in the code and applied all 5 times (this is without the foreach). Works fine but shows the others. Using xf:if returns true but because it's not on/off type deal and only an style id entry then the other entries style apply because they also return true.

I'm more than likely missing something here but would work as you stated quite fine if I knew how I could go that method. Also thanks for the tip I will add the ability to add a font awesome icon (had that in mind already :P)

As for special case, that is mostly correct. I designed my sites styles and found it very easy to mix 5 colors on both light and dark themes. I basically only have 3 colored style properties and then I applied them using "@" in the code. So while this is for my site, I also know someone else would get a lot of use out of it. The style chooser I already did separate links for and since there aren't 2 sides of the flip there it was easier to do. If the style ids are left blank in the light bulb as well as the style chooser it does not apply. There's up to 9 styles you can add to the chooser

Any idea?
 
Also I just realized in your example it's the same style custom_style_1 for example for each light and dark area. I had separate ID boxes for all 10 of the dark and light styles. If your method is a bit different I'm all ears. Appreciate your advice
 
So why not:

Code:
<xf:if is="property('custom_style_1 light ')">
  <a href="{{ link('misc/style', null, {'style_id': property('custom_style_1 light '),'_xfRedirect': $xf.fullUri,'t': csrf_token()}) }}">

                <xf:fa icon="fa-lightbulb" />
            
            </a>
</xf:if>
<xf:if is="property('custom_style_2 light ')">
  <a href="{{ link('misc/style', null, {'style_id': property('custom_style_2 light '),'_xfRedirect': $xf.fullUri,'t': csrf_token()}) }}">

                <xf:fa icon="fa-lightbulb" />
            
            </a>
</xf:if>
<xf:if is="property('custom_style_3 light ')">
  <a href="{{ link('misc/style', null, {'style_id': property('custom_style_3 light '),'_xfRedirect': $xf.fullUri,'t': csrf_token()}) }}">

                <xf:fa icon="fa-lightbulb" />
            
            </a>
</xf:if>
<xf:if is="property('custom_style_4 light ')">
  <a href="{{ link('misc/style', null, {'style_id': property('custom_style_4 light '),'_xfRedirect': $xf.fullUri,'t': csrf_token()}) }}">

                <xf:fa icon="fa-lightbulb" />
            
            </a>
</xf:if>
<xf:if is="property('custom_style_5 light ')">
  <a href="{{ link('misc/style', null, {'style_id': property('custom_style_5 light '),'_xfRedirect': $xf.fullUri,'t': csrf_token()}) }}">

                <xf:fa icon="fa-lightbulb" />
            
            </a>
</xf:if>

Repeat for the dark styles, place where you want them. I think you're over thinking this way too much. This way, if a user fills in a style id for each property, it'll show the lightbulb.
 
So why not:

Code:
<xf:if is="property('custom_style_1 light ')">
  <a href="{{ link('misc/style', null, {'style_id': property('custom_style_1 light '),'_xfRedirect': $xf.fullUri,'t': csrf_token()}) }}">

                <xf:fa icon="fa-lightbulb" />
           
            </a>
</xf:if>
<xf:if is="property('custom_style_2 light ')">
  <a href="{{ link('misc/style', null, {'style_id': property('custom_style_2 light '),'_xfRedirect': $xf.fullUri,'t': csrf_token()}) }}">

                <xf:fa icon="fa-lightbulb" />
           
            </a>
</xf:if>
<xf:if is="property('custom_style_3 light ')">
  <a href="{{ link('misc/style', null, {'style_id': property('custom_style_3 light '),'_xfRedirect': $xf.fullUri,'t': csrf_token()}) }}">

                <xf:fa icon="fa-lightbulb" />
           
            </a>
</xf:if>
<xf:if is="property('custom_style_4 light ')">
  <a href="{{ link('misc/style', null, {'style_id': property('custom_style_4 light '),'_xfRedirect': $xf.fullUri,'t': csrf_token()}) }}">

                <xf:fa icon="fa-lightbulb" />
           
            </a>
</xf:if>
<xf:if is="property('custom_style_5 light ')">
  <a href="{{ link('misc/style', null, {'style_id': property('custom_style_5 light '),'_xfRedirect': $xf.fullUri,'t': csrf_token()}) }}">

                <xf:fa icon="fa-lightbulb" />
           
            </a>
</xf:if>

Repeat for the dark styles, place where you want them. I think you're over thinking this way too much. This way, if a user fills in a style id for each property, it'll show the lightbulb.

Your right, I'm a bit new to the whole thing. Not so much new that I don't know how to use xenforo code just not super advanced like you guys quite yet. I hope to learn from the best. I didn't even know you could apply "light" to the same style property like that. That's news to me. By custom_style_1... etc I assume you mean the style ID property. I will give it a go. I will try to make this add-on have some extra features if I can think some up. Give me some time to get it ready. Thank you
 
Well, it's not really assigning "light or dark" to a style property, it's just labeling them as such.

Best of luck.

Well looks like I'll have to put my thinking cap on as it doesn't work. The light bulb only displays when I remove the label light and dark and then it shows both bulbs. Is there something I have to do on the style property end? Shouldn't be too hard to figure out on my own I just was looking for someone who had a quick answer that new the correct conditional to use.
 
My code:

HTML:
<xf:if is="property('LightSwitch_On') == 'Enabled'">

    <xf:if is="property('Dark_Switch dark ')">
  <a href="{{ link('misc/style', null, {'style_id': property('Dark_Switch dark '),'_xfRedirect': $xf.fullUri,'t': csrf_token()}) }}">


<img src="{{ base_url('styles/default/bp/lightswitch/bulb-off.png', true) }}">
            
            </a>
</xf:if>
    <xf:if is="property('Dark_Switch2 dark ')">
  <a href="{{ link('misc/style', null, {'style_id': property('Dark_Switch2 dark '),'_xfRedirect': $xf.fullUri,'t': csrf_token()}) }}">

                <img src="{{ base_url('styles/default/bp/lightswitch/bulb-off.png', true) }}">
            
            </a>
</xf:if>
    <xf:if is="property('Dark_Switch3 dark ')">
  <a href="{{ link('misc/style', null, {'style_id': property('Dark_Switch3 dark '),'_xfRedirect': $xf.fullUri,'t': csrf_token()}) }}">

               <img src="{{ base_url('styles/default/bp/lightswitch/bulb-off.png', true) }}">
            
            </a>
</xf:if>
    <xf:if is="property('Dark_Switch4 dark ')">
  <a href="{{ link('misc/style', null, {'style_id': property('Dark_Switch4 dark '),'_xfRedirect': $xf.fullUri,'t': csrf_token()}) }}">

               <img src="{{ base_url('styles/default/bp/lightswitch/bulb-off.png', true) }}">
            
            </a>
</xf:if>
    <xf:if is="property('Dark_Switch5 dark ')">
  <a href="{{ link('misc/style', null, {'style_id': property('Dark_Switch5 dark '),'_xfRedirect': $xf.fullUri,'t': csrf_token()}) }}">

              <img src="{{ base_url('styles/default/bp/lightswitch/bulb-off.png', true) }}">
            
            </a>
</xf:if>

<xf:if is="property('Light_Switch light ')">
  <a href="{{ link('misc/style', null, {'style_id': property('Light_Switch light '),'_xfRedirect': $xf.fullUri,'t': csrf_token()}) }}">

                               <img src="{{ base_url('styles/default/bp/lightswitch/bulb-on.png', true) }}">
            
            </a>
</xf:if>
<xf:if is="property('Light_Switch2 light ')">
  <a href="{{ link('misc/style', null, {'style_id': property('Light_Switch2 light '),'_xfRedirect': $xf.fullUri,'t': csrf_token()}) }}">

                                <img src="{{ base_url('styles/default/bp/lightswitch/bulb-on.png', true) }}">
            
            </a>
</xf:if>
<xf:if is="property('Light_Switch3 light ')">
  <a href="{{ link('misc/style', null, {'style_id': property('Light_Switch3 light '),'_xfRedirect': $xf.fullUri,'t': csrf_token()}) }}">

                               <img src="{{ base_url('styles/default/bp/lightswitch/bulb-on.png', true) }}">
            
            </a>
</xf:if>
<xf:if is="property('Light_Switch4 light ')">
  <a href="{{ link('misc/style', null, {'style_id': property('Light_Switch4 light '),'_xfRedirect': $xf.fullUri,'t': csrf_token()}) }}">

                                <img src="{{ base_url('styles/default/bp/lightswitch/bulb-on.png', true) }}">
            
            </a>
</xf:if>
<xf:if is="property('Light_Switch5 light ')">
  <a href="{{ link('misc/style', null, {'style_id': property('Light_Switch5 light '),'_xfRedirect': $xf.fullUri,'t': csrf_token()}) }}">

                              <img src="{{ base_url('styles/default/bp/lightswitch/bulb-on.png', true) }}">
            
            </a>
</xf:if>
</xf:if>

Just using the image for testing. I plan to add both the image and the icon to be used
 
Post your style properties.

Also, you can't just add light or dark to it. that's not what I meant at all. I mean rename your custom style properties to those I listed above.
 
I've already got it to work before both with the foreach method and also without it, just not without more than one bulb showing for multiple styles. I took your advice in the last thread about the radio buttons and it's already been tested so I did it right but heres a screenshot

197115
 
So try this out:

Code:
<xf:if is="{$xf.visitor.style_id} == property('Light_Switch') AND property('Dark_Switch')">
    <a href="{{ link('misc/style', null, {'style_id': property('Dark_Switch'),'_xfRedirect': $xf.fullUri,'t': csrf_token()}) }}">
        <img src="{{ base_url('styles/default/bp/lightswitch/bulb-off.png', true) }}">
    </a>
</xf:if>
</xf:if>
<xf:if is="{$xf.visitor.style_id} == property('Light_Switch2') AND property('Dark_Switch2')">
    <a href="{{ link('misc/style', null, {'style_id': property('Dark_Switch2'),'_xfRedirect': $xf.fullUri,'t': csrf_token()}) }}">
        <img src="{{ base_url('styles/default/bp/lightswitch/bulb-off.png', true) }}">
    </a>
</xf:if>
</xf:if>
<xf:if is="{$xf.visitor.style_id} == property('Light_Switch3') AND property('Dark_Switch3')">
    <a href="{{ link('misc/style', null, {'style_id': property('Dark_Switch3'),'_xfRedirect': $xf.fullUri,'t': csrf_token()}) }}">
        <img src="{{ base_url('styles/default/bp/lightswitch/bulb-off.png', true) }}">
    </a>
</xf:if>
</xf:if>
<xf:if is="{$xf.visitor.style_id} == property('Light_Switch4') AND property('Dark_Switch4')">
    <a href="{{ link('misc/style', null, {'style_id': property('Dark_Switch4'),'_xfRedirect': $xf.fullUri,'t': csrf_token()}) }}">
        <img src="{{ base_url('styles/default/bp/lightswitch/bulb-off.png', true) }}">
    </a>
</xf:if>
</xf:if>
<xf:if is="{$xf.visitor.style_id} == property('Light_Switch5') AND property('Dark_Switch5')">
    <a href="{{ link('misc/style', null, {'style_id': property('Dark_Switch5'),'_xfRedirect': $xf.fullUri,'t': csrf_token()}) }}">
        <img src="{{ base_url('styles/default/bp/lightswitch/bulb-off.png', true) }}">
    </a>
</xf:if>
</xf:if>

This will check if the visitor ID is using the Light_Switch style ID AND a dark sttyle id is set, then display a lightbulb. This way only 1 lightbulb will show when you're browsing that specific style. Is that what you're after?
 
So try this out:

Code:
<xf:if is="{$xf.visitor.style_id} == property('Light_Switch') AND property('Dark_Switch')">
    <a href="{{ link('misc/style', null, {'style_id': property('Dark_Switch'),'_xfRedirect': $xf.fullUri,'t': csrf_token()}) }}">
        <img src="{{ base_url('styles/default/bp/lightswitch/bulb-off.png', true) }}">
    </a>
</xf:if>
</xf:if>
<xf:if is="{$xf.visitor.style_id} == property('Light_Switch2') AND property('Dark_Switch2')">
    <a href="{{ link('misc/style', null, {'style_id': property('Dark_Switch2'),'_xfRedirect': $xf.fullUri,'t': csrf_token()}) }}">
        <img src="{{ base_url('styles/default/bp/lightswitch/bulb-off.png', true) }}">
    </a>
</xf:if>
</xf:if>
<xf:if is="{$xf.visitor.style_id} == property('Light_Switch3') AND property('Dark_Switch3')">
    <a href="{{ link('misc/style', null, {'style_id': property('Dark_Switch3'),'_xfRedirect': $xf.fullUri,'t': csrf_token()}) }}">
        <img src="{{ base_url('styles/default/bp/lightswitch/bulb-off.png', true) }}">
    </a>
</xf:if>
</xf:if>
<xf:if is="{$xf.visitor.style_id} == property('Light_Switch4') AND property('Dark_Switch4')">
    <a href="{{ link('misc/style', null, {'style_id': property('Dark_Switch4'),'_xfRedirect': $xf.fullUri,'t': csrf_token()}) }}">
        <img src="{{ base_url('styles/default/bp/lightswitch/bulb-off.png', true) }}">
    </a>
</xf:if>
</xf:if>
<xf:if is="{$xf.visitor.style_id} == property('Light_Switch5') AND property('Dark_Switch5')">
    <a href="{{ link('misc/style', null, {'style_id': property('Dark_Switch5'),'_xfRedirect': $xf.fullUri,'t': csrf_token()}) }}">
        <img src="{{ base_url('styles/default/bp/lightswitch/bulb-off.png', true) }}">
    </a>
</xf:if>
</xf:if>

This will check if the visitor ID is using the Light_Switch style ID AND a dark sttyle id is set, then display a lightbulb. This way only 1 lightbulb will show when you're browsing that specific style. Is that what you're after?

That's correct and quite ingenius of you. I can already tell it's going to work this time. Personally I just need to get used to the Xenforo syntax. Certain conditions like you've just shown are not documented and must be learnt from reading other threads or from other people. I spent a week searching google and wasn't quite lucky enough to find the right condition however this should do the trick. I can use your code to re-arrange it for the bulb-on portion, that's not as important as colors for the icon can be changed regardless. Appreciate you taking the time to write that.
 
Top Bottom