3

I have an account page where a user can update his/her profile picture. I use Amazon S3 to store the images so after a successful upload, I return the image URL to populate the image src and a TextBoxFor with a value of the URL. However, when I submit my form, the model that is submitted to my POST still contains the desktop filename instead of the Amazon S3 URL.

Here's my ajax call that (upon success) populates an img field and a TextBoxFor field:

$.ajax
        ({
            type: "POST",
            contentType: "application/json; charset=utf-8",
            url: "/Account/UploadProfImageToS3Return",
            data: formdata,
            processData: false,
            contentType: false,
            success: function (data) {
                $("#profile-image").attr("src", data);
                $("#profImage").attr("value", data);
            },
            error: function (jqXHR, textStatus, errorThrown) {
                //TODO: Indicate Error
                console.log(jqXHR);
            }
        });
        });

Here is my Html.BeginForm:

 @using (Html.BeginForm("General", "Account", new { ReturnUrl = ViewBag.ReturnUrl }, FormMethod.Post, new { @class = "form-horizontal", role = "form" }))
    {
       <img id="profile-image" src="@Model.Artist.ImageURL" alt="Profile Image" />

       @Html.TextBoxFor(m => m.Artist.ImageURL, new { @name = "profImage", @id = "profImage", @type = "file" })

        <div class="form-group">
            <input type="submit" value="Save" class="btn btn-default btn-form" />
        </div>
}

The file, when added to the @Html.TextBoxFor(m => m.Artist.ImageURL, new { @name = "profImage", @id = "profImage", @type = "file" })

is called: 20507471_10214.jpg and after the file is uploaded the value of that TextboxFor is now https://s3.amazonaws.com/unlink/profile-picture/xxxxxxx.jpg (because I update the field after AJAX success)

But when I set a breakpoint on my POST here:

[HttpPost]
public ActionResult General(Artist artist)

and I inspect the artist.ImageURL it still equals 20507471_10214.jpg

What can I do to fix this?

EDIT, image to prove that the value/src attribute of each is being set properly:

enter image description here

8
  • What does the rendered HTML of the view look like? Commented Jul 10, 2018 at 5:14
  • @prd added an image for you, both src and value are being updated in html correctly Commented Jul 10, 2018 at 5:18
  • @prd pretty sure this has to do with ModelState on submit but I don't know how to Clear() the model state before posting so that I get the updated model in my post ActionResult. Any thoughts? Commented Jul 10, 2018 at 5:30
  • Not related, but remove the pointless @name = "profImage" - fortunately that does nothing at all (and if it did work, then model binding would fail) Commented Jul 10, 2018 at 7:03
  • I now see from your self answer that you assumed that would work. The model in the POST method needs to be the same as the model in the view (or you use the [Bind(Prefix="Artist")] attribute). In any case you should never use data models in view when editing data - always use a view model Commented Jul 10, 2018 at 7:10

3 Answers 3

2

Well alright then, so a workaround is to not use:

@Html.TextBoxFor(m => m.Artist.ImageURL, new { @name = "profImage", @id = "profImage", @type = "file" })

and to instead use something like this, with a hidden form element to bind the value on submit...odd, but works:

<input name="profImage" id="profImage" type="file" />
@Html.HiddenFor(m => m.Artist.ImageURL)

I assign the S3 URL value to the hidden form upon AJAX success with:

$("#Artist_ImageURL").attr("value", data);
Sign up to request clarification or add additional context in comments.

7 Comments

That cannot possibly work since name="profImage" has no relationship to the model property which is ImageURL or an object named Artist. I can only assume you have done something stupid like the model in the POST method is not the same as the model in the view
@StephenMuecke the point here is that I'm just using a normal HTML input element to capture the file instead of a TextBoxFor. However, you're right, I forgot to state that upon AJAX return I populate the HiddenFor field with the return URL value
What you are not understanding is that you are not binding correctly. You should have a view model with a HttpPostedFileBase property to bind to the fine input, and a separate string property to bind the name of the file to (although it does not really make sense to have that property since its already included in the HttpPostedFileBase)
@StephenMuecke as someone who has not used HttpPostedFileBase could you post an answer with the correct way to do this? I'm not posting a file, I'm posting a url string though, if that changes anything...
But your input is type = "file, and you using FormData with the relevant ajax options to post the file, so now it even more unclear what you are doing (and as a side note, delete the first contentType: "application/json; charset=utf-8", in the ajax call - fortunately the 2nd contentType: false, overrides it)
|
1

Try to add new image-url from received from Amazon S3 to formData like this

$.ajax
    ({
        type: "POST",
        contentType: "application/json; charset=utf-8",
        url: "/Account/UploadProfImageToS3Return",
        data: formdata,
        processData: false,
        contentType: false,
        success: function (data) {
            $("#profile-image").attr("src", data);
            $("#profImage").attr("value", data);

            //imageUrl corresponds to the Artist model property.
            formData.append("imageUrl",data);
        },
        error: function (jqXHR, textStatus, errorThrown) {
            //TODO: Indicate Error
            console.log(jqXHR);
        }
    });
});

Comments

0

firstly, be very carefully if you are using Chrome, Chrome do not update the css and JS files inmediatly, I recomend to you, use firefox to develop.

Maybe, when you edit the ´name´ tag, you maybe edit some behavior and this is not how MVC wait the response, can you try to delete the ¨@name = "profImage"¨ part and then check the behavior

1 Comment

This has nothing whatsoever to do with the question

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.