Copied to clipboard

Flag this post as spam?

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


  • Tara Pattenden 44 posts 205 karma points
    Sep 06, 2020 @ 04:29
    Tara Pattenden
    0

    Trouble getting if statement to work

    Hi!

    I'm pretty new to this and working with a site in Umbraco v7 that already exists.

    I am trying to display the word Free when the property alias freeProgram is true.

    FreeProgram is already set up with a checkbox on doc type program

    It is being used to create filters and it is referenced in a few places

    This content is created from a partial template - here's the code (including on of many attempts to create content if freeProgram is true)

    @model PerformanceSpace.Models.VM_Cards
    

    @{ var imgurl = String.Format("{0}?width={1}&height={2}&mode=crop", Model.imgUrl, Model.doubleCrop ? 700 : 400, Model.doubleCrop ? 400 : Model.smallCard ? 400 : 496); }

        <div class="card-image">
            @if (!String.IsNullOrEmpty(Model.imgUrl))
            {
                <img src="@imgurl" alt="@Model.imgAlt">}
        </div>
    
    
        @if (Model.smallCard)
        {
            <div class="py16 px16">
                <h3 class="h6 mb0 card--title" style="color:@Model.txtColour !important">
                    @Model.title
                </h3>
            </div> }
    
        else
        {
            <h3 class="h6 mb0 card__heading">
                <span class="text--hl card--title" style="background-color:@Model.colour;">
                    @Model.title
                </span>
            </h3>}
    
        <div class="card__date mt16" style="color:@Model.txtColour !important">
            <small>@Model.subTitle</small>
        </div>
    </a>
    
    @{
        if (!Model.Value<bool>("freeProgram"))
        {
            <p>The Checkbox is not checked!</p>
        }
    }
    

    Currently this prevents the articles from opening. Tracing things back (remember i am a total noob at this)

    I have tried a lot of different syntax and copied if statements that are used in a controller to get the same content

    @if (model.freeProgram)
    {
        <div>free</div>
    }
    

    here is the model that contains the VMCards class

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Runtime.CompilerServices;
    using System.Web;
    using Umbraco.Web;
    using Umbraco.Web.PublishedContentModels;
    
    namespace PerformanceSpace.Models
    {
        public class VM_RelatedCards
        {
            public string   areaTitle       { get; set; }
            public bool     pastOnly        { get; set; }
            public string   pastURL         { get; set; }
            public string   currentURL      { get; set; }
            public int      displayLimit    { get; set; }
            public string   card1Colour     { get; set; }
            public string   cardTextColour  { get; set; }
            public string   card2Colour     { get; set; }
            public string   card3Colour     { get; set; }
            public bool     altSizes        { get; set; }
            public bool     doubleSizeFirst { get; set; }
            public bool     noCurrentPast   { get; set; }
            public bool     showline        { get; set; }
    
            public List<VM_Cards> cards { get; set; }
    
    
            public VM_RelatedCards()
            {
                init();
            }
    
            public VM_RelatedCards(IEnumerable<Artist> inputList)
            {
                init(inputList);
            }
    
            public VM_RelatedCards(IEnumerable<Program> inputList)
            {
                init(inputList);
            }
    
            public VM_RelatedCards(IEnumerable<Umbraco.Core.Models.IPublishedContent> inputList)
            {
                init(inputList);
            }
    
            private void init(IEnumerable<Umbraco.Core.Models.IPublishedContent> input = null, bool sizeAlternation = false)
            {
                pastOnly        = true;
                displayLimit    = 3;
                cards           = new List<VM_Cards>();
                altSizes        = sizeAlternation;
                doubleSizeFirst = false;
                noCurrentPast   = false;
                showline        = true;
    
                if (input != null && input.Count() > 0) {
                    var T = input.First().GetType();
    
                    if (T == typeof(Artist)) {
                        foreach (Artist item in input) {
                            cards.Add(new VM_Cards(item)); } }
                    else if(T == typeof(Program)) {
                        foreach (Program item in input) { 
                            cards.Add(new VM_Cards(item)); } }
                    else if(T== typeof(BlogPost)) {
                        foreach(BlogPost item in input) {
                            cards.Add(new VM_Cards(item)); } } } 
            }
    
            private void init(IEnumerable<Artist> inputList)
            {
                init();
    
                for (int count = 0; count < inputList.Count(); count++) {
                    var item = inputList.ElementAt(count);
    
                    cards.Add(new VM_Cards(item)); }
            }
    
            private void init(IEnumerable<Program> inputList)
            {
                init();
    
                foreach (var item in inputList) {
                    cards.Add(new VM_Cards(item)); }
            }
        }
    
    
        public class VM_Cards
        {
            public string colour    { get; set; }
            public string txtColour { get; set; }
            public string title     { get; set; }
            public string subTitle  { get; set; }
            public string imgUrl    { get; set; }
            public string imgAlt    { get; set; }
            public string linkURL   { get; set; }
            public bool   smallCard { get; set; }
            public string cellClass { get; set; }
            public bool doubleCrop  { get; set; }
            public bool freeProgram  { get; set; }
            public bool onlineProgram { get; set; }
    
            public VM_Cards()
            {
                smallCard   = false;
                doubleCrop  = false;
                freeProgram = false;
    
            }
    
            public VM_Cards(Artist input, bool small = false, string textColour = null)
            {
                this.colour = input.HeadingColours.GetPropertyValue<string>("backgroundColour");
                txtColour   = textColour ?? gFuncs.textColourFromBG(colour);
                title       = input.FirstName + " " + input.LastName;
                subTitle    = input.HeadingText;
                imgUrl      = input.BiographyImage != null ? input.BiographyImage.Url : input.HeadingHeroImage.Url;
                imgAlt      = input.BiographyImage == null ? input.HeadingHeroImage.Name : input.BiographyImage.Name;
                smallCard   = small;
                cellClass   = "mb32";
                linkURL     = input.Url;
                doubleCrop  = false;
            }
    
            public VM_Cards(Program input, bool small = false, string textColour = null)
            {
                string format   = (input.ProgramDates != null) ? ((List<Umbraco.Core.Models.IPublishedContent>)input.ProgramDates).ToMultiDate().MaxDate().Date <= DateTime.Now.AddMonths(-8) ? "MMM d, yyyy" : "MMM d" : null;
                this.colour     = input.HeadingColours.GetPropertyValue<string>("backgroundColour");
                title           = input.Title;
                subTitle        = input.ProgramDates != null ? input.ProgramDates.ToList().ToMultiDate().MinDate().ToString(format) + ((input.ProgramDates.Count() > 1) ? " - " + input.ProgramDates.ToList().ToMultiDate().MaxDate().ToString(format) : "") : "";
                imgUrl          = input.HeadingHeroImage.Url;
                linkURL         = input.Url;
                smallCard       = small;
                txtColour       = textColour ?? gFuncs.textColourFromBG(colour);
                cellClass       = "mb32";
                doubleCrop      = false;
                freeProgram     = "free";
            }
    
            public VM_Cards(program input, bool small = false) 
            {
                string format   = input.dateFinish.Year < DateTime.Now.Year ? "MMM d, yyyy" : "MMM d";
                colour          = input.bgColour;
                txtColour       = gFuncs.textColourFromBG(input.fgColour);
                title           = input.heading;
    
    
                if (input.dateStart == new DateTime())
                {
                    subTitle = "TBC";
                }
                else
                {
                    subTitle = input.dateStart.ToString(format) + (input.dateStart.Date != input.dateFinish.Date ? " - " + input.dateFinish.ToString(format) : null);
                }
                imgUrl          = input.img;
                linkURL         = input.url;
                smallCard       = small;
                cellClass       = "mb32";
                doubleCrop      = false;
                freeProgram = "free";
            }
    
            public VM_Cards(BlogPost input, bool dblCrop = false)
            {
                //string format = "dddd MMMM dd yyyy";
                title           = input.Title;
                //subTitle      = input.CreateDate.ToString(format);
                imgUrl          = input.FeatureImage.Url;
                imgAlt          = input.FeatureImage.Name;
                linkURL         = input.Url;
                colour          = input.CardColour as string;
                txtColour       = gFuncs.textColourFromBG(colour);
                doubleCrop      = dblCrop;
            }
        }
    }
    

    So from my understanding this appears to be a model that is not created from making a doctype - there are no doctypes called VM

    The freeProgam property alias is set originally in the Property model. Here is the property model header and related code.

                //------------------------------------------------------------------------------
    // <auto-generated>
    //   This code was generated by a tool.
    //
    //    Umbraco.ModelsBuilder v3.0.10.102
    //
    //   Changes to this file will be lost if the code is regenerated.
    // </auto-generated>
    //------------------------------------------------------------------------------
    
    using System;
    using System.Collections.Generic;
    using System.Linq.Expressions;
    using System.Web;
    using Umbraco.Core.Models;
    using Umbraco.Core.Models.PublishedContent;
    using Umbraco.Web;
    using Umbraco.ModelsBuilder;
    using Umbraco.ModelsBuilder.Umbraco;
    
    namespace Umbraco.Web.PublishedContentModels
    {
    .
    .
    .
    
    
    ///<summary>
            /// Free Program: Is this a free program?
            ///</summary>
            [ImplementPropertyType("freeProgram")]
            public bool FreeProgram
            {
                get { return this.GetPropertyValue<bool>("freeProgram"); }
            }
    

    I think I don't understand the relationship between the model created with modelsbuilder and how to use them in the other namespace (I'm not even really sure what a namespace is but I'm guessing it separates them somehow)

    So what I would like to do is to add the word free in the items that have that property alias set. Where am I going wrong? Thanks so much in advance. I'm on a tight deadline as I was told this was a wordpress site and now they can't find anyone else to do it and the site goes live in two days... ergh....

    **update (still need help)

    more of an update. I can get the word free to hide or show on the program page. using this code

    @{ if (!Model.GetPropertyValue

    Not free

    } else {

    free

    } }

    I'm just not sure how to reference it on the other namespace....

  • Marc Goodson 2144 posts 14347 karma points MVP 8x c-trib
    Sep 06, 2020 @ 20:30
    Marc Goodson
    100

    Hi Tara

    I'm not super sure what's going on here, some of your examples haven't displayed correctly but it does like you've stumbled across a complicated implementation.

    Normally in an Umbraco View(Template) or PartialView the underlying 'Model' that the View is expecting to work with is of type RenderModel, which includes a property called Content that is of type IPublishedContent

    So normally in an Umbraco View you can write out any property from the underlying content item, based on its Document Type definition using the alias of the property eg:

    @using UmbracoTemplatePage
    
    <h1>@Model.Content.GetPropertyValue<string>("title")</h1>
    @if (Model.Content.GetPropertyValue<bool>("freeProgram")){
    <h2>It's a Free program!!</h2>
    }
    else {
    <h2>It's not a free program :-(</h2>
    }
    

    But people didn't like typing the ("freeProgram") bit in case they made a 'typo' and so Modelsbuilder was invented!

    With Modelsbuilder turned on in the Web.config file, Umbraco will generate a C# Model for each DocumentType, and the above becomes something more like this:

    @using UmbracoViewPage<MyDocTypeAlias>
    
    <h1>@Model.Title</h1>
    @if (Model.FreeProgram){
    <h2>It's a Free program!!</h2>
    }
    else {
    <h2>It's not a free program :-(</h2>
    }
    

    Which is 'less' to type, but whenever you change your Document Types you'll need to remember to 'regenerate your models' to update them to match (From the Developer section of Umbraco).

    There are also several different modes for running Modelsbuilder in: PureLive where the models are generated in memory, and AppData where they are generated as files in the AppData folder (and need to be compiled and deployed to the site to work), and also DLL mode - where they are compiled into a DLL - the Models are generated under the default 'namespace' - Umbraco.Web.PublishedContentModels and a namespace is just a way of grouping models together and avoiding clashes with other models that might be generated in an application with the same name...

    You've seen the generated Models, for your Document Type - and see that the property for 'FreeProgram' just uses the GetPropertyValue syntax and the alias 'freeProgram' to retrieve the value...

    But you appear to have a further complication here... often the Model generated by Modelsbuilder which is 1-1 with the underlying DocumentType, doesn't cover 'ALL' the properties or things that might want to be written out in the PartialView, perhaps there is a list of latest News Articles to display, or some logic over whether to use the Image or a default Image if one is not picked - and here what developers might choose to do is to create a ViewModel - that is 1-1 with what is required for the View but not necessarily 1-1 with the Document Type... and I'm guessing that's what you have here, given the models are called VM_Cards... it's the ViewModel for writing out Cards.

    Not there isn't an automatic way for Umbraco to know about these ViewModels, and they need to be wired up in Code - and usually this is done via an MVC Controller - Umbraco has this convention that if you create an MVC Controller that inherits RenderMvcController and name the controller DocumentTypeAliasController all requests for any content based on that Document Type will go through the Custom MVC Controller and it's usually here that someone might hijack the normal Umbraco request and create and populate a new ViewModel to use in a View.

    Which makes it a bit convoluted if you 'just' want to add a new property!

    So somewhere in your site, in a Controller or in a template view the ViewModel is created with a new keyword

    eg

    var relatedCards = new VM_RelatedCards(somethingHere);
    

    and in particular there is a 'constructor' for VM_RelatedCards that takes a list of Programs to use as the source for creating the related cards:

       public VM_RelatedCards(IEnumerable<Program> inputList)
            {
                init(inputList);
            }
    

    and I'm guessing that Program IS a model generated by Modelsbuilder based on the Program document type - so if your models have been regenerated since you added the FreeProgram checkbox, each of these Program objects will contain the FreeProgram true/false boolean value.

    Now the constructor here calls init(inputList) method and passes through the list of Program objects to construct the ViewModel... funnily it knows at this stage what type of object it is... but doesn't let on to the init method which has to 'guess' which type of object it is, by looking at the first item in the list's type:

      else if(T == typeof(Program)) {
                        foreach (Program item in input) { 
                            cards.Add(new VM_Cards(item)); } }
    

    So you can see now for each Program, a new VMCards model is being created, and each Program item generated by Modelsbuilder is being passed in to the VMCards model constructor, which is implemented like so here:

       public VM_Cards(Program input, bool small = false, string textColour = null)
        {
            string format   = (input.ProgramDates != null) ? ((List<Umbraco.Core.Models.IPublishedContent>)input.ProgramDates).ToMultiDate().MaxDate().Date <= DateTime.Now.AddMonths(-8) ? "MMM d, yyyy" : "MMM d" : null;
            this.colour     = input.HeadingColours.GetPropertyValue<string>("backgroundColour");
            title           = input.Title;
            subTitle        = input.ProgramDates != null ? input.ProgramDates.ToList().ToMultiDate().MinDate().ToString(format) + ((input.ProgramDates.Count() > 1) ? " - " + input.ProgramDates.ToList().ToMultiDate().MaxDate().ToString(format) : "") : "";
            imgUrl          = input.HeadingHeroImage.Url;
            linkURL         = input.Url;
            smallCard       = small;
            txtColour       = textColour ?? gFuncs.textColourFromBG(colour);
            cellClass       = "mb32";
            doubleCrop      = false;
            freeProgram     = "free";
        }
    

    Now your VM_Cards model does have a FreeProgram property of type 'bool

     public bool freeProgram  { get; set; }
    

    but you can see in your constructor for VM_Cards that takes in a Program object, that the property freeProgram is being set to be a string value of "free"...

    ... so apologies for the long winded explanation but I think, this just needs to become...

       public VM_Cards(Program input, bool small = false, string textColour = null)
        {
            string format   = (input.ProgramDates != null) ? ((List<Umbraco.Core.Models.IPublishedContent>)input.ProgramDates).ToMultiDate().MaxDate().Date <= DateTime.Now.AddMonths(-8) ? "MMM d, yyyy" : "MMM d" : null;
            this.colour     = input.HeadingColours.GetPropertyValue<string>("backgroundColour");
            title           = input.Title;
            subTitle        = input.ProgramDates != null ? input.ProgramDates.ToList().ToMultiDate().MinDate().ToString(format) + ((input.ProgramDates.Count() > 1) ? " - " + input.ProgramDates.ToList().ToMultiDate().MaxDate().ToString(format) : "") : "";
            imgUrl          = input.HeadingHeroImage.Url;
            linkURL         = input.Url;
            smallCard       = small;
            txtColour       = textColour ?? gFuncs.textColourFromBG(colour);
            cellClass       = "mb32";
            doubleCrop      = false;
            freeProgram     = input.FreeProgram;
        }
    

    But possible this is the very first thing you tried and it didn't work because the Modelsbuilder models weren't regenerated and so this gave an error?

    With this set wherever the VM_Cards object is used you should be able to check the value using

    @if (Model.freeProgram){
    <h1>yey, it's free!</h1>
    }
    

    Anyway hope this helps demystify your model shenanigans, (and also Umbraco doesn't need to be this complicated!!!)

    regards

    Marc

  • Tara Pattenden 44 posts 205 karma points
    Sep 07, 2020 @ 01:40
    Tara Pattenden
    0

    I've solved it!!! all the code has been fine all along. Just spoke to the developer and I have to build the project (I had no idea) in Visual Studio by pressing ctrl + shift + b or none of the changes I have made (eg adding free program to the model)

    Is that standard? I've never seen it mentioned in any umbraco docs. The dev said it was standard umbraco

  • Marc Goodson 2144 posts 14347 karma points MVP 8x c-trib
    Sep 07, 2020 @ 06:15
    Marc Goodson
    0

    Hi Tara

    Not so much 'standard' Umbraco but, 'standard' C#/.Net.

    So yes, the Models generated by ModelsBuilder are created as files, and need to be compiled- but also those ViewModels, or anything that is C# code will also need to be compiled, to see any changes.

    Rebuilding the Visual Studio solution will trigger that compiliation, but you can create code in a special app_code folder and have the compilation occur automatically.

    Any changes in Views, eg Html or Razor code do not need to be compiled.

    The benefits of compiling are that you should see any coding errors reported before you deploy your site, eg

    freeProgram     = "free";
    

    Would have thrown an error during compilation because freeProgram is a boolean and not a string.

    It's one of the reasons why people choose the ViewModel approach because more implementation logic is compiled, and so any typos etc are more likely to be found early. and you can write 'tests' against the code etc.

    But it isn't the 'only way'

    Anyway, I'm glad you got it working! - and you can mark your answer as the answer! :-P

    regards

    Marc

  • Tara Pattenden 44 posts 205 karma points
    Sep 06, 2020 @ 23:02
    Tara Pattenden
    0

    Thanks you so incredibly much for this detailed explanation!!! it's so helpful and I am understanding a lot more from it.

    I had not tried

    freeProgram     = input.FreeProgram;
    

    so I will try that - I had put the "free" in there just copying the way the other booleans were done

    I'll give that a go now and see if I can get any info

    Thanks!

  • Tara Pattenden 44 posts 205 karma points
    Sep 06, 2020 @ 23:45
    Tara Pattenden
    0

    Hi,

    I tried your suggestions and again it just returns no results as soon as I add

    @if (Model.freeProgram){
    <h1>yey, it's free!</h1>
    }
    

    to the render card page.

    Also I didn't mention this but I manually added the public bool freeProgram { get; set; } to the VM_Cards Model, is there somewhere else it should be added. I also have two models folders and both get used, one in the models folder in the root, which contains this VM cards and another in the AppData folder which seems to contain generated models.

    I think there is something in the way this installation has been set up. I'm about to talk to the previous developer to see if they can point me in the right direction.

Please Sign in or register to post replies

Write your reply to:

Draft