Developer forum

Forum » Development » Item Types and view models question

Item Types and view models question

Karol Barkowski
Reply

Hi,

I'm trying to figure out how to deal with custom item types and there's one thing that seems really, really weird.
Let's say that I have this simple type defined as a code-first item. All the permissions are set up too in admin, I have a layout for it and I can add it to the page. So far so good.

    [Item("Hero Component", "")]
    [Category("MyAwesomeShop")]
    [ModuleAttachmentRule(true), StructureRule(StructureContextType.Paragraphs)]
    public class HeroModel : ItemEntry
    {
        [Name("Title")]
        [Required]
        public string Title { get; set; }
 
        [Name("Call to action link")]
        [Link]
        [Required]
        public string CTALink { get; set; }
    }

 

Layout file is the werid part. And how I can get the actual values of that model class specifically.
So for example, for this oversimplified example, it should look like this, right?

@inherits Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.ParagraphViewModel>
 
<div class="hero">
    <h1>@Model.Item.GetString("Title")</h1>
    <a href="@Model.Item.GetLink("CTALink").Url">CTA</a>
</div>

 

Now, am I missing something here? How is this possible that I am defining a specific model class and then on the template I don't have any access to that type and I need to use a bunch of magic strings and methods to get properly types values? So goodbye intellisense, goodbye refactorings, goodbye "find usages" for my properties. But welcome magic strings, typos, casting errors and maintenance hell since everything is accessed by a string?
Is this really the correct approach?  Is there a way to get an instance of the actual HeroModel class on the template so I could write something like @model.CTALink?
 

 


Replies

 
Nicolai Pedersen Dynamicweb Employee
Nicolai Pedersen
Reply
This post has been marked as an answer

Hi Karol

In Dynamicweb there is a difference between viewmodels (which you have in templates) and the models used CRUD operations. Long history of the system that made it that way since Items existed first, then code-first items and later viewmodels in templates.

You can however get your item model in the template like this:

@inherits Dynamicweb.Rendering.ViewModelTemplate<Dynamicweb.Frontend.ParagraphViewModel>
var myModel = ItemManager.Storage.GetById<HeroModel>(Model.Item.Id);

Find more about working with code first items here:

https://doc.dynamicweb.com/training/training/certifications/t3-platform-developer/t3-platform-developer/3-4-items#5967

Full code first item type: https://doc.dynamicweb.com/apix/api/Dynamicweb.Content.Items.ItemEntry.html

You can also make viewmodels that are typed - by doing like below:

And then change your inherit statement of the template to 

@inherits Dynamicweb.Rendering.ViewModelTemplate<SwiftPosterViewModel>

To create the viewmodel:

[AddInName("MultiPurposeParagraphInfo")]
    public class SwiftPosterViewModel : ParagraphViewModel
    {
        private object _instance;
        public SwiftPosterViewModel()
        {
            //this is initialisation. The model does not have anyting set at this point.
            //Initialize objects, i.e. services, that can be used throughtout the instance - i.e. to get addtional data.
            _instance = new object();

            //This will not work as the header will be overriden later in the initialisation process of this object. Don't try to initialize any properties of the base class.
            base.Header = "Seting the header inside the constructor does not work";
        }

        /// <summary>
        /// Take over default property of the base viewmodel. Suitable to change default behavior
        /// </summary>
        public new string Header
        {
            get
            {
                return $"{base.Header} changed1";
            }
        }

        /// <summary>
        /// Addtional data property available in template. Suitable for additional data
        /// </summary>
        public string NameOrTile
        {
            get
            {
                if (Item.GetRawValue("Title") is object)
                {
                    return Item.GetRawValue("Title").ToString();
                }
                else
                {
                    return $"From nameOrTitle prop: {Header}";
                }
            }
        }

        /// <summary>
        /// Method to call from template using data from the model instance. Suitable for rendering logic
        /// </summary>
        /// <returns></returns>
        public string GetPosterPadding()
        {
            string posterPadding = Item.GetRawValueString("ContentPadding", string.Empty);
            string posterPaddingClass = "px-3";

            switch (posterPadding)
            {
                case "none":
                    posterPaddingClass = " p-3 px-xl-3 py-xl-4";
                    break;
                case "small":
                    posterPaddingClass = " p-3 p-xl-4";
                    break;
                case "large":
                    posterPaddingClass = " p-4 p-xl-5";
                    break;
            }
            return posterPaddingClass;
        }
    }
Votes for this answer: 1
 
Karol Barkowski
Reply

Awesome. Exactly what I needed. Thank you for elaborative response andl links.

 

You must be logged in to post in the forum