Copied to clipboard

Flag this post as spam?

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


  • Daniel Gillett 72 posts 149 karma points
    Mar 14, 2020 @ 13:14
    Daniel Gillett
    0

    Help with Linq Join Query

    Hello,

    I really need some help with this, please.

    I have a Model called CategoryMenu. It's a checkbox list which gives an IEnumerable string

    I'm using the same DataType but used inside a Portfolio model.

    I am now trying to render this in a parial view and need to Join these lists to get the sequence number from the Category menu, but I'm getting errors no matter what I try.

    Here are some code snippets...

    //IEnumerable list
    var categories = Model.PortfolioCategoryMenu.Select((name, i) => new { name, i });
    

    // My portfolio IEnumerable list

    foreach (var items in portfolio.PortfolioCategories.Select((name, i) => new { name, i }))
                   {
                       var cat = from category in categories 
                                 join portfolioName in items on category.name equals portfolioName.name
                                 select new { portName = portfolioName, CategoryNumber = category.i };
    

    The errors says, "IEnumerable " does not contain a definition for Join and the best extension method overload requires a receiver of type HtmlHelper

    here is the entire partial...

    @inherits Umbraco.Web.Mvc.UmbracoViewPage<Home>
    @{
        // https://www.tutorialsteacher.com/codeeditor?cid=cs-DoAglF
        // https://www.tutorialsteacher.com/linq/linq-joining-operator-join
        var categories = Model.PortfolioCategoryMenu != null && Model.PortfolioCategoryMenu.Any() ? Model.PortfolioCategoryMenu.Select((name, i) => new { name, i }) : null;
        var portfolioItems = Model.Portfolio != null && Model.Portfolio.Any() ? Model.Portfolio : null;
    }
    <div id="portfolio" class="section lb">
        <div class="container">
            <div class="section-title text-left">
                <h3>@Model.PortfolioTitle</h3>
                <p>@Model.PortfolioSummary</p>
            </div>
           @if (categories != null)
            {
            <div class="gallery-menu row">
                <div class="col-md-12">
                    <div class="button-group filter-button-group text-left">
                        <button class="active" data-filter="*">All</button>
                        @foreach (var item in categories){
                        <button data-filter=".gal_@(item.i)">@item.name</button>
                        }
                    </div>
                </div>
            </div>
            }
            <div class="gallery-list row">
           @if (portfolioItems != null)
           {
               foreach (var portfolio in portfolioItems)
               {
                   var image = portfolio.PortfolioImage != null ? portfolio.PortfolioImage : null;
                   var imageUrl = image != null ? Umbraco.Media(image.Id).Url : string.Empty;
    
                   foreach (var items in portfolio.PortfolioCategories.Select((name, i) => new { name, i }))
                   {
                       var cat = from category in categories
                                 join portfolioName in items on category.name equals portfolioName.name
                                 select new { portName = portfolioName, CategoryNumber = category.i };
    
                   <div class="col-md-4 col-sm-6 gallery-grid @(string.Join("gal_", cat, 0))">
                        <div class="gallery-single fix">
                            <img src="@imageUrl" class="img-fluid" alt="@(image != null ? image.Name : string.Empty)">
                            <div class="img-overlay">
                                <a href="@imageUrl" data-rel="prettyPhoto[gal]" class="hoverbutton global-radius"><i class="fa fa-picture-o"></i></a>
                            </div>
                        </div>
                   </div>
                   }
               }
           }
            </div>
        </div>
    </div>
    

    Really need help on this.

    Cheers, Daniel

  • Marc Goodson 2126 posts 14217 karma points MVP 8x c-trib
    Mar 15, 2020 @ 20:10
    Marc Goodson
    0

    Hi Daniel

    I can't quite get my head around, what you are trying to achieve, but it looks like you need to 'retrieve' the appropriate matching category from the selection of categories, for each of the selected portfolio categories, in order to determine the 'order' number of the sequence of that category in the original list, for the filtering to work...

    Anyway... could

               var cat = from category in categories
                             join portfolioName in items on category.name equals portfolioName.name
                             select new { portName = portfolioName, CategoryNumber = category.i };
    

    become...

               var cat = categories.FirstOrDefault(f=>f.name == items.name);
    

    or

    var indexPosition = categories.FindIndex(f=>f.name==items.name)
    

    If I'm totally misunderstanding and you do need to JOIN things together using Linq... then I'm thinking your items variable in the 'foreach' isn't an IEnumerable of anonymous objects, name, i - it is a single instance of the anonymous object 'name, i' and that's why you get the error regarding the JOIN operation...

    so outside the foreach loop something like this would I think join the lists together:

        foreach (var portfolio in portfolioItems)
                   {
                       var image = portfolio.PortfolioImage != null ? portfolio.PortfolioImage : null;
                       var imageUrl = image != null ? Umbraco.Media(image.Id).Url : string.Empty;
                       var portfolioCategories = portfolio.PortfolioCategories.Select((name, i) => new { name, i });
    
                       var cat = from category in categories
                                     join portfolioName in portfolioCategories on category.name equals portfolioName.name
                                     select new { portName = portfolioName, CategoryNumber = category.i };
    

    It gets very confusing with anonymous objects! as I write out the suggestion, it also dawns on me more what you are trying to do... so apologies if this is wide of the mark of your intention!

    The other option would be to use just the names of the categories as the filter.. assuming they are unique, there is a handly method that I tend to use here, that strips out any bad chars or spaces etc... which is used by Umbraco when generating Url segments...

    var fairlyNiceSafeStringId = "some string".ToUrlSegment();
    

    Anyway hopefully this gives you some inspiration...

    regards

    Marc

  • Daniel Gillett 72 posts 149 karma points
    Mar 16, 2020 @ 10:24
    Daniel Gillett
    0

    Oh Wow! Marc!

    Thank you SO much for taking a look at this with me. I was beginning to think no one would try and help on this one. :-O

    I'm attaching the screen-shots to give you some mass on this problem, but the short story is that I have an List of categories using the Checkbox List DataType which is just a list of strings that have been selected.

    I'm using the same DataType inside a Nested Element as part of a Porfolio. The portfolio is "gallery of images" which belong to one or more of the categories.

    enter image description here

    The Content Section looks like this...

    enter image description here

    The reason for needing the index from the Checkbox List is because, in the HTML, the gallery is filtered so I need to match the Categories with the Portfolio Categories. ...that's why I created the int on each of the Category items. I want to select any of the portfolio items which are in the Categories so I thought a Join would be best so my Portfolio Categories have the correct int from the Categories list.

    here is the html/razor and the rendered page.

    @{
        var categories = Model.PortfolioCategoryMenu != null && Model.PortfolioCategoryMenu.Any() ? Model.PortfolioCategoryMenu.Select((name, i) => new { name, i }) : null;
        var portfolioItems = Model.Portfolio != null && Model.Portfolio.Any() ? Model.Portfolio : null;
    }
    <div id="portfolio" class="section lb">
        <div class="container">
            <div class="section-title text-left">
                <h3>@Model.PortfolioTitle</h3>
                <p>@Model.PortfolioSummary</p>
            </div>
            @if (categories != null)
            {
                <div class="gallery-menu row">
                    <div class="col-md-12">
                        <div class="button-group filter-button-group text-left">
                            <button class="active" data-filter="*">All</button>
                            @foreach (var item in categories)
                            {
                                <button data-filter=".gal_@(item.i)">@item.name</button>
                            }
                        </div>
                    </div>
                </div>
            }
    
            <div class="gallery-list row">
                <div class="col-md-4 col-sm-6 gallery-grid gal_0 gal_1">
                    <div class="gallery-single fix">
                        <img src="/media/me0byj4h/gallery_img-01.jpg" class="img-fluid" alt="Gallery Img 01">
                        <div class="img-overlay">
                            <a href="/media/me0byj4h/gallery_img-01.jpg" data-rel="prettyPhoto[gal]" class="hoverbutton global-radius"><i class="fa fa-picture-o"></i></a>
                        </div>
                    </div>
                </div>
                <div class="col-md-4 col-sm-6 gallery-grid gal_1 gal_2">
                    <div class="gallery-single fix">
                        <img src="/media/nohd4nt1/gallery_img-02.jpg" class="img-fluid" alt="Gallery Img 02">
                        <div class="img-overlay">
                            <a href="/media/nohd4nt1/gallery_img-02.jpg" data-rel="prettyPhoto[gal]" class="hoverbutton global-radius"><i class="fa fa-picture-o"></i></a>
                        </div>
                    </div>
                </div>
                <div class="col-md-4 col-sm-6 gallery-grid gal_0 gal_2">
                    <div class="gallery-single fix">
                        <img src="/media/m35ddgmp/gallery_img-03.jpg" class="img-fluid" alt="Gallery Img 03">
                        <div class="img-overlay">
                            <a href="/media/m35ddgmp/gallery_img-03.jpg" data-rel="prettyPhoto[gal]" class="hoverbutton global-radius"><i class="fa fa-picture-o"></i></a>
                        </div>
                    </div>
                </div>
    

    [... and so on]

    Each portfolio item has a class gal0 gal2 depending on what Categories the gallery belongs to. Syncing the Categories with the Portfolio Categories is important so the gallery can filter correctly.

    enter image description here

    The problem seems two-fold: 1) Taking only the Portfolios that are in the Categories List and 2) usingor attaching the index/int of the Categories onto the Portfolio Categories.

    Thank you so, so much for taking a look at this. It is the last part of this page this is holding me up from completing it.

    Best wishes, Daniel

  • Daniel Gillett 72 posts 149 karma points
    Mar 16, 2020 @ 10:47
    Daniel Gillett
    0

    I should add as well that...

    I cannot seem to do a join properly because the Portfolio Categories are inside of the Portfolio so I try and use a predicate to try and assign a value to the list of string... With your help, this is the best I've been able to come up with (but also doesn't work)

            @foreach (var porfolio in portfolioItems
                .Where(p => p.PortfolioCategories.Select((name, i) => new { name, i })
                .Where(
                    from category in categories
                    join portfolioName in p.PortfolioCategories
                    on category.name equals portfolioName
                    select new { portName = portfolioName, categoryNumber = category.i })))
            {
                <div class="col-md-4 col-sm-6 gallery-grid gal_0 gal_1">
                    <div class="gallery-single fix">
                        <img src="/media/me0byj4h/gallery_img-01.jpg" class="img-fluid" alt="Gallery Img 01">
                        <div class="img-overlay">
                            <a href="/media/me0byj4h/gallery_img-01.jpg" data-rel="prettyPhoto[gal]" class="hoverbutton global-radius"><i class="fa fa-picture-o"></i></a>
                        </div>
                    </div>
                </div>
            }
    

    I can't seem to assign the .select((value, i) => new { value, i}) inside of the portfolioItems to get the portfolio item categories to use in the Join. ;-(

    Really hoping you can help!

    Best wishes, Daniel

  • Daniel Gillett 72 posts 149 karma points
    Mar 16, 2020 @ 10:58
    Daniel Gillett
    0

    here is an image of the razor which helps to see where I think I'm stuck...

    enter image description here

    I hope this makes things even clearer.

    Thanks very much!

    Best, Daniel

  • Marc Goodson 2126 posts 14217 karma points MVP 8x c-trib
    Mar 16, 2020 @ 20:19
    Marc Goodson
    1

    Hi Daniel

    What you are trying to do is I think what I understood by the bottom of my explaination, but then didn't have the energy to go back and change what I'd written ;-(

    Anyway... I think you are really close!!

    Each nested item is a portfolio and each portfolio has the checkbox and you want to write out each portfolio item once with the css class for each category the portfolio is in, in the outer div then your magic front end filtering can, show and hide portfolio items depending on the css classes they have...

    so if you persist with your integer approach:

     @foreach (var porfolio in portfolioItems){
    
              var portfolioCategoriesForThisPortfolio = portfolio.PortfolioCategories.Select((name, i) => new { name, i });
    
             var portfolioCategoriesWithCatId = from category in categories
                                     join portfolioName in portfolioCategoriesForThisPortfolio on category.name equals portfolioName.name
                                     select new { portName = portfolioName, CategoryNumber = category.i };
    
             string filterCssClasses = "";
             foreach (var portCatWithCatId in portfolioCategoriesWithCatId){
                          filterCssClasses = filterCssClasses  + "gal_" + portCatWithCatId.CategoryNumber + " ";
              }
    
                    <div class="col-md-4 col-sm-6 gallery-grid @filterCssClasses">
                        <div class="gallery-single fix">
                            <img src="/media/me0byj4h/gallery_img-01.jpg" class="img-fluid" alt="Gallery Img 01">
                            <div class="img-overlay">
                                <a href="/media/me0byj4h/gallery_img-01.jpg" data-rel="prettyPhoto[gal]" class="hoverbutton global-radius"><i class="fa fa-picture-o"></i></a>
                            </div>
                        </div>
                    </div>
    

    }

    but equally you could forget the whole integer thing, and just use the name of the categories?

      @foreach (var item in categories){
                    <button data-filter=".gal_@(item.name.ToUrlSegment())">@item.name</button>
                    }
    

    would produce gal_web-design as the filtering css class, which would save all the faffing with the join and the i integer...

    regards

    Marc

  • Daniel Gillett 72 posts 149 karma points
    Mar 17, 2020 @ 20:50
    Daniel Gillett
    0

    Hi Marc!

    Thank you sooo much for your time. I will look at your fix and reply back tomorrow. Fingers crossed!

    Thank you so much for helping!

    Till tomrrow!

    Daniel

  • Daniel Gillett 72 posts 149 karma points
    Mar 18, 2020 @ 12:50
    Daniel Gillett
    0

    Marc!

    It worked! Thank you sooo much! I was really stuck on this one!

    Thank you so much for your time and effort. I'm over the moon! ...gonna take a moment. lol

    Best wishes,

    Daniel

  • Marc Goodson 2126 posts 14217 karma points MVP 8x c-trib
    Mar 18, 2020 @ 19:32
    Marc Goodson
    0

    Hi Daniel

    Great to hear!

    If you are anything like me you'll have spent the whole day, just clicking on and off different filters, and revelling in the fact it works!

    regards

    Marc

  • Daniel Gillett 72 posts 149 karma points
    Mar 19, 2020 @ 01:54
    Daniel Gillett
    0

    haha I did! My hands through up into the air and shouted YES! Then I had to walk around my villa breathing out a lot of relief. Then I sat down and played around watching it work! hahaha

    (If you don't mind me asking... How do I know if I've got a bug with Umbraco or if it's something I'm doing wrong? I made a post the other day about updating a page, saving, and then using the preview button, but the links for those pages won't work whilst in preview. No one has commented on it and I'm not sure where to go with it. )

    Thanks so much again!

    Best, Daniel

  • Marc Goodson 2126 posts 14217 karma points MVP 8x c-trib
    Mar 19, 2020 @ 08:32
    Marc Goodson
    0

    Hi Daniel,

    I've replied on the 'other post' :-)

    regards

    Marc

Please Sign in or register to post replies

Write your reply to:

Draft