0

I have this HTML code with a div whose contents I want to pass to the controller. The div basically contains some span items of the label-primary class (link). I want to be able to get the names of the labels in this div in the controller. My idea was, as soon as the submit button is clicked, get the list of items that are inside the label-container div and pass their names to the controller as the List<string> OwnerTerminals value. How do I do that?

HTML + JS code:

@using (Html.BeginForm("Register", "Account", FormMethod.Post, new { @class = "form-horizontal", role = "form" }))
{
    ...
    <div id="register-terminal-panel" class="panel panel-default" style="max-width: 450px;">
        <div class="panel-heading" style="color:#003F8B">
            Add terminals to client
        </div>
        <div class="panel-body">
            <div id="label-container"></div>
            <div class="input-group input-group pull-right">
                <span class="input-group-addon">
                    <span class="glyphicon glyphicon-search" aria-hidden="true"></span>
                </span>
                <input id="register-terminals-search" type="text" class="form-control" placeholder="Search terminals" aria-describedby="search-addon" onkeyup="searchTerminals()">
            </div>
        </div>
        <ul id="register-terminal-list-container" class="list-group">
            @foreach (Point p in terminals)
            {
                <li id="list-item-@p.Name"><a href="javascript:void(0)" class="list-group-item" onclick="createLabel('@p.Name')">@p.Name</a></li>
            }
        </ul>
    </div>

    <div class="form-group">
        <div class="col-md-offset-2 col-md-10">
            <input type="submit" class="btn btn-default" value="Register" />
        </div>
    </div>
}

<script>
    function closeLabel(item) {
        item.parentElement.remove();
        var listItem = '\n<li id="list-item-' + item.parentElement.id + '"><a href="javascript:void(0)" class="list-group-item" onclick="createLabel(\'' +
            item.parentElement.id + '\')">' + item.parentElement.id + '</a>';
        $('#register-terminal-list-container').append(listItem);
        sortUnorderedList("register-terminal-list-container");
    };

    function createLabel(name) {
        var label =
            '<span id="' + name + '" class="label label-primary terminal-label"><span class="glyphicon glyphicon-remove" onclick="closeLabel(this)" id="terminal-label-close-btn"></span> ' + name + '</span>\n'
        $('#label-container').append(label);
        $('#list-item-' + name).remove();
    };
</script>

Model:

public class RegisterViewModel
{
    ...
    public List<string> OwnerTerminals { get; set; }
}
A. Savva
  • 632
  • 10
  • 30
  • When you create the labels why not store the names in `data-name` on the required element. Not sure if I seen this incorrectly but giving multiple elements the same id `terminal-label-close-btn` is not valid but you can give them a `data-id` with that value and then use it as a selector to get the `data-name` value into an array you can then post – Nope Mar 27 '17 at 08:46
  • @Fran not sure I understood. How would I do that? `terminal-label-close-btn` is not the id of the label, it is the id of a "X" button inside the label (to remove the label from the list). – A. Savva Mar 27 '17 at 08:50
  • 1
    Never mind about the button then sorry :) Though same `id` on multiple elements is still bad. To not automatically submit you can make your button a `type="button"` bind to the click event of it, build your array in that click event and use a manual `form.post` using jquery ajax post as seen here [**http://stackoverflow.com/questions/425095/submit-form-using-ajax-and-jquery**](http://stackoverflow.com/questions/425095/submit-form-using-ajax-and-jquery) passing your array as the data to the controller action. – Nope Mar 27 '17 at 08:50
  • @Fran so there is no way to do it the razor way? – A. Savva Mar 27 '17 at 10:54
  • 1
    You can create a hidden field for each label containing the value so the hidden fields get posted on submit. However, that way, in my humble opinion adds unnecessary DOM clutter. The suggested Ajax route is very common. Most of the time I don't even bother with a form around those read-only cases and just add a div with the target url and post with ajax only but that depends of course on your exact use case for the rest of the form. – Nope Mar 27 '17 at 12:04

1 Answers1

1

Modify answer regard to comment for doing it using post

It is possible to do it without using ajax, mainly by using a hidden input with proper name to achieve it.

so add a hidden input when creating the label to achieve it

function createLabel(name) {
    var label =
        '<span id="' + name + '" class="label label-primary terminal-label"><span class="glyphicon glyphicon-remove" onclick="closeLabel(this)" id="terminal-label-close-btn"></span> ' + name + '</span>\n'
    label = label + '<input type="hidden" value="' + name + '" name="OwnerTerminals" />';
    $('#label-container').append(label);
    $('#list-item-' + name).remove();
};

if the model is object, there may need some object name prefix to the input name - i.e ModelName.OwnerTerminals

more info about model binding, please reference other article such as this one: http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx/

Original Answer

There is two part

  1. get all the names you can get name via javascript like (I have made a jsfiddle which assume how your view would look like here https://jsfiddle.net/alantsai/p076235t/):

    $(function() {
        $("#btnGetName").click(function() {
            var nameList = [];
            $("#label-container > span").each(function() {
            nameList.push($(this).text());
            });
            alert(nameList);
        })
    })
    
  2. post it to controller
    you probably need to modify the post object according to your view model, but if simply the OwnerTerminals, then should be something like:

    $.post("postUrl", {OwnerTerminals : nameList});
    
Alan Tsai
  • 2,465
  • 1
  • 13
  • 16
  • So there is no way to do it with razor? – A. Savva Mar 27 '17 at 11:03
  • 1
    It is possible to do it with razor - by using the hidden input for model binding, I have edit the answer to include it – Alan Tsai Mar 27 '17 at 14:44
  • Thank you, I am wondering how I can use `@Html.HiddenFor()` with this. My item is `public List OwnerTerminals { get; set; }`. Do you know of a way to do that? – A. Savva Mar 30 '17 at 14:15