7

I have a base model class, NotificationBase, and two derived models, GeneralNotification and ReleaseNotification.

public class NotificationBase
{
        public int Id { get; set; }

        [Required]
    [StringLength(50, ErrorMessage="Title must not exceed 50 characters.")]
    public string Title { get; set; }

    [Required(ErrorMessage="Type is required.")]
    public int TypeId { get; set; }

    [Required(ErrorMessage="Importance is required.")]
    public int ImportanceId { get; set; }

    public DateTime Created {get; set; }

    [Required(ErrorMessage="Start date is required.")]        
    public DateTime StartDate { get; set; }

    [Required(ErrorMessage="End date is required")]
    public DateTime EndDate { get; set; }

    [AllowHtml]
    [Required(ErrorMessage="Details are required")]
    public string Details { get; set; }                

}

public class GeneralNotification : NotificationBase
{
    [Required(ErrorMessage="Message is required.")]
    [StringLength(50, ErrorMessage = "Message must be maximum 50 chararacters long.")]
    public string Message { get; set; } 
}

  public class ReleaseNotification : NotificationBase
{
    [Required(ErrorMessage="Version is required.")]
    public string Version { get; set; }
}

I'm trying to use a single edit view to edit both derived notification types.

This view has a model of type NotificationBase.

The problem is I can't get the added properties of the derived types to be displayed in the edit view. Sending a model of the base type means I lose along the way the extra properties of the derived types.

Is there a workaround, or I just have to make separate views for each derived model ?

brasofilo
  • 25,496
  • 15
  • 91
  • 179
Octavian Epure
  • 1,019
  • 5
  • 19
  • 35

4 Answers4

4

You can add a couple of conditions to your view. Suppose your view is strongly typed with base class:

@model NotificationBase

You can check for each subclass and add corresponding fields (untested code below!):

@if (Model is GeneralNotification)
{
    Html.TextBoxFor(m => ((GeneralNotification) m).Message);
}

The same goes for second subtype of course:

@if (Model is ReleaseNotification)
{
    Html.TextBoxFor(m => ((ReleaseNotification) m).Version);
}
Andrei
  • 55,890
  • 9
  • 87
  • 108
  • Thank you for the quick response, Andrei. That is exactly what I am doing, problem is this is an edit view and I need to display the selected entities properties. For a GeneralNotification model, I need to display the value of the Message property. It is this value I cannot pass to my view. – Octavian Epure Jul 25 '13 at 08:39
  • @OctavianEpure, how are you passing model to the view? Can you share a code sample of this? In theory running `return View(generalNotificationInstance)` along with snippets in the answer above should give you an expected result. – Andrei Jul 25 '13 at 08:42
  • this is the model I pass to the view @model NotificationBase, and in the controller I do this NotificationBase model =null; switch (typeId) { case (int)NotificationType.General: model = Service.GetGeneralNotification(id); break; case (int)NotificationType.Release: model = Service.GetReleaseNotification(id); break; } return View(model); – Octavian Epure Jul 25 '13 at 08:49
  • @OctavianEpure, as long as both methods give instance of correct subclasses, everything should be fine. What does `Model is GeneralNotification` give you? – Andrei Jul 25 '13 at 08:55
  • I solved it, I passed from the controller a specific derived type model and it works; the problem was I was passing from the controller a base type model, which did not contain the Message/ Version properties from the beginning. Thank you and sorry to have waysted your time – Octavian Epure Jul 25 '13 at 09:03
  • @OctavianEpure, no problem, seems like our discussion helped you to resolve the problem anyway. At least we were on the right track! – Andrei Jul 25 '13 at 09:49
0

This can also be solved by using an interface. For example if you want to avoid conditions in your views. Razor views can also be strongly typed with an interface.

You can go for a full interface implemented by NotificationBase with overrides in your derived classes. (note that NotificationBase would need to be abstract for this) Or you implement partial interfaces.

Kr

Bastaspast
  • 1,022
  • 8
  • 9
0

Set your model type to the base type:

@model NotificationBase

Then:

@Html.EditorForModel()

EditorForModel is smart enough to render the form based on the concrete type passed on runtime.

haim770
  • 48,394
  • 7
  • 105
  • 133
  • I cannot use EditorForModel, since I need to display special JAvaScript datetime editor in view for the StarDate and EndDate fields – Octavian Epure Jul 25 '13 at 08:52
  • 1
    This is exactly what `EditorTemplates` are for. either add a generic `DateTime` editor template (`~/Views/Shared/EditorTemplates/DateTime.cshtml`) or decorate your `StartDate` & `EndDate` properties with `[UIHint("JsDateTime")]` then `~/Views/Shared/EditorTemplates/JsDateTime.cshtml`. – haim770 Jul 25 '13 at 08:55
0

Problem solved: I passed to the view a specific derived type model (GeneralNotification/ ReleaseNotification) instead of passing a base type model. The view stayed the same and everithing works now.

Octavian Epure
  • 1,019
  • 5
  • 19
  • 35