Reputation: 6673
In an HTML form how do you bind jquery controls (e.g. tokeninput) the same way you bind the ordinary primitive types to the model? I am struggling to find ways to do this and I know you can use custom templates etc, but there is nothing for jquery plugins.
Specifically I am using tokenInput see here (http://loopj.com/jquery-tokeninput/). Here is the jQuery code that I apply against a standard HTML text input. For every keypress it goes to the controller to return a list of authors. You can also pre-populate with authors, and I use the data tags in HTML5 to prepopulate the control.
$("#AUTHORs").tokenInput('/author/getauthors/', {
hintText: "Enter surname",
searchingText: "Searching...",
preventDuplicates: true,
allowCustomEntry: true,
highlightDuplicates: false,
tokenDelimiter: "*",
resultsLimit: 10,
theme: "facebook",
prePopulate: $('#AUTHORs').data('AUTHORs')
});
I have posted a bit of code from my view just to show you exactly what I am trying to bind to the model.
@model myModels.BOOK
@{
ViewBag.Title = "Edit";
}
@using (Html.BeginForm()) {
@Html.ValidationSummary(true)
<fieldset>
<legend>Basic</legend>
<div class="editor-label">
@Html.LabelFor(model => model.TITLE)
</div>
<div class="editor-field" >
@Html.EditorFor(model => model.TITLE)
@Html.ValidationMessageFor(model => model.TITLE)
</div>
<div class="authors">
<div class="editor-field">
<input type="text" id="authors" name="authors" data-val="true" data-val-required="You must enter at least one author" data-authors="@Json.Encode(Model.AUTHORs.Select(a => new { id = a.AUTHOR_ID, name = a.FULL_NAME }))"/>
<span class="field-validation-valid" data-valmsg-for="authors" data-valmsg-replace="true"></span>
</div>
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
and here is the code that I use when trying to update the model (after pressing "Save") on the form:
[HttpPost]
public ActionResult Edit(BOOK book)
{
if (ModelState.IsValid)
{
db.Entry(book).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Details", new { id = book.REF_ID });
}
ViewBag.REF_ID = new SelectList(db.REFERENCEs, "REF_ID", "REF_ID", book.REF_ID);
return View(book);
}
When you look at the code in the HTML it has formatted the authors from the tokeninput element it looks like so, and it seems that this format it has a real problem with I think:
<input type="text" id="AUTHORs" name="AUTHORs" data-val="true" data-val-required="You must enter at least one author" data-authors="
[{"id":156787,"name":"Faure,M."},
{"id":177433,"name":"Wang,D.Z."},
{"id":177434,"name":"Shu,L.Sh"},
{"id":177435,"name":"Sheng,W.Z."}]"
style="display: none; ">
Upvotes: 2
Views: 1981
Reputation: 1038940
It seems that you are using the tokeninput plugin. Let's have a step-by-step example about how this could be implemented with ASP.NET MVC:
Model:
public class Book
{
public string Title { get; set; }
public IEnumerable<Author> Authors { get; set; }
}
public class Author
{
public int Id { get; set; }
public string Name { get; set; }
}
Controller:
public class HomeController : Controller
{
// fake a database. Obviously that in your actual application
// this information will be coming from a database or something
public readonly static Dictionary<int, string> Authors = new Dictionary<int, string>
{
{ 1, "foo" },
{ 2, "bar" },
{ 3, "baz" },
{ 4, "bazinga" },
};
public ActionResult Index()
{
// preinitialize the model with some values => obviously in your
// real application those will be coming from a database or something
var model = new Book
{
Title = "some title",
Authors = new[]
{
new Author { Id = 2, Name = "bar" }
}
};
return View(model);
}
[HttpPost]
public ActionResult Index(Book book)
{
return Content(string.Format("thanks for selecting authors: {0}", string.Join(" ", book.Authors.Select(x => x.Name))));
}
public ActionResult GetAuthors(string q)
{
var authors = Authors.Select(x => new
{
id = x.Key,
name = x.Value
});
return Json(authors, JsonRequestBehavior.AllowGet);
}
}
View:
@model Book
@using (Html.BeginForm())
{
<div>
@Html.LabelFor(x => x.Title)
@Html.EditorFor(x => x.Title)
</div>
<div>
@Html.TextBoxFor(
x => x.Authors,
new {
id = "authors",
data_url = Url.Action("GetAuthors", "Home"),
data_authors = Json.Encode(
Model.Authors.Select(
x => new { id = x.Id, name = x.Name }
)
)
}
)
</div>
<button type="submit">OK</button>
}
<script type="text/javascript" src="@Url.Content("~/scripts/jquery.tokeninput.js")"></script>
<script type="text/javascript">
var authors = $('#authors');
authors.tokenInput(authors.data('url'), {
hintText: 'Enter surname',
searchingText: 'Searching...',
preventDuplicates: true,
allowCustomEntry: true,
highlightDuplicates: false,
tokenDelimiter: '*',
resultsLimit: 10,
theme: 'facebook',
prePopulate: authors.data('authors')
});
</script>
and the last step is to write a custom model binder which will retrieve the authors form the ids:
public class AuthorModelBinder : IModelBinder
{
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var values = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
if (values != null)
{
// We have specified asterisk (*) as a token delimiter. So
// the ids will be separated by *. For example "2*3*5"
var ids = values.AttemptedValue.Split('*').Select(int.Parse);
// Now that we have the selected ids we could fetch the corresponding
// authors from our datasource
var authors = HomeController.Authors.Where(x => ids.Contains(x.Key)).Select(x => new Author
{
Id = x.Key,
Name = x.Value
}).ToList();
return authors;
}
return Enumerable.Empty<Author>();
}
}
that will be registered in Application_Start:
ModelBinders.Binders.Add(typeof(IEnumerable<Author>), new AuthorModelBinder());
Upvotes: 4
Reputation: 10648
I made small test - and seems that kind of attribute text is not an error and correclty recognized by browser as JSON object
Try to add expression $("#authorlist").data("authors")
to watch in your browser (press F12) or execute it in console - for me it returns valid javascript object.
Upvotes: 0
Reputation: 1497
data-authors="@Json.Encode(Model.AUTHORs.Select(a => new { id = a.AUTHOR_ID, name = a.FULL_NAME }))
"
I think this should be :
data-authors="@Html.Raw(Json.Encode(Model.AUTHORs.Select(a => new { id = a.AUTHOR_ID, name = a.FULL_NAME })))"
Upvotes: 0
Reputation: 17288
You can use serialize
$("form").on('submit', function(event){
event.preventDefault();
var form = $(this);
$.ajax({
url: form.attr('action'),
type: form.attr('method'),
data: form.serialize(),
success: function(r) { }
});
});
Upvotes: 0