0

I have a table containing a list of games. Each row contains a game ID, a drop-down list containing all the versions of the game and a status which currently shows the status of the latest version.

I want to update a single row on the table based on what the version drop-down list value contains which should change the value of the status cell. This change should also change the ActiveVersion field in the view model.

I think this is achievable by using AJAX, model binding and potentially partial views but I'm unsure on how to do it.

I have attempted to simplify my problem by using versioning of games with strings and integers as data types as an example as I am using complex models and viewmodels in my webapp.

I have an MVC view as follows

@model IEnumerable<GameViewModel>
...
<tbody>
    @foreach (var item in Model)
    {
    <tr>
        <td>
            @Html.DisplayFor(modelItem => item.Id)
        </td>
        <td>
            @Html.DisplayFor(modelItem => @item.Versions.Where(x => x.Version == item.ActiveVersion).FirstOrDefault().Status)
        </td>
        <td>
            <select asp-for="@item.ActiveVersion" asp-items="@item.VersionsList"></select>
        </td>
    </tr>
    }
</tbody>

My view model is as follows

public class GameViewModel
{
    public string Id { get; set; }
    public List<GameVersion> Versions { get; set; }
    public string ActiveVersion { get; set; }

    //Constructor - initialises active version to highest version
    public GameViewModel(Game game)
    {
        Id = game.Id;
        Versions = game.Versions;
        ActiveVersion = game.Versions.Max(x => x.Version).ToString();
    }

    //Returns a list of all versions to be used in dropdown
    public List<SelectListItem> VersionsList
    {
        get
        {
            List<SelectListItem> versionList = new List<SelectListItem>();
            foreach (GameVersion gv in Versions)
            {
               versionList.Add(new SelectListItem { Value = gv.Version.ToString(), Text = gv.Version.ToString() });
            }
            return versionList;
        }
    }
}

My models are as follows

public class GameVersion
{
    public int Version { get; set; }
    public string Status { get; set; }
}

public class Game
{
    public string Id { get; set; }
    public List<GameVersion> Versions { get; set; }
}

I am using ASP.NET Core 3.1 to develop a MVC webapp.

1
  • What is your GameVersion model used to do?And your GameViewModel contains Version model.Could you please share your whole model?i.e. Version and Game model. Commented Jul 23, 2020 at 6:20

2 Answers 2

2

You can use jQuery to control the implementation of the drop-down list to dynamically update the value of the state, according to the model you provide.

Here is a working demo like below:

Model:

public class GameVersion
{
    public int Version { get; set; }
    public string Status { get; set; }
}

public class Game
{
    public string Id { get; set; }
    public List<GameVersion> Versions { get; set; }
}
public class GameViewModel
{
    public string Id { get; set; }
    public List<GameVersion> Versions { get; set; }
    public string ActiveVersion { get; set; }

    //Constructor - initialises active version to highest version
    public GameViewModel(Game game)
    {
        Id = game.Id;
        Versions = game.Versions;
        ActiveVersion = game.Versions.Max(x => x.Version).ToString();
    }

    //Returns a list of all versions to be used in dropdown
    public List<SelectListItem> VersionsList
    {
        get
        {
            List<SelectListItem> versionList = new List<SelectListItem>();
            foreach (GameVersion gv in Versions)
            {
                versionList.Add(new SelectListItem { Value = gv.Version.ToString(), Text = gv.Version.ToString() });
            }
            return versionList;
        }
    }
}

View(Index.cshtml):

@model IEnumerable<GameViewModel>
<table>
    <tbody>
        @foreach (var item in Model)
        {
            <tr id="@item.Id">
                <td>
                    @Html.DisplayFor(modelItem => item.Id)
                </td>
                <td>
                    <span>

                        @*change this line*@

                        @Html.DisplayFor(modelItem => @item.Versions.Where(x => x.Version.ToString() == item.ActiveVersion).FirstOrDefault().Status)
                    </span>
                </td>
                <td>
                    <select class="[email protected]" asp-for="@item.ActiveVersion" asp-items="@item.VersionsList"></select>
                </td>
            </tr>
        }
    </tbody>
</table>

@section Scripts{
    <script>
        $(function () {
            var gameModel [email protected](Model);
            $('*[class^="activeVersion"]').change(function () {
                var vers = $(this).find('option:selected').val()
                console.log(vers)
                var stat = $(this).parent().prev().find('span');
                stat.empty();
                var nodeid = $(this).attr('class').split('_')[1]
                $.each(gameModel, function (index, game) {
                    if (nodeid == game['id']) {
                        console.log(game['versions'])
                        $.each(game['versions'], function (indx, version) {
                            if (vers == version['version'])
                                stat.text(version['status'])
                        })
                    }
                })
            })
        })
    </script>
}

Controller(For easy testing,I set the value manually):

public IActionResult Index()
    {
        var games = new Game
        {
            Id = "game",
            Versions = new List<GameVersion> {
                new GameVersion{  Version=1,Status="Status1"},
                new GameVersion{  Version=2,Status="Status2"},
                new GameVersion{  Version=3,Status="Status3"},
            },
        };
        var games2 = new Game
        {
            Id = "game2",
            Versions = new List<GameVersion> {
                new GameVersion{ Version=4,Status="Status4"},
                new GameVersion{ Version=5,Status="Status5"},
                new GameVersion{ Version=6,Status="Status6"},
            },
        };
        var gameviewModels = new List<GameViewModel> {
            new GameViewModel(games),
            new GameViewModel(games2)
        };
        return View(gameviewModels);
    }

Result:

enter image description here

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

4 Comments

Thank you for this answer, this is what I am after. I have edited the question to make it clearer. This answer does not change the "activeVersion" in the view model.
Thank you for this, although this still doesn't update the "activeVersion" in the view model.
The razor view should be the same with mine.Otherwise,the jquery may does not work well.Please confirm your code.
Jquery won't work as I am wanting a backend update in the view model and jquery is client side. This solution works if you don't want backend changes.
1

There are a number of ways to achieve this.

A simple one that doe snot require Ajax is to wrap each select within a form tag which posts to an action that takes an ID and VERSION. Within this form add a hidden field for the ID.

Add an OnChange event to the select and use javascript to post back the form.

At the action, perform your update and redirect back to your index action that displays the list

If you want to use ajax then create a javascript method passes your select control as a parameter instead of posting back. From this parameter you can get the select value. You can get the previous control (the hidden ID input) to get that value then pass these back to your action.

Your action can pass back a JSON result of OK or an error or even the table cell html. Assuming success, either with HTML passed back by the action (you can use a partial view which replaces the original table cell content) or already knowing having the correct select action already displayed then you are done. If there is an error you have to decide to show that message and whether to put the select back to the original value

1 Comment

Would it be possible to get an example using the code I've provided?

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.