0

I have a form in a partial view. The view receives a "model".

@model EditUserViewModel
@{Layout = null;}
<form asp-action="Edit" id="EditUser" method="post">
    <input type="hidden" asp-for="Id" />
 
    <div class="mb-3">
        <label asp-for="UserName" class="form-label">Nom d'utilisateur</label>
        <input asp-for="UserName" class="form-control" required />
        <span asp-validation-for="UserName" class="text-danger"></span>
    </div>
 
    <div class="mb-3">
        <label asp-for="Email" class="form-label">Email</label>
        <input asp-for="Email" type="email" class="form-control" required />
        <span asp-validation-for="Email" class="text-danger"></span>
    </div>
 
    <div class="mb-3">
        <label class="form-label">Changer le mot de passe (laisser vide pour ne pas modifier)</label>
        <input asp-for="Password" type="password" class="form-control" value=""/>
        <span asp-validation-for="Password" class="text-danger"></span>
    </div>
 
    <div class="mb-3">
        <label asp-for="Pseudo" class="form-label">Pseudo</label>
        <input asp-for="Pseudo" class="form-control" />
        <span asp-validation-for="Pseudo" class="text-danger"></span>
    </div>
 
    <div class="mb-3">
        <label class="form-label">Rôles</label>
        <div>
            @for (int i = 0; i < Model.Roles.Count; i++)
            {
                <div class="form-check">
                    <input type="checkbox" class="form-check-input" asp-for="Roles[i].Selected" />
                    <label class="form-check-label" for="Roles[i].Selected">@Model.Roles[i].RoleName</label>
                    <input type="hidden" asp-for="Roles[i].RoleId" />
                    <input type="hidden" asp-for="Roles[i].RoleName" />
                </div>
            }
        </div>
    </div>
    <button type="submit" class="btn-dark btn-sm" >Enregistrer</button>
    <button type="button" id="[email protected]"  onclick="LoadDetailPartialView_USERS()" style="background-color:lightgray">Annuler</button>
</form>
@section Scripts {
    <partial name="_ValidationScriptsPartial" />
}

Controller side:

public async Task<IActionResult> Edit(string id)
{
    var user = await _userManager.FindByIdAsync(id);
    if (user == null) return NotFound();

    var userRoles = await _userManager.GetRolesAsync(user);
    var allRoles = _roleManager.Roles.ToList();

    var model = new EditUserViewModel
    {
        Id = user.Id,
        UserName = user.UserName,
        Email = user.Email,
        Pseudo = user.Pseudo,
        Roles = allRoles.Select(r => new RoleSelectionViewModel
        {
            RoleId = r.Id,
            RoleName = r.Name,
            Selected = userRoles.Contains(r.Name)
        }).ToList()
    };

    return View(model);
}

This view is itself called by a partial view (list of 'Users'), by:

function Modif_User(Id) {
    $.ajax({
        url: '@Url.Action("Edit", "Users", new { Area = "Admin" })',
        type: 'GET',
        cache: false,
        data: {id:Id }
    }).done(function (result) {
            $(PartialUsers).html(result);
    });
}

Upon form submission, in my Edit view:

$("#Edit").submit(function (e) {
    e.preventDefault();
    var formdata = new FormData(this);

    $.ajax({
        url: '@Url.Action("Edit","Users", new { Area = "Admin" })',
        data: formdata,
        method: "post",
        success: function (result) {
            debugger;
            if(result.success)
            {
                window.location.href = "@Url.Action("Index","Users", new { Area = "Admin" })";
            }
        },
    });
});

and the related controller method:

[HttpPost]
public async Task<IActionResult> Edit(EditUserViewModel model)
{
    if (!ModelState.IsValid)
    {
        return Json(new { success = false });
    }

    var user = await _userManager.FindByIdAsync(model.Id);
    if (user == null) return Json(new { success = false }); 

    user.Email = model.Email;
    user.Pseudo = model.Pseudo;
    if (!string.IsNullOrEmpty(model.Password))
    {
        var token = await _userManager.GeneratePasswordResetTokenAsync(user);
        await _userManager.ResetPasswordAsync(user, token, model.Password);
    }

    await _userManager.UpdateAsync(user);

    var currentRoles = await _userManager.GetRolesAsync(user);
    var selectedRoles = model.Roles.Where(r => r.Selected).Select(r => r.RoleName).ToList();

    await _userManager.RemoveFromRolesAsync(user, currentRoles);
    await _userManager.AddToRolesAsync(user, selectedRoles);

    return Json(new { success = true });
}

The submission process is successful and the information is saved.

The problem is that "Json(new { success = true })" is not returned to the calling AJAX function but is displayed in raw form in the browser.

enter image description here

The AJAX function isn't even being read in `$("#Edit").submit(function (e)...").

The JSON response would allow me to display the result where it should appear, that is, by calling the partial view listing the 'Users' which then calls the partial view containing the 'User' edit form.

I've already used this method, with a partial view containing a form and the data submitted by 'submit', and it worked; AJAX received the JSON response correctly.

I don't understand what's not working this time. Thanks

4
  • You need to configure your Ajax call with the dataType expected: dataType: 'json' Commented Jan 4 at 21:26
  • I tried it, it doesn't work Commented Jan 4 at 23:19
  • Please show how you "tried it". Commented Jan 4 at 23:22
  • I tried it as an option for the Ajax function. ` $.ajax({ url: '@Url.Action("Edit", "Users", new { Area = "Admin" })', data: formdata, dataType: 'json', processData: false, contentType: false, type: 'POST', ... ` Commented Jan 5 at 11:12

1 Answer 1

0

I finally understood why it couldn't work the way I thought it had for another view.
There were two problems.

First problem:

When it loads, my main view loads four partial view (in tabs).
One of these partial views (List of 'Users') then loads, only on demand, another partial view ('Edit User', which is displayed in its place).

The code in the main view references elements of the second partial view ('Edit User') that don't yet exist when the main view loads. The ID of the 'Edit' form doesn't exist at that point.

Therefore, in the main view, the code specific to this second partial view is simply ignored (without an error message).

The script that intercepts the 'Edit' form submission must be loaded with its corresponding 'Edit User' partial view.

Second problem:

Initially, the script for the 'Edit User' partial view wasn't loading with the view because I had it enclosed in an '@section Script' tag.
Then I read, deep in a forum, that sections aren't carried over into a partial view.
Once enclosed only in <script></script>, the code loaded with the partial view.

$('#Edit').submit(function (e) {
    e.preventDefault();
    var formdata = new FormData(this);
    $.ajax({
        url: '@Url.Action("Edit", "Users", new { Area = "Admin" })',
        data: formdata,
        processData: false,
        contentType: false,
        type: 'POST',
        success: function (result) {
            debugger;
            if(result.success)
            {
                LoadDetailPartialView_USERS();
            }
         },
    });
});

The two options:

processData: false,
contentType: false,

are essential for proper functioning.
I don't understand their role, but without them I get the following error:

Uncaught TypeError: 'append' called on an object that does not implement interface FormData.

After submitting the 'Edit' form, to return to the 'List of Users' partial view I have to use the JavaScript function which calls this first partial view when the main view loads...

function LoadDetailPartialView_USERS() {
    $.ajax({
        url: '@Url.Action("Index", "Users", new { Area = "Admin" })',
        type: 'GET',
        cache: false,
    }).done(function (result) {
            $(PartialUsers).html(result);
    });
};

to ensure that the first partial view ('List of Users') is displayed correctly again (in the correct tab).
The form submission controller for the 'Edit User' partial view was not returning HTML after saving the information, but only a JSON success message.

The problem is resolved.
Please let me know if you see a more elegant solution.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.