NMathur
NMathur

Reputation: 829

Passing value for required property at Controller, but still ModelState.IsValid is false

I have a partial view to post comment for my article module on my main view for article detail. Model for comment has three required fields, ID (identity field), ArticleId and CommentText. (I am using Razor syntax)

I tried to pass ArticleId at controller in Create Action.

public ActionResult Create(ArticleComment articlecomment, string AID)
{

    articlecomment.ArticleId = AID;    //this is required

    if (User.Identity.IsAuthenticated)
    {
        articlecomment.UserId = WebSecurity.CurrentUserId.ToString();
    }
    else
    {
        articlecomment.UserId = Constants.Anonymus;
    }

    articlecomment.CommentDate = DateTime.Now;

    if (ModelState.IsValid)
    {
        db.ArticleComment.Add(articlecomment);
        int success = db.SaveChanges();
        if (success > 0)
        {
            return Content("<script language='javascript' type='text/javascript'>alert('Comment added successfully.');window.location.href='" + articlecomment.ArticleId + "';</script>");
        }
        else
        {
            return Content("<script language='javascript' type='text/javascript'>alert('Posting comment has failed, please try later.');window.location.href='" + articlecomment.ArticleId+ "';</script>");
        }
    }

    return PartialView(articlecomment);
}

But still ModelState.IsValid is returning false. I have used following code and find that ModelState is getting ArticleId as null.

foreach (var modelStateValue in ViewData.ModelState.Values)
{
    foreach (var error in modelStateValue.Errors)
    {
        // Do something useful with these properties
        var errorMessage = error.ErrorMessage;
        var exception = error.Exception;
    }
}

I have also thought to set value for ArticleId using Hidden field using ViewBag but have not find any working code. I tried following:

@Html.HiddenFor(model => model.ArticleId, new { @value = ViewBag.Article })

and

 @Html.HiddenFor(model => model.ArticleId, (object)ViewBag.Article)

My 'ParticalView' to post comment is:

@model Outliner.Models.ArticleComment

<script src="~/Scripts/jquery-1.8.2.min.js"></script>
<script src="~/Scripts/jquery.validate.min.js"></script>
<script src="~/Scripts/jquery.validate.unobtrusive.min.js"></script>

@using (Html.BeginForm()) {
    @Html.AntiForgeryToken()
    @Html.ValidationSummary(true)



        <div class="editor-label">
           @* @Html.HiddenFor(model => model.ArticleId, new { @value = ViewBag.Article })
            @Html.HiddenFor(model => model.ArticleId, (object)ViewBag.Article)*@
            @Html.LabelFor(model => model.Comment) &nbsp;&nbsp;&nbsp;
            <span class="error">@Html.ValidationMessageFor(model => model.Comment)</span>  
        </div>

            @Html.TextAreaFor(model => model.Comment)        

            <input type="submit" value="Post" />        

}

And this is how I am calling this partial view on 'ArticalDetail' view (my main view):

 @Html.Action("Create", "ArticleComment")

I have passed required field value at controller for a View before, but I am facing issue for PartialView. What I am doing wrong and how can I make this work?

Edit After a try

As Satpal and Fals lead me to a direction, I tried their suggestions, and tried following:

TryUpdateModel(articlecomment);

and also

TryUpdateModel<ArticleComment>(articlecomment);

and also

TryValidateModel(articlecomment);

but I was still getting same validation error for ArticleId, then I checked in Watch and all tree methods I tried are returning False.

I also tried following:

UpdateModel(articlecomment);

and

UpdateModel<ArticleComment>(articlecomment);

above methods are generating an exception :

The model of type 'Outliner.Models.ArticleComment' could not be updated.

Here is my model:

 [Table("ArticleComments")]
    public class ArticleComment
    {
        [Key]
        [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
        public int Id { get; set; }

        [Required]
        public string ArticleId { get; set; }

        public string UserId { get; set; }

        [Required]
        [Display(Name = "Comment")]
        public string Comment { get; set; }

        [Required]
        [Display(Name = "Commented On")]
        public DateTime CommentDate { get; set; }

    }

I don't get it, why my model is not updating ... :(

Upvotes: 0

Views: 2376

Answers (4)

SamTech
SamTech

Reputation: 1313

It is quite late answer, but it should work.

Before ModelState.IsValid, add following

ModelState.Remove("ArticleId");

It will remove that field from validation.

Upvotes: 2

Justin
Justin

Reputation: 3397

To me it seems that your @Html.Action(...) code it invoking the action to create the partial view, like you said. If you are doing this it isn't the correct way to invoke a partial view. While it isn't uncommon for a action to return a partial view, it is normally via AJAX, in my experience, so you can just insert it into the DOM after it returns.

You can use the following method to render a partial view:

@{ 
    Html.RenderPartial("_myPartialView", 
                       new ArticleComment {ArticleId = model.Id}); 
}

This should render your partial view, pass your model to it so it can render properly. Then when the form is POST'ed to the server it should create the model from the form data. You shouldn't need the AID parameter as it is part of your ArticleComment model.

Upvotes: 0

Fals
Fals

Reputation: 6839

After update any requerid field after the ModelBind you must call another method to update the validation.

You can use:

TryValidateModel(articlecomment);

or

TryUpdateModel<ArticleComment>(articlecomment);

Upvotes: 1

Satpal
Satpal

Reputation: 133403

You can try TryUpdateModel(articlecomment) once before checking ModelState.IsValid. However I have not tested it

Upvotes: 2

Related Questions