Привязка данных в MVC 5 и Select2 Multiple Values с движком Razor

Обычно я очень мало работаю на стороне html приложения, потому что по большей части я просто позволяю этому генерировать для меня.

Я работаю над приложением для блога с сообщениями и комментариями к сообщениям. Что я хочу сделать, так это при создании нового сообщения, я должен иметь возможность добавлять существующие теги в новое сообщение. Я пытаюсь использовать Select2, но я не могу понять, как сделать выбранные значения переданы методу Create в пост-контроллере, чтобы они могли быть сохранены в базе данных.

Вот что я работаю с:

namespace Blog.Data.Entities
{
    public class Post
    {
        public virtual long PostId { get; set; }

        -------------------

        public virtual ICollection<Tag> Tags { get; set; }
    }

    public class Tag
    {
        public virtual long TagId { get; set; }
        public virtual string Name { get; set; }
        public virtual string Description { get; set; }
    }
}

Почтовый контроллер

// POST: /Post/Create
    [HttpPost]
    public ActionResult Create(PostsCreateViewModel postModel)
    {
        if (ModelState.IsValid)
        {
            Post post = new Post
            {
                Title = postModel.Title,
                Body = postModel.Body,
                PostDate = _dateTime.UtcNow
            };

            foreach (var tag in postModel.Tags)
            {
                post.Tags.Add(_tagRepository.GetTag(tag.TagId));
            }

            _postRepository.SavePost(post);

            return RedirectToAction("Detail");
        }
        return View(postModel);
    }

Я успешно загружаю данные с удаленного компьютера с помощью: кода Json

<script type="text/javascript">
    $(document).ready(function () {
        $("#tags").select2(
        {
            placeholder: "Select a Tag",
            minimumInputLength: 1,
            multiple: true,
            maximumSelectionSize: 5,
            ajax: {
                url: '@Url.Action("SearchTag", "Post")',
                dataType: 'json',
                data: function (term, page) {
                    return {
                        searchTerm: term,
                        page_limit: 10,
                        page: page,
                    };
                },
                results: function (data, page) {
                    var more = (page * 10) < data.total;
                    return { results: data, more: more };
                }
            }
        });
    });
</script>

Вид: обычно у меня было бы что-то вроде

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

Как написать аналогичный html для текстового поля тега, чтобы при нажатии кнопки "Сохранить" все сохраняется в соответствующих таблицах?

В настоящее время у меня есть это только для select2:

<div class="form-group">
    @Html.LabelFor(model => model.Tags, new { @class = "control-label col-md-2" })
    <div class="col-md-10">
        <input id="tags" style="width: 300px" />
        @Html.ValidationMessageFor(model => model.Tags)
    </div>
</div>

Что производит:

enter image description here

Ответ 1

Я также использую select2, и это работает для меня:

Вид

@Html.ListBoxFor(M => M.TagsId, new MultiSelectList(Model.Tags, "Id", "Description"), new { @class = "form-control select-multiple", multiple = "multiple" })

ViewModel

 public List<Tag> Tags { get; set; } = new List<Tag>();
 public int[] TagsId { get; set; }

Вы можете использовать коллекцию тегов, чтобы заполнить опции в множественном выборе, и массив TagsId будет заполнен идентификатором выбранных тегов. Если вы заполняете опции выбора через ajax, я думаю, вы можете опустить свойство Tags.

Примечание. Я использую множественный выбор, а не текстовое поле.

Ответ 2

Я думаю, что это так же, как <select multiple>
например

    <select name="abc" multiple>
        <option value=1>a</option>
        <option value=2>b</option>
        <option value=3>c</option>
        <option value=4>d</option>
    </select>

вы выбираете вариант a и вариант b, затем отправляете форму методом post

почтовые данные будут abc 1
abc 2
и вы можете получить данные в действии mvc с параметром вроде IEnumeralbe<int> abc

действие понравится

public ActionResult ActionName(IEnumerable<int> abc)  

плагин select2 изменяет только представление, после публикации также используют сообщение http

Ответ 3

Я предлагаю сделать следующее:

  • сначала: сохранить текстовое поле тегов только для отображения.

  • second: есть скрытые входы, которые синхронизируются с значениями текстового поля, манипулируя его значением в javascript. каждый тег в текстовом поле будет иметь скрытый ввод скрытые входы будут представлять идентификаторы тегов, которые выбраны и показаны в текстовом поле.

Преимущество этого способа заключается в том, что связующее устройство по умолчанию позаботится о привязке значений скрытых входов к свойству модели представления: [общедоступные виртуальные метки ICollection {get; задавать; }]

расскажите, как скрытые входы должны выглядеть в вашем html:

<input type="hidden" name="Tags[0].TagId" value="1" />
<input type="hidden" name="Tags[1].TagId" value="2" />
<input type="hidden" name="Tags[2].TagId" value="3" />

для получения дополнительной информации о привязке списка просто следуйте по ссылке:

http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx/

Ответ 4

Если список и выбранные элементы поступают из разных источников:

Пример:

-Model.CategoryList >> фактические элементы selectList

-Model.SubCategories(m => m.SubCategories) >> только выбранные элементы (Ids int [])

@Html.DropDownListFor(m => m.SubCategories, Model.CategoryList, Html.DescriptionFor(m => m.SubCategories), new { @class = "form-control m-select2 select2", multiple = "multiple" })

Я сделал это так с небольшим кодом JS:

@using Newtonsoft.Json;


<script>
    //Edit mode
    //set "selected" prop for the <select> manaually
    $(function () {
        var SubCategories_selected = @JsonConvert.SerializeObject(Model.SubCategories);
        SubCategories_selected.forEach(function (value, index) {
            $('[name="SubCategories"]').find('[value="${value}"]').prop("selected", true);
        });
        //recall the select2 init
        $('#SubCategories').select2();
    });
</script>