Search code examples
c#htmleditorforremote-validation

Override EditorFor ID and name


I'm building a blog website. I want users to be able to edit their posts. I need to change the name of the HTML helper to match my model so I can use remote validation.

Model

        [RegularExpression("[a-z]{1,50}", ErrorMessage = "URL String must be in lowercase")]
        [Required(ErrorMessage = "Unique URL is required")]
        [Remote("doesURLExist", "Post", HttpMethod = "POST", 
        ErrorMessage = "URL already exists. Please enter a different URL.")]
        public string URLString { get; set; }

HTML, Using the viewbag to pass through my pre populated data.

<div class="form-group">
        @Html.LabelFor(model => model.post.URLString, htmlAttributes: new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.EditorFor(model => model.post.URLString, new { htmlAttributes = new { @Value = ViewBag.postURL, @class = "form-control", @name = "URLString" } })
            @Html.ValidationMessageFor(model => model.post.URLString, "", new { @class = "text-danger" })
        </div>
</div>

The prepopulated fields work great like this but my remote validation doesnt work. the name attribute needs to be "URLString" but it comes up as post.URLString which cant be used in my remote method.

Here is my remote method to check for existing URLStrings

    [HttpPost]
    public JsonResult doesURLExist(String URLString)
    {
        var allposts = _unitOfWork.PostRepository.Get();

        if (allposts.Count(p => p.URLString == URLString) == 0)
        {
            return Json(true, JsonRequestBehavior.AllowGet);
        }


        return Json(false, JsonRequestBehavior.AllowGet);
    }

I have gotten the remote validation to work using the raw HTML and manually changing the name attribute.

Here is the raw html that the helper outputs when I view source in google chrome. I copied it and changed the name.

<div class="form-group">
        <label class="control-label col-md-2" for="post_URLString">URLString</label>
        <div class="col-md-10">
            <input class="form-control text-box single-line" data-val="true" 
                   data-val-regex="URL String must be in lowercase" data-val-regex-pattern="[a-z]{1,50}" 
                   data-val-remote="URL already exists. Please enter a different URL." data-val-remote-additionalfields="" data-val-remote-type="POST" data-val-remote-url="/Post/doesURLExist" 
                   data-val-required="Unique URL is required" id="post_URLString" name="URLString" type="text" value=  />
            <span class="field-validation-valid text-danger" data-valmsg-for="URLString" data-valmsg-replace="true"></span>
        </div>
    </div>

So that works great! The issue is I cant use my viewbag to prepopulate the data. So I guess I have 2 problems lets just solve the easier one. 1. How do i get model data in the HTML Value field. value = Model.post.URLString doesnt work.

  1. How do I override the HTML name attribute @name = "URLString"

I'm pretty new to c# I might be missing something really obvious here.


Solution

  • Got it. Because the name of my form element kept have a post. before the name I couldn't use the URLString. I instead pass a post object through and get the URL String that way. I also pass through the ID for a more thorough check.

    [HttpPost]
        public JsonResult doesURLExist(tPost post)
        {
            var allposts = _unitOfWork.PostRepository.Get();
    
            if (allposts.Count(p => p.URLString == post.URLString) == 0)
            {
                return Json(true, JsonRequestBehavior.AllowGet);
            }
    
            if (allposts.Count(p => p.URLString == post.URLString && p.Id == post.Id) == 1)
            {
                return Json(true, JsonRequestBehavior.AllowGet);
            }
    
            return Json(false, JsonRequestBehavior.AllowGet);
        }
    

    Here is my model, passing an additional field "Id" this also gets put into my post object.

                [RegularExpression("[a-z, 0-9]{1,50}", ErrorMessage = "URL String must be in lowercase")]
                [Required(ErrorMessage = "Unique URL is required")]
                [Remote("doesURLExist", "Post", AdditionalFields = "Id", HttpMethod = "POST", ErrorMessage = "URL already exists. Please enter a different URL.")]
                public string URLString { get; set; }
    

    Here is my HTML, all working perfect now.

    <div class="form-group">
                @Html.LabelFor(model => model.post.URLString, htmlAttributes: new { @class = "control-label col-md-2" })
                <div class="col-md-10">
                    @Html.EditorFor(model => model.post.URLString, new { htmlAttributes = new {  @class = "form-control" } })
                    @Html.ValidationMessageFor(model => model.post.URLString, "", new { @class = "text-danger" })
                </div>
            </div>