I'm trying to set up a basic Mvc.Jquery.Datatables runthrough. I'm getting an extra row at the top which isn't the expected filter row.
There is a script error in the background 'Uncaught TypeError: {object Object} has no method 'columnFilter' as shown below
My Index View is
#using DataTables.Controllers
#using Mvc.JQuery.Datatables
#using Mvc.JQuery.Datatables.Serialization
<script src="~/Content/DataTables/media/js/jquery.js"></script>
<script src="~/Content/DataTables/media/js/jquery.dataTables.js"></script>
<link href="~/Content/DataTables/media/css/demo_table.css" rel="stylesheet" />
<h2>Datatables Demo</h2>
#{
var vm = Html.DataTableVm("table", (HomeController h) => h.GetDataObject(null), null);
vm.ColumnFilter = true;
vm.StateSave = true;
}
#Html.Partial("DataTable", vm)
My controller code is
public class HomeController : Controller
{
public ActionResult Index()
{
var data = DataRepository.GetData();
return View(data);
}
public DataTablesResult<MyDataObject> GetDataObject(DataTablesParam dataTablesParam)
{
var data = DataRepository.GetData().Select(o => o).AsQueryable();
return DataTablesResult.Create(data, dataTablesParam);
}
}
How to get the sort row to show? Thanks.
** Solution **
As suggested, I was missing the script
<script src="~/Content/jquery.dataTables.columnFilter.js"></script>
I think you have a missing script tag for the column filter extension. compare the references against the example page.
also make sure you are using EmbeddedResourceVirtualPathProvider or have the templates project installed
Related
I am trying to use knockout with MVC strongly typed view. Since my model will have over 20 properties, I prefer to use strongly-typed view model to post back data by using ko.mapping.toJS and ko.Util.postJson. The Eligible field was passed back correctly, however the following code does not post back the selected option from drop down list, it just showed value as 0 when I looked that selectOptionModel on the controller. Can someone point out what I did wrong?
the view model from server side is as follows:
public class SelectOptionModel
{
public bool Eligible { get; set; }
public int selectedOption { get; set; }
public IEnumerable<SelectListItem> AvailableOptions
{
get
{
return Enum.GetValues(typeof(OptionEnum)).Cast<OptionEnum>()
.Select(x => new SelectListItem
{
Text = x.ToString(),
Value = x.ToString()
});
}
}
}
public enum OptionEnum
{
[Description("First")]
FirstOption = 1,
[Description("Second")]
SecondOption = 2,
[Description("Third")]
ThirdOption = 3
}
The razor view is like following:
#model TestKo.Models.SelectOptionModel
...
subViewModel = ko.mapping.fromJS(#Html.Raw(Json.Encode(Model)));
...
}
#using (Html.BeginForm()){
<button type="submit" class="button" id="SaveBtn">Save</button>
<div data-bind="with:vm">
<div>
#Html.LabelFor(model => model.Eligible)
#Html.CheckBoxFor(model => model.Eligible, new { data_bind = "checked: selectOptionVM.Eligible" })
</div>
<div>
#Html.LabelFor(model => model.selectedOption)
#Html.DropDownListFor(model => model.selectedOption, Model.AvailableOptions,
new
{ data_bind = "options: selectOptionVM.AvailableOptions, optionsText: 'Text', optionsValue: 'Value', value: selectOptionVM.selectedOption"
})
</div>
</div>
}
The javascript for the knockout view model is:
sectionVM = function (data) {
var self = this;
var selectOptionVM = data;
return {
selectOptionVM: selectOptionVM
}
}
$(document).ready(function () {
var viewModel = {
vm: new sectionVM(subViewModel)
};
ko.applyBindings(viewModel);
$("#SaveBtn").click(function () {
var optionModel = ko.toJS(viewModel.vm.selectOptionVM);
ko.utils.postJson($("form")[0], optionModel)
});
});
The controller part:
[HttpPost]
public ActionResult Create(SelectOptionModel selectOptionModel)
{
try
{
// TODO: Add insert logic here
var modelSaved = selectOptionModel;
return RedirectToAction("Index");
}
catch
{
return View();
}
}
I'm venturing a bit of a guess here, but this could be the problem: the id-bit of your selected option will always be a string (because it will go in the <option value="" attribute). Your endpoint expects an int. As far as I can see, you don't convert the selectedOption before sending it to the server. try parseInt(selectedOption, 10) before sending it to the server. Also, use the network tool in your browser to debug the info that is being sent to the controller. That might help you to zone in on the problem.
Actually it works. Somehow it was not working previously, but after I cleared cache, cookies etc, it just worked. Thanks everyone!
I have been using ASP.NET MVC 4 for a while but I have not yet come across a situation where i need to insert a value into the database from a scaffolded Create view which is based on a value passed from another view. I have tried to infer from the Edit view to try and modify my code to work but I have run into a snag. I got an error similar to this post. Here is my code from the view passing the value
#Html.ActionLink("Allocate", "Create", "Allocation", new { id=item.requestID}, null)
this is from the list of requests already in the database from the Index view
here is my code on the controller that is trying to force the Create method to use the ID passed from the link above
public ActionResult Create(int id = 0)
{
Request request = db.Requests.Find(id);
ViewBag.requestID = new SelectList(db.Requests, "requestID", "requestID", request.requestID);
return View(request);
}
then here is the posting code to the db
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(Allocation allocation)
{
if (ModelState.IsValid)
{
db.Allocations.Add(allocation);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.requestID = new SelectList(db.Requests, "requestID", "requestID", allocation.requestID);
return View(allocation);
}
Basically what I am trying to do is allocate funds to a request made where by the allocation is entered into the db based on the request id. I am trying to prevent the user from choosing the request id from a drop down list. When I run this i get an error
The model item passed into the dictionary is of type 'System.Data.Entity.DynamicProxies.Request_A52006F7570E0448EE323CB36858E4D13EED0BAD958340B32FF166708545DA8C', but this dictionary requires a model item of type 'BudgetAllocation.Models.Allocation'.
If theres anyone out there who can help me out with this please do as soon as you can. I appreciate all the effort offred!!!!!
//EDIT
Here is my Create view
#model BudgetAllocation.Models.Allocation
#{
ViewBag.Title = "Create";
}
<h2>Create</h2>
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>Allocation</legend>
#Html.HiddenFor(model => model.requestID)
<div class="editor-label">
#Html.LabelFor(model => model.allocAmount, "Amount")
</div>
<div class="editor-field">
#Html.EditorFor(model => model.allocAmount)
#Html.ValidationMessageFor(model => model.allocAmount)
</div>
<p>
<input type="submit" value="Allocate" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
The problem is your view id strongly typed with BudgetAllocation.Models.Allocation while in get action of Create you are passing object of type BudgetAllocation.Models.Request thats why you are getting the exception.
You have to pass object of type BudgetAllocation.Models.Allocation in Create get action as well because you view is strongly typed to it.
public ActionResult Create(int id = 0)
{
Request request = db.Requests.Find(id);
return View(request) // <-------------- here is the mistake
}
it should return allocation object, something like this, it is just an example may be you need to do some other thing instead of selecting:
public ActionResult Create(int id = 0)
{
Allocation allocation = db.Allocations.Find(x=>x.requestID == id);
ViewBag.requestID = new SelectList(db.Requests, "requestID", "requestID", request.requestID);
return View(allocation);
}
UPDATE:
you simply need to do like this not return allocaiton object return simply View:
public ActionResult Create(int id = 0)
{
ViewBag.requestID = new SelectList(db.Requests, "requestID", "requestID", request.requestID);
return View();
}
I need to get Guid.Empty in controller and pass it to view. I tried to use ViewBag, I added this code in my controller
public class QuestionnaireController : Controller
{
//....
ViewBag.EmptyGuid = Guid.Empty;
}
and added this code in view
if (rowobject[6] == ViewBag.EmptyGuid) { //...}
but I got some errors in controller
Error 1 Invalid token '=' in class, struct, or interface member declaration
Error 2 Invalid token ';' in class, struct, or interface member declaration
what's wrong and how to make it works?
UPD
I changed code in my controller (I added ViewBag.EmptyGuid inside method)
[HttpGet]
public ActionResult QuestionnaireIndex()
{
ViewBag.EmptyGuid = Guid.Empty.ToString();
FillViewBags();
return View();
}
and this is script in my view
#section scripts{
<script type="text/javascript"> function buttonize(cellvalue, options, rowobject) {
var buttons = '';
if (rowobject[5] == "False") {
buttons += '<input type="button" value="Edit" onclick="editQuestionnaire(' + options.rowId + ')">';
}
buttons += '<input type="button" value="Delete" onclick="deleteQuestionnaire(' + options.rowId + ')">';
if (rowobject[6] == ViewBag.EmptyGuid) {
buttons += '<input type="button" value="Publish" onclick="publishQuestionnaire(' + options.rowId + ')">';
}
else {
buttons += '<input type="button" value="Remove" onclick="removePublishQuestionnaire(' + options.rowId + ')">';
}
return buttons;
}
</script>
}
You have code directly in the class, you need a method. For example:
public class QuestionnaireController : Controller
{
public ActionResult Index()
{
ViewBag.EmptyGuid = Guid.Empty;
return View();
{
}
This error really has nothing to do with MVC: that is invalid C# syntax and you're getting a compilation error.
On a side note - I'd recommend not using ViewBag at all (or almost ever) when you can use a strongly typed model. Same goes for rowobject[6]: I'm not sure what that is, but you definitely don't want data readers on your View. By the time the data is in the view, it should have already been converted to a model.
On the other hand, I don't think it is wrong to use Guid.Empty or default(Guid) on a view.
not sure what is wrong. Syntax seems correct.... but it still doesn't fire on client side. If I submit the form, I get server side validation, client side nothing...
Here is the code that is on the page:
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")"></script>
<script type="text/javascript">
// we add a custom jquery validation method
(function ($) {
$.validator.addMethod('additive', function (value, element, params) {
//just return false to test it.
return false;
});
// and an unobtrusive adapter
$.validator.unobtrusive.adapters.add("additive", ["field2", "field3", "field4"], function (options) {
var params = {
field2: options.params.field2,
field3: options.params.field3,
field4: options.params.field4
};
options.rules['additive'] = params;
if (options.message) {
options.messages['additive'] = options.message;
}
});
}) (jQuery);
</script>
Here is the part that is on the validator that is related to client side (IClientValidatable):
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
ModelClientValidationRule rule = new ModelClientValidationRule
{
ValidationType = "additive",
ErrorMessage = "ERROR MESSAGE"
};
rule.ValidationParameters.Add("field2", propName2);
rule.ValidationParameters.Add("field3", propName3);
rule.ValidationParameters.Add("field4", propName4);
yield return rule;
}
The model is decorated as following:
[SumValidation("OtherField2...")]
public int MyField { get; set; }
When field renders, it is all there, all the stuff from the server side in terms of data-xxx attributes. Just this specific client validation does not fire. Anyone see what I'm missing?
figured it out. If anyone runs into this. Added custom validation too late on the page. After I moved my custom validation javascript to the head section of the _Layout.cshtml it started to work.
So if your script looks right, good place to check.
Another work around is to run $.validator.unobtrusive.parse('form'); which reloads all the validators.
In my Search controller I have:
public JsonResult Search(string term)
{
var termLower=term.ToLower();
var pictures=_PictureRepo.GetAll();
var productsWereSeached = _ProductRepo.GetAll().Where(x => x.Name.ToLower().Contains(term)).Select(x=> new ProductData
{
Name=x.Name,
Price=x.Price,
Id=x.Id,
Warranty=x.Warranty,
Picture=x.Pictures.FirstOrDefault()
});
ViewBag.NOfMatchedProduct = productsWereSeached.Count();
productsWereSeached = productsWereSeached.Take(2);
foreach (var product in productsWereSeached)
{
product.Picture = _PictureRepo.GetAll().Where(x => x.ProductId == product.Id).FirstOrDefault();
}
return Json(productsWereSeached);
}
In my _Layout I have :
<div>
<input id="nOfMatchedProducts" value='#ViewBag.NOfMatchedProduct'/>
<ul id="realPlaceForSearchItems">
</ul>
</div>
Maybe I should put this code from _Layout to PartialView. The question would be, how to pass ViewBag data from controller to PartialView.
"public JsonResult Search" - so you are already calling your method in ajax, right?
Yes, but I am returning 2 productsWereSeached
You already have the result and just need to show it to your targeted element:
$.get('#Url.Action("Search")',function(result){
$("#nOfMatchedProducts").html(result.length);
});
If you want to return additional information like the total number of records searched in addition to "your filtered results", then you can pass it like this:
var totalrows = productsWereSeached.Count();
//filter your search (productsWereSeached)
return Json(new {list=productsWereSeached, totalrows });
Then do this ajax call:
$.get('#Url.Action("Search")',function(result){
$("#nOfMatchedProducts").html(result.totalrows);
});