Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Jeroen Oostwouder 104 posts 300 karma points
    Jun 17, 2022 @ 09:35
    Jeroen Oostwouder
    0

    Best practice to render optional links

    I'm wondering what is best practice, when you have to deal with optional links/containers in html.

    For example: I have a list of elements. Each element has an image field, and a Url-picker field. The Url-picker value is optional.

    So I loop through the elements, to render the html like this:

    foreach (var element in elements) {
        <a href="@element.Link.Url"><img src="@element.Image.Url()"></a>
    }
    

    How can I make the anchor optional?

    I can't do:

    foreach (var element in elements) {
        if (element.Link != null) {
            <a href="@element.Link.Url">
        }
        <img src="@element.Image.Url()">
        if (element.Link != null) {
            </a>
        }
    }
    

    Because then I open an -tag without closing in the same block.

    In Umbraco7 I did this:

    foreach (var element in elements) {
        @Umbraco.If(element.Link != null, "<a href=\"" + element.Link.Url + "\">")
        <img src="@element.Image.Url()">
        @Umbraco.If(element.Link != null, "</a>")
    }
    

    But the UmbracoHelper doesn't seem to have an 'if' function anymore.

    What's the best solution for this problem?

  • Marc Goodson 2157 posts 14434 karma points MVP 9x c-trib
    Jun 20, 2022 @ 10:19
    Marc Goodson
    100

    Hi Jeroen

    Number of ways you could look at this...

    You could create a razor helper to write out the image bit eg

    @{
    void DisplayLovelyImage(IPublishedContent image, string altText){
    <img src="@image.Url" alt="@altText" />
    }
    }
    

    and then in your foreach have:

    @if (element.Link != null)
    {
       <a href="@element.Link.Url">
        @{ DisplayLovelyImage(element.Image, element.Image.Name); }
      </a>
    }
    else
    {
      @{ DisplayLovelyImage(element.Image, element.Image.Name); }
    }
    

    It's also not a bad idea to have a ViewComponent responsible for rendering all your img / picture tags from your razor, so 'one place' to update the logic around the displaying of images in a consistent way, eg if you want to provide responsive srcsets etc - then your DisplayLovelyImage method would be:

    @await Component.InvokeAsync("DisplayLovelyImage", new { image = element.Image, width = 900, height = 0, cssClassName = "scale" })
    

    regards

    Marc

  • Jeroen Oostwouder 104 posts 300 karma points
    Jun 21, 2022 @ 07:45
    Jeroen Oostwouder
    0

    That's a nice way indeed. I'm still not too familiar with components, but I might give that a try too.

    Thank you.

  • Marc Goodson 2157 posts 14434 karma points MVP 9x c-trib
    Jun 21, 2022 @ 07:54
    Marc Goodson
    0

    Hi Jeroen

    This is a good intro: https://docs.microsoft.com/en-us/aspnet/core/mvc/views/view-components?view=aspnetcore-6.0#add-a-viewcomponent-class

    With ViewComponents, there are two parts, the 'code' and the 'view'

    You create a class that inherits from ViewComponent, so for example, we tend to use Slimsy a lot on sites, and so this ViewComponent builds up different variations of the Url, low quality image etc for lazyish loading

    public class ResponsiveImageViewComponent : ViewComponent
        {   
                public async Task<IViewComponentResult> InvokeAsync(MediaWithCrops image, UrlHelper urlHelper, int width, int height, string cssClassName = "")
                {
                    var imageModel = new ResponsiveImageViewModel();
    
                    if (image != null)
                    {
                        string defaultMimeType;
                        var umbracoExtension = image.Value<string>(Constants.Conventions.Media.Extension);
                        var defaultFormat = umbracoExtension;
    
                        switch (umbracoExtension)
                        {
                            case "jpg":
                                defaultMimeType = "image/jpeg";
                                break;
                            case "png":
                                defaultMimeType = "image/png";
                                break;
                            case "gif":
                                defaultMimeType = "image/gif";
                                break;
                            default:
                                defaultMimeType = "image/jpeg";
                                defaultFormat = "jpg";
                                break;
                        }
    
                        var lqipWidth = (int)Math.Round((decimal)width / 2);
                        var lqipHeight = (int)Math.Round((decimal)height / 2);
    
                        var imgSrcSet = urlHelper.GetSrcSetUrls(image, width, height, outputFormat: defaultFormat);
                        var imgSrc = SlimsyExtensions.GetCropUrl(image, width, height, furtherOptions: "&format=" + defaultFormat);
    
                        // ** Using half width/height for LQIP to reduce filesize to a minimum, CSS must oversize the images **
                        var imgLqip = SlimsyExtensions.GetCropUrl(image, lqipWidth, lqipHeight, quality: 20, furtherOptions: "&format=" + defaultFormat);
    
                        //Image Model Stuff
                        imageModel.DefaultSrcSetUrl = imgSrcSet;
                        imageModel.Id = image.Id;
                        imageModel.Url = imgSrc;
                        imageModel.CssClass = cssClassName;
                        imageModel.LqipUrl = imgLqip;
                        imageModel.AltText = image.Name;
                    }
    
    
                    return View("ResponsiveImage", imageModel);
                }
            }
    

    Then you create a corresponding View in /Views/Components/ResponsiveImage/ResponsiveImage.cshtml

    Which would then write out the img tag

    @model ResponsiveImageViewModel
    @{
        if (Model != null)
        {
            var cssClass = "lazyload";
            if (!string.IsNullOrEmpty(Model.CssClass))
            {
                cssClass += $" {Model.CssClass}";
            }
    
    
            <picture>
                <!--[if IE 9]><video style="display: none"><![endif]-->
                <source data-srcset="@Model.DefaultSrcSetUrl" srcset="@Model.LqipUrl" type="@Model.MimeType" data-sizes="auto" />
                <!--[if IE 9]></video><![endif]-->
                <img src="@Model.LqipUrl"
                     data-src="@Model.Url"
                     class="@cssClass"
                     data-sizes="auto"
                     alt="@Model.AltText" />
            </picture>
        }
    }
    

    if that gives you the idea!

    regards

    marc

  • This forum is in read-only mode while we transition to the new forum.

    You can continue this topic on the new forum by tapping the "Continue discussion" link below.

Please Sign in or register to post replies