Copied to clipboard

Flag this post as spam?

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


  • Nik 1593 posts 7151 karma points MVP 6x c-trib
    Mar 21, 2016 @ 10:09
    Nik
    0

    Return CurrentUmbracoPage is not repopulating custom model.

    Hi peeps,

    I'm hoping someone can shed a bit of light on this for me. I've created a custom surface controller with a couple of actions on it. These actions present and then receive a fairly comprehensive feedback questionnaire.

    However, what I've found is that if my model is invalid on my post method when I call return CurrentUmbracoPage() the model is no longer populated with the previously entered values.

    This is happening with the majority (not all) of the values and is an absolute pain as it has meant that I've had to use the ViewData.ModelState to retrieve information.

    This is a cut down version of my model:

    public class FeedbackResponseModel : IFeedbackResponse
    {
        #region Implementation of IFeedbackResponse
    
        [UmbracoRequired("Site.Feedback.Required", AllowEmptyStrings = false)]
        [UmbracoDisplayName("Site.Feedback.Name")]
        public string Name { get; set; }
    
        [UmbracoDisplayName("Site.Feedback.Organisation")]
        public string Organisation { get; set; }
    
        [UmbracoDisplayName("Site.Feedback.Address")]
        public string Address { get; set; }
    
        [UmbracoEmail(ErrorMessageDictionaryKey = "Site.Feedback.InvalidEmail")]
        [UmbracoDisplayName("Site.Feedback.Email")]
        public string EmailAddress { get; set; }
    
        [UmbracoRequired("Site.Feedback.Required")]
        [UmbracoDisplayName("Site.Feedback.RetainCenter")]
        [UmbracoRange("Site.Feedback.Option", minimum:1D, maximum:5D)]
        public int RetainCenter { get; set; }
    
    }
    

    (Just a side note, I'm using Warren Buckley's Umbraco Validation attributes, which is a wonderful addition for validation using dictionaries for messages)

    The name field will re-populate no problem, as will the Organisation and the E-mail, however the Organisation and the RetainCenter options would get lost.

    When I examine the model during debug they are empty as if they couldn't be mapped back correctly.

    This is the first part of my post action for my surface controller:

    [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult ReceiveFeedback(FeedbackResponseModel model)
        {
            ILog log =
                    LogManager.GetLogger(
                        MethodBase.GetCurrentMethod().DeclaringType
                        );
    
            log.Info(model.ToString());
            //Check if the data posted is valid
            if (!ModelState.IsValid)
            {
                //Not valid - so lets return the user back to the view with the data they entered still prepopulated
                return CurrentUmbracoPage();
            }
    }
    

    I've tried various different approachs in the view to correct the model issue including having:

    @model FeedbackResponseModel
    

    and alternatively

    @inherits UmbracoViewPage<FeedbackResponseModel>
    

    Neither of these allow the model to re-populate with previous values.

    The result of this is that using this approach to rendering form fields:

    @Html.TextBoxFor(m => m.Name, new {@class = "form-control", aria_describedby = "NameStatus"})
    

    does't work and I've had to do the following for the fields that don't work properly:

    <textarea id="Address" name="Address" rows="4" class="form-control" aria-describedby="AddressStatus">@(Html.ViewData.ModelState.Count > 0 && Html.ViewData.ModelState["Address"].Value != null ? Html.ViewData.ModelState["Address"].Value.AttemptedValue : string.Empty)</textarea>
    

    What I find odd, is that the fields that are bound to a simple text box work but those that are bound to other sorts of controls don't seem to, for example the textarea or radio check boxes.

    If anyone has any ideas or needs more information let me know. My work around works, I would just like to know if there is a better way to do it, or if there is something I'm missing.

  • Bo Jacobsen 593 posts 2389 karma points
    Apr 06, 2020 @ 10:43
    Bo Jacobsen
    0

    Hi Nik.

    I know this is an old post, but did you ever find a better solution, then using the ViewData.ModelState?

    I got the same issue in Umbraco 8.5.5 and curently i am using the ViewData.ModelState, i just had to expand it, since we also use steps, so they can go back.

    var value = Model.Something != null ? Model.Something : Html.ViewData.ModelState.Count > 0 && Html.ViewData.ModelState["Something"] != null && Html.ViewData.ModelState["Something"].Value != null ? Html.ViewData.ModelState["Something"].Value.AttemptedValue : string.Empty;
    

    and i had to add Html.ViewData.ModelState["Something"] != null because, when i did a browser previous, then the Html.ViewData.ModelState["Something"] was null.

    I will proberly make a static function for it, if i encounter more then one property. But was curious if you ever did find a better solution?

  • Bo Jacobsen 593 posts 2389 karma points
    Apr 06, 2020 @ 12:20
    Bo Jacobsen
    0

    In case anybody else stumble over this, i made a static function, that seems to work with any object kinds.

    using System;
    using System.Linq.Expressions;
    using System.Web.Mvc;
    
    namespace MyProject.Core.Extensions
    {
        public static class HtmlHelperExtensions
        {
            public static TProperty PostbackValue<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression)
            {
                var propertyExpression = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
                var propertyValue = propertyExpression.Model;
                if (propertyValue != null)
                {
                    return (TProperty)propertyValue;
                }
                else
                {
                    var propertyName = propertyExpression.PropertyName;
                    if (htmlHelper.ViewData != null &&
                        htmlHelper.ViewData.ModelState != null &&
                        htmlHelper.ViewData.ModelState.Count > 0 &&
                        htmlHelper.ViewData.ModelState[propertyName] != null &&
                        htmlHelper.ViewData.ModelState[propertyName].Value != null)
                    {
                        var obj = htmlHelper.ViewData.ModelState[propertyName].Value.AttemptedValue as object;
                        return (TProperty)obj;
                    }
                }
                return default(TProperty);
            }
        }
    }
    

    Then you can use it like this Html.PostbackValue(m => m.SomeProperty) like

    @using MyProject.Core.Extensions
    @inherits UmbracoViewPage<MyProject.Core.Models.MyModel>
    @{
        var testValue = Html.PostbackValue(m => m.SomeProperty);
    }
    <textarea id="Address" name="Address" rows="4" class="form-control" aria-describedby="AddressStatus">@(testValue ?? string.Empty)</textarea>
    
Please Sign in or register to post replies

Write your reply to:

Draft