<xsl:attribute> should be used to set an attribute on an elements. In the above you just need a value in the variable, which should either hold a path to an image or display a text.
To set an attribute on an element you should do it like this for instance:
This should do the trick if the bgImage is not empty. In the above I'm just asuming that an image has been uploaded directly on your root node. If you're using a media picker then you will of course need to use GetMedia to fetch the proper image from the chosen media id.
Wether or not it's an ideal solution is hard for me to say since I only see the tip of the iceberg. But from what I've seen above I think it makes sense if you just don't do too much inline-styling. In situations where you need to be able to select backround images from a CMS then I think it's perfectly valid to use inline styling.
If there's only a single (or maybe a couple) exception(s), I usually make the code reflect the common state, and then have a clear condition to handle the exception.
So I'd throw the style attribute on, using an attribute value template (the curly braces) and then immediately after use an if + attribute instruction to override the style attribute if necessary:
Chriztian the problem is that the background picker at custom dropdown list with some options and not a image it self. But if I understand it right your will override the bgImage variable when your make the if statement? is that correct understod?
No - the $bgImage variable stays the same, but the style attribute will be overridden (which is probably also what you meant) - "There can only be one" (the Highlander rule :-) attribute of the name "style", so the last one added will be the one that ends up in the output tree.
But now I get what you want - you need to map the values in your picker to actual images... check this out then:
<xsl:variable name="rootnode" select="$currentPage/ancestor-or-self::* [@level = '1']" />
<!-- Lookup variable for background images -->
<xsl:variable name="imagesProxy">
<bg id="SortPlade" src="/images/patterns/blackplate.png" />
<bg id="GulPlade" src="/images/patterns/yellowplate.png" />
<!-- etc. -->
</xsl:variable>
<xsl:variable name="images" select="msxml:node-set($imagesProxy)" />
<!-- Find the image chosen in the picker (if any) -->
<xsl:variable name="bgImage" select="$images/bg[@id = $rootnode/backgroundPicker]/@src" />
<!-- Add a default (fallback) image directly -->
<div class="fullWidthWrapper" id="sliderBackground" style="background: url(/images/patterns/default.png);">
<!-- If an image was picked, use that instead -->
<xsl:if test="normalize-space($bgImage)">
<xsl:attribute name="style">
<xsl:value-of select="concat('background: url(', $bgImage, ');')" />
</xsl:attribute>
</xsl:if>
<!-- ... -->
</div>
<!-- This is a kind of the xsl:choose it looks for wich one i choosen? --> <xsl:variablename="imagesProxy"> <bgid="SortPlade"src="/images/patterns/blackplate.png"/> <bgid="GulPlade"src="/images/patterns/yellowplate.png"/> <!-- etc. --> </xsl:variable>
<!-- ...And then it does something i dont understand - msxml:node-set explanation??? --> <xsl:variablename="images"select="msxml:node-set($imagesProxy)"/>
<!-- and then i catch the image from the imagesProxy --> <xsl:variable name="bgImage"select="$images/bg[@id = $rootnode/backgroundPicker]/@src"/>
<!-- Add a default (fallback) image directly --> <divclass="fullWidthWrapper"id="sliderBackground"style="background: url(/images/patterns/default.png);"> <!-- If an image was picked, use that instead --> <xsl:iftest="normalize-space($bgImage)"> <xsl:attributename="style">
<!-- What does concat do? Is it way to insert plain text? --> <xsl:value-ofselect="concat('background: url(', $bgImage, ');')"/> </xsl:attribute> </xsl:if> <!-- ... --> </div>
I like that you're not just "OK, I'll copy & paste that here - next..." but (like me) actually want to know what's going on :-)
The $imagesProxy variable is just a chunk of XML that we've constructed so it maps a value to an image. Unfortunately, you can't use XPath on a variable created like that because of (insert long difficult explanation here - google "Result Tree Fragment" if you're curious) - so that's why the msxml:node-set() function is there - it converts our XML variable into a nodeset, on which we can now use XPath, which we do to select the image that maps to the value that was selected in the backgroundPicker property on the $rootNode.
concat() is a function that takes 2 or more arguments — converting every argument to a string and returning them as a single string - when used in a value-of instruction, it's essentially the same as using a mix of text and value-of instructions, e.g.:
<xsl:text>Hello </xsl:text>
<xsl:value-of select="$name" />
<xsl:text>, how are you?</xsl:text>
Is the same as:
<xsl:value-of select="concat('Hello ', $name, ', how are you?')" />
In most situations, using concat() is just easier to "read".
Yeah - that's basically it - you *could* actually define it like that (using <id> and <src> nodes instead of attributes) and then you would just have to remove the "@" where you select them (so $images[id = ...]/src instead of $images[@id = ...]/@src) - it's just a chunk of XML that you can use standard XPath on.
This happens because you're accidentally picking the first one everytime (because you're using $slideNode inside the for-each) - when you're inside a for each and you're doing a comparison this way, you need to use the current() function to get a reference to the current item in the loop:
Variable attribute
Hey Guys
I've a problem with collecting values in an variable with xsl:attribute.
I'm getting this message:
Error occured
System.Xml.Xsl.XslTransformException: An item of type 'Attribute' cannot be constructed within a node of type 'Root'.
Any ideas what i'm doing wrong?
Hi Mads
<xsl:attribute> should be used to set an attribute on an elements. In the above you just need a value in the variable, which should either hold a path to an image or display a text.
To set an attribute on an element you should do it like this for instance:
<div>
<xsl:attribute name="class">box</xsl:attribute>
</div>
So just remove the attribute element in the above and your variable will work.
Hope this helps.
/Jan
Hey Jan
I dont think i understand what you mean?
What i want is something like this:
<div id="holder" style="background: url({$bgImage})"></div>
but i need to check what value i checked?
And i wanted to use the variable insite the div style?
I hope it make seense :)
Hi Mads
Ok, to achieve the above you will need to do something like this.
<xsl:variable name="rootnode" select="$currentPage/ancestor-or-self::* [@level = '1']" />
<xsl:variable name="bgImage" select="$rootnode/backgroundPicker" />
<div id="holder">
<xsl:if test="normalize-space($bgImage)">
<xsl:attribute name="style">
<xsl:value-of select="concat('background: url',$bgImage,');')" />
</xsl:attribute>
</xsl:if>
</div>
This should do the trick if the bgImage is not empty. In the above I'm just asuming that an image has been uploaded directly on your root node. If you're using a media picker then you will of course need to use GetMedia to fetch the proper image from the chosen media id.
Hope the above makes a bit more sense :)
/Jan
Hej Jan
I was just working out something simular. It's bit tricky solution, we are runne multiple sites on same umbraco install.
And it's the same kind of clients but with custom themes to there websites.
<xsl:variable name="rootnode" select="$currentPage/ancestor-or-self::* [@level = '1']" />
<xsl:variable name="bgImage" select="$rootnode/backgroundPicker" />
<xsl:value-of select="$bgImage" />
<div class="fullWidthWrapper" id="sliderBackground">
<xsl:attribute name="style"><xsl:text>background: url(</xsl:text>
<xsl:choose>
<xsl:when test="$bgImage = 'Sortplade'">/images/patterns/blackplate.png</xsl:when>
</xsl:choose>
<xsl:text>);</xsl:text>
</xsl:attribute>
</div>
I'll just need to apply xsl:otherwise as fallback :D
Is it at stupid way to solve the problem? I'm not sure if it's the best way?
Hi Mads
Hi Mads the above looks fine to me.
Wether or not it's an ideal solution is hard for me to say since I only see the tip of the iceberg. But from what I've seen above I think it makes sense if you just don't do too much inline-styling. In situations where you need to be able to select backround images from a CMS then I think it's perfectly valid to use inline styling.
Glad you figured it out btw :)
/Jan
Hi Mads (+ Jan),
If there's only a single (or maybe a couple) exception(s), I usually make the code reflect the common state, and then have a clear condition to handle the exception.
So I'd throw the style attribute on, using an attribute value template (the curly braces) and then immediately after use an if + attribute instruction to override the style attribute if necessary:
/Chriztian
Hey guys.
Thanks for your help Jan.
Chriztian the problem is that the background picker at custom dropdown list with some options and not a image it self.
But if I understand it right your will override the bgImage variable when your make the if statement? is that correct understod?
Another thing, i thought it was possible to make an attribute on af variable?
Am i wrong on this?
Hi Mads,
No - the $bgImage variable stays the same, but the style attribute will be overridden (which is probably also what you meant) - "There can only be one" (the Highlander rule :-) attribute of the name "style", so the last one added will be the one that ends up in the output tree.
But now I get what you want - you need to map the values in your picker to actual images... check this out then:
/Chriztian
Hey Chriztian
That works just as great as my own so let me se if get this right.
I know im a bit heavy to dance with :o)
/mads
Hi Mads,
I like that you're not just "OK, I'll copy & paste that here - next..." but (like me) actually want to know what's going on :-)
The $imagesProxy variable is just a chunk of XML that we've constructed so it maps a value to an image. Unfortunately, you can't use XPath on a variable created like that because of (insert long difficult explanation here - google "Result Tree Fragment" if you're curious) - so that's why the msxml:node-set() function is there - it converts our XML variable into a nodeset, on which we can now use XPath, which we do to select the image that maps to the value that was selected in the backgroundPicker property on the $rootNode.
concat() is a function that takes 2 or more arguments — converting every argument to a string and returning them as a single string - when used in a value-of instruction, it's essentially the same as using a mix of text and value-of instructions, e.g.:
Is the same as:
In most situations, using concat() is just easier to "read".
Hope that clears some of your questions!
/Chriztian
Hi Chriztian
So basicly this is
<imagesProxy>
<bg>
<id>SortPlate</id>
<src>/images/....</src>
</bg>
<bg>
<id>YellowPlate</id>
<src>/images/....</src>
</bg>
</imagesProxy>
And then you tell umbraco that imagesproxy is a node like in the content tree with values of id and src??
Hi Mads,
Yeah - that's basically it - you *could* actually define it like that (using <id> and <src> nodes instead of attributes) and then you would just have to remove the "@" where you select them (so $images[id = ...]/src instead of $images[@id = ...]/@src) - it's just a chunk of XML that you can use standard XPath on.
/Chriztian
Hi Chriztian
I think i get it :D
I've already used it several times :D
Hi Chriztian
...and then i ran into this problem. It only output the first image??? what do i do wrong?
Hi Mads,
This happens because you're accidentally picking the first one everytime (because you're using $slideNode inside the for-each) - when you're inside a for each and you're doing a comparison this way, you need to use the current() function to get a reference to the current item in the loop:
/Chriztian
Oh - and by the way: I don't get what the xsl:if around the <img> is supposed to do, actually - was that an extra check you we're doing?
Shouldn't be necessary...
/Chriztian
Understanding the context I do master'xslt'jedi!
- and it make sense :D
Thanks a lot Chriztian :o)
is working on a reply...