Not Get data in jstree - asp.net-mvc

I am create menu of Category and SubCategory in my project using jstree.
but i do not get or not show my data in jstree format.
so, what is problem.?
Plz Help me.
thnks....
My Controller Code
[HttpGet]
public JsonResult GetCatList()
{
IEnumerable<Category> cats = _CategoryBusiness.Select();
return new JsonResult
{
JsonRequestBehavior = JsonRequestBehavior.AllowGet,
Data = cats
};
}
My Model Class
[Serializable]
public class Category
{
[Key]
[DisplayName("Id")]
public int CategoryID { get; set; }
public string CategoryName { get; set; }
public int? SubCategoryID { get; set; }
[ForeignKey("SubCategoryID")]
public virtual Category SubCategory { get; set; }
}
And _CategoryBusiness.Select() is
public List<Category> Select(int id = 0)
{
var selectFrom = _Ctx.Categories.Select(a => a);
var query = selectFrom.Select(a => a);
if(id > 0)
query = query.Where(a => a.CategoryID == id);
return query.ToList();
}
And My View Page code is
<script type="text/javascript">
$(function () {
FillJSTree();
});
function FillJSTree() {
$("#onflycheckboxes").jstree({
json_data: {
"ajax": {
"url": "/Categories/GetCatList/",
"type": "GET",
"dataType": "json",
"contentType": "application/json charset=utf-8",
}
},
//checkbox: {
// real_checkboxes: true,
// checked_parent_open: true
//},
plugins: ["themes", "json_data", "ui"]
});
}
</script>
.
.
.
.
..
<div id="onflycheckboxes">
</div>

Try this: Before sending data to view, serialize that. This works for me. P.s. Your category data must be tree node.
[HttpGet]
public string GetCatList()
{
IEnumerable<Category> cats = _CategoryBusiness.Select();
string myjsonmodel = new JavaScriptSerializer().Serialize(cats);
return myjsonmodel;
}

Related

Custom Validation for nested model in .net core

I am trying to validate a nested model using custom validation. But the problem is AttributeAdapterBase.AddValidation function is never called on nested model. However it works well with simple class property
Custom required validation attribute:
public interface IId
{
long Id { get; set; }
}
public class Select2RequiredAttribute : RequiredAttribute
{
public Select2RequiredAttribute(string errorMessage = "") : base()
{
ErrorMessage = errorMessage;
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
Type t = value.GetType();
if (typeof(IId).IsAssignableFrom(t))
{
if ((value as IId).Id == 0)
{
return new ValidationResult(ErrorMessage);
}
}
else
{
return new ValidationResult(ErrorMessage);
}
return ValidationResult.Success;
}
}
Attribute adapter base:
public class Select2RequiredAttributeAdapter : AttributeAdapterBase<Select2RequiredAttribute>
{
public Select2RequiredAttributeAdapter(Select2RequiredAttribute attribute, IStringLocalizer stringLocalizer) : base(attribute, stringLocalizer)
{
}
public override void AddValidation(ClientModelValidationContext context)
{
MergeAttribute(context.Attributes, "data-val", "true");
MergeAttribute(context.Attributes, "data-val-select2-required", GetErrorMessage(context));
}
public override string GetErrorMessage(ModelValidationContextBase validationContext)
{
return Attribute.ErrorMessage ?? GetErrorMessage(validationContext.ModelMetadata, validationContext.ModelMetadata.GetDisplayName());
}
}
Adapter provider:
public class Select2RequiredAdapterProvider : IValidationAttributeAdapterProvider
{
private readonly IValidationAttributeAdapterProvider _baseProvider = new ValidationAttributeAdapterProvider();
public IAttributeAdapter GetAttributeAdapter(ValidationAttribute attribute, IStringLocalizer stringLocalizer)
{
if (attribute is Select2RequiredAttribute)
{
return new Select2RequiredAttributeAdapter(attribute as Select2RequiredAttribute, stringLocalizer);
}
else
{
return _baseProvider.GetAttributeAdapter(attribute, stringLocalizer);
}
}
}
Startup.cs:
services.AddSingleton<IValidationAttributeAdapterProvider, Select2RequiredAdapterProvider>();
Model classes:
public interface IBaseBriefViewModel : IId
{
string Name { get; set; }
}
public class BaseBriefViewModel : IBaseBriefViewModel
{
public virtual long Id { get; set; }
public string Name { get; set; }
}
public class UserViewModel
{
public long Id { get; set; }
public string Name { get; set; }
[Select2Required("Branch is required.")]
public BaseBriefViewModel Branch { get; set; }
}
Branch select 2 partial view:
#model DataLibrary.ViewModels.BriefViewModels.BaseBriefViewModel
#{
var elementId = ViewData["ElementId"] != null && !string.IsNullOrEmpty(ViewData["ElementId"].ToString()) ? ViewData["ElementId"].ToString() : "branch-id";
}
<div class="form-group">
<label>Branch: <span class="text-danger"></span></label>
<div class="row">
<div class="#select2Class">
#Html.DropDownListFor(model => model.Id, new List<SelectListItem>() {
new SelectListItem()
{
Value = (Model!=null&&Model.Id>0)?Model.Id.ToString():"",
Text = (Model!=null&&Model.Id>0)?Model.Name:"",
Selected = (Model!=null&&Model.Id>0)?true:false,
}}, new { #id = elementId, #class = "form-control disable-field"})
#Html.ValidationMessageFor(model => model.Id, "", new { #class = "text-danger" })
</div>
</div>
</div>
<script>
$(function () {
var id = "#" + "#elementId";
var url = '/Branch/GetBranchsForSelect2';
var dataArray = function (params) {
params.page = params.page || 1;
return {
prefix: params.term,
pageSize: pageSize,
pageNumber: params.page,
};
};
Select2AutoCompleteAjax(id, url, dataArray, pageSize, "---Branch---");
});
</script>
All this code works well for server side. But for better user experience I want to show error before submitting form. How can I achieve this? I want to use this BaseBriefViewModel for a lot of Select2 in the project. So hard coding a static error message is not a good idea. What I really want to do is pass a error message from parent object. Like Branch is required in this specific case. Maybe in some other class I might pass Product is required
Any direction will be appreciated
At the moment this is not supported - but support is in planned. See dotnet github issue:
https://github.com/dotnet/runtime/issues/36093

Polymorphic model binding / Complex Models

I have problem in model binding. When I submit form it returns me id=0 and device is null? and how to solve it. My goal is to add new device, and choose device type from view by selector. if user selects smartphone it has to add fields for smartphone. I don't want to save device type in base class as Kind variable. Thanks in advance(sorry for english)
controller->
public IActionResult Index()
{
MainCont mainCont = new MainCont();
return View(mainCont);
}
index.cshtml ->
#model MainCont
#{
ViewData["Title"] = "Home Page";
}
<form action="home/create" method="post">
#Html.Partial("example",Model.Device)
<button type="submit">გაგზავნა</button>
</form>
example.cshtml ->
#model SmartPhone
#Html.TextBoxFor(model => model.imei)
#Html.TextBoxFor(model => model.screensize)
Device Model ->
public abstract class Device : Object
{
}
LaptopModel ->
public class Laptop : Device
{
public string CPU { get; set; }
public string GPu { get; set; }
}
MainCont ->
public class MainCont
{
public int Id{ get; set; }
public Device Device { get; set; }
}
SmartphoneModel ->
public class SmartPhone : Device
{
public string screensize { get; set; }
public string imei { get; set; }
}
model binder ->
using Bind.Models;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Bind
{
public class DeviceModelBinder : IModelBinder
{
private Dictionary<Type, (ModelMetadata, IModelBinder)> binders;
public DeviceModelBinder(Dictionary<Type, (ModelMetadata, IModelBinder)> binders)
{
this.binders = binders;
}
public async Task BindModelAsync(ModelBindingContext bindingContext)
{
IModelBinder modelBinder;
ModelMetadata modelMetadata;
if (bindingContext.ModelType == typeof(Laptop))
{
(modelMetadata, modelBinder) = binders[typeof(Laptop)];
}
else if (bindingContext.ModelType == typeof(SmartPhone))
{
(modelMetadata, modelBinder) = binders[typeof(SmartPhone)];
}
else
{
bindingContext.Result = ModelBindingResult.Failed();
return;
}
var newBindingContext = DefaultModelBindingContext.CreateBindingContext(
bindingContext.ActionContext,
bindingContext.ValueProvider,
modelMetadata,
bindingInfo: null,
bindingContext.ModelName);
await modelBinder.BindModelAsync(newBindingContext);
bindingContext.Result = newBindingContext.Result;
if (newBindingContext.Result.IsModelSet)
{
// Setting the ValidationState ensures properties on derived types are correctly
bindingContext.ValidationState[newBindingContext.Result] = new ValidationStateEntry
{
Metadata = modelMetadata,
};
}
}
}
}
binderprovider ->
using Bind.Models;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Bind
{
public class DeviceModelBinderProvider: IModelBinderProvider
{
public IModelBinder GetBinder(ModelBinderProviderContext context)
{
if (context.Metadata.ModelType != typeof(Device))
{
return null;
}
var subclasses = new[] { typeof(Laptop), typeof(SmartPhone), };
var binders = new Dictionary<Type, (ModelMetadata, IModelBinder)>();
foreach (var type in subclasses)
{
var modelMetadata = context.MetadataProvider.GetMetadataForType(type);
binders[type] = (modelMetadata, context.CreateBinder(modelMetadata));
}
return new DeviceModelBinder(binders);
}
}
}
Here is a demo:
Index.cshtml(when select SmartPhone,use example.cshtml,when select Laptop,use example1.cshtml):
#model MainCont
#{
ViewData["Title"] = "Home Page";
}
<form asp-action="create" asp-controller="home" method="post">
<select id="select" name="select">
<option value="SmartPhone">SmartPhone </option>
<option value="Laptop">Laptop </option>
</select>
<div id="sample"></div>
<button type="submit">გაგზავნა</button>
</form>
#section scripts{
<script>
$(function () {
GetPartialView();
})
$("#select").change(function () {
GetPartialView();
})
function GetPartialView() {
$.ajax({
url: "/Test1/ReturnExample",
type: "POST",
data: {
select: $("#select").val()
},
success: function (data) {
$('#sample').html(data);
},
error: function (reponse) {
alert("error : " + reponse);
}
});
}
</script>
}
example.cshtml:
#model SmartPhone
#Html.TextBoxFor(model => model.imei)
#Html.TextBoxFor(model => model.screensize)
example1.cshtml:
#model Laptop
#Html.TextBoxFor(model => model.CPU)
#Html.TextBoxFor(model => model.GPu)
Controller:
public IActionResult Index()
{
return View(new MainCont());
}
public IActionResult ReturnExample(string select)
{
if (select == "SmartPhone")
{
return PartialView("~/Views/Test1/example.cshtml", new SmartPhone());
}
else {
return PartialView("~/Views/Test1/example1.cshtml", new Laptop());
}
}
Create Action in Home Controller:
[HttpPost]
public IActionResult Create([ModelBinder(typeof(DataBinder))]MainCont mainCont) {
return Ok();
}
DataBinder:
public class DataBinder : IModelBinder
{
public Task BindModelAsync(ModelBindingContext bindingContext)
{
if (bindingContext == null)
{
throw new ArgumentNullException(nameof(bindingContext));
}
var model1 = new MainCont();
var select = bindingContext.ValueProvider.GetValue("select").FirstValue;
if (select == "SmartPhone")
{
var model2 = new SmartPhone();
model2.screensize = bindingContext.ValueProvider.GetValue("screensize").FirstValue;
model2.imei = bindingContext.ValueProvider.GetValue("imei").FirstValue;
model1.Device = model2;
}
else if (select == "Laptop")
{
var model2 = new Laptop();
model2.CPU = bindingContext.ValueProvider.GetValue("CPU").FirstValue;
model2.GPu = bindingContext.ValueProvider.GetValue("GPu").FirstValue;
model1.Device = model2;
}
bindingContext.Result = ModelBindingResult.Success(model1);
return Task.CompletedTask;
}
}
result:

how to return back list of data from controller to knockout function to view page

This is my controller where i am returning back list of tags with the post:
public JsonResult GetPosts(int? id)
{
var varid = id;
var ret = (from post in db.Posts.ToList()
orderby post.PostedDate descending
select new
{
CityName = post.City.CityName,
TagName = post.Tags.ToList()
// TagName = post.Tags
}
}
I dont know, here, is this the way to return back all the tags selected.
Posts and Tags table are interconnected by many to many relation with a join table TagPost in database which contains TagId and PostId.
this is the knockout code:
function Post(data) {
var self = this;
data = data || {};
self.CityName = data.CityName || "";
self.TagName = data.TagName || "";
}
function viewModel() {
var self = this;
self.posts = ko.observableArray();
self.newMessage = ko.observable();
self.error = ko.observable();
self.loadPosts = function () {
// to load existing posts
$.ajax({
url: postApiUrl1,
data: { id: $("#Locations").val() },
datatype: "json",
contentType: "application/json",
cache: false,
type: 'Get'
})
.done(function (data) {
var mappedPosts = $.map(data, function (item)
{ return new Post(item); });
self.posts(mappedPosts);
})
.fail(function () {
error('unable to load posts');
});
}
This is the view page where i want to data-bind the cityName along with the tags:
<div>
<img src="~/assests/images/icon.png" alt=""><span><a data-bind="text: CityName"></a></span>
</div>
<div>
<img src="~/assests/images/tag.png" alt=""><span><a data-bind="text: TagName"></a></span>
</div>
Here, i want to return back all the tag name with comma seperated.Please someone suggest me what to do from here.
This is my Post class:
public class Post
{
[Key]
public int PostId { get; set; }
public string Message { get; set; }
public int? cityId { get; set; }
public IList<Tag> Tags { get; set; }
}
and this is my tag class:
public class Tag
{
public int TagId { get; set; }
public string TagName { get; set; }
public IList<Post> Posts { get; set; }
}
There is a many to many relationship between tag and post class so its creating a new join Table TagPost with column(TagId, PostId).
This is how i am inserting data to this table with on model creating:
modelBuilder.Entity<Tag>()
.HasMany(p => p.Posts)
.WithMany(t => t.Tags)
.Map(m =>
{
m.ToTable("TagPost");
m.MapLeftKey("TagId");
m.MapRightKey("PostId");
});
This should bring the data in the format you want:
var data = db.Posts.Include(x => x.Tags)
.Include(x => x.City)
.Where(x => x.PostId == id)
.SingleOrDefault();
var json = new {
PostId = data.PostId,
PostMessage = data.Message,
CityName = data.City.CityName,
Tags = string.Join(",", data.Tags.Select(t => t.TagName))
};
return Json(json, JsonRequestBehavior.AllowGet);
This will return the following Json:
{
"PostId": 1,
"PostMessage": "ABC",
"CityName": "Chicago",
"Tags": "C#,.NET,StackOverflow"
}
Just note that I've included the City using Include in the Post but in the model you posted, there's only the cityId. Perhaps you'll need to change that too.
EDIT
As per request, to return all posts and related tags change the code to this:
var data = db.Posts.Include(x => x.Tags)
.Include(x => x.City)
.ToList();
if (data.Count == 0)
return null; //Just return something if no post is found
var json = data.Select(x => new
{
PostId = x.PostId,
PostMessage = x.Message,
CityName = x.City.CityName,
Tags = string.Join(",", x.Tags.Select(t => t.TagName))
}).ToList();

Json to List<object> not binding

I have a problem with object send in json format, that is not binded in Action Controller
Here the json parts:
function filterTxAjustement(arrTx) {
return {
dateDebut: $("#TxAjustementDateDebut").val(),
dateFin: $("#TxAjustementDateFin").val(),
ufCode: $("#TxAjustementUf").val(),
tx: JSON.stringify(arrTx)
};
}
function SaveTx() {
var arrTx = [];
$.each(Day, function (i, v) {
var $this = $('#' + v + 'Tx');
var tx = new Object();
tx.Day = v;
tx.Nb = parseInt($this.val());
tx.UfCode = parseInt($('#TxAjustementUf').val());
tx.Total = 0;
arrTx.push(tx);
});
$.ajax({
url: EasilyRelativeUrl("Lit/SetTxAjustementByDateAndUf"),
data: filterTxAjustement(arrTx),
type: 'POST',
dataType: 'json'
}).done(function (data) {
$('#TxAjustementGrid').data("kendoGrid").dataSource.read();
});
}
My array is well populated:
dateDebut:16/12/2013
dateFin:22/12/2013
ufCode:21124
tx:[{"Day":"Sunday","Nb":1,"UfCode":21124,"Total":0},{"Day":"Monday","Nb":2,"UfCode":21124,"Total":0},{"Day":"Tuesday","Nb":3,"UfCode":21124,"Total":0},{"Day":"Wednesday","Nb":0,"UfCode":21124,"Total":0},{"Day":"Thursday","Nb":0,"UfCode":21124,"Total":0},{"Day":"Friday","Nb":0,"UfCode":21124,"Total":0},{"Day":"Saturday","Nb":0,"UfCode":21124,"Total":0}]
But when it hit Action Controller, tx is null
public ActionResult SetTxAjustementByDateAndUf(DateTime dateDebut, DateTime dateFin, string ufCode, List<TauxAjustement> tx)
(Here the TauxAjustement object)
public class TauxAjustement
{
public string Day { get; set; }
public int Nb { get; set; }
public int Total { get; set; }
public int UfCode { get; set; }
}
I have tried with TauxAjustement[], but same issue. I have added Total = 0 and parseInt to have exact definition of C# object, but same...
What have I missed ? I do make a CustomBinderModel for this ?
Thanks for your help.
You need to define the tx argument as an array rather than a List:
public ActionResult SetTxAjustementByDateAndUf(DateTime dateDebut,
DateTime dateFin,
string ufCode,
TauxAjustement[] tx)
{}

Jquery post to mvc 4 controller not passing data

I'm trying to pass data from JQuery to an MVC 4 controller. The controller gets invoked, but no data is passed. In the past I always just used form serialization, but that's not appropriate here.
My Controller:
[HttpPost]
public ActionResult Write(VideoSessionEnvelope envelope)
{
if (ModelState.IsValid)
{
envelope = Log.Write(envelope);
}
var result = Json(envelope);
return result;
}
We use an envelope class as a container for all view models
public class VideoSessionEnvelope : BaseEnvelope
{
public VideoSessionEnvelope()
{
SessionStart = new VideoSessionStartViewModel();
}
public Guid? LogEntryID { get; set; }
public VideoSessionStartViewModel SessionStart { get; set; }
}
}
The view model
public class VideoSessionStartViewModel: IViewModel
{
public string SessionId { get; set; }
public int UserId { get; set; }
public string Message { get; set; }
}
And finally the javascript
var Logging = Logging || {};
Logging.VideoSession = function () {
var Start = function (sessionId, userId, message) {
var envelope = {
SessionStart: {
"SessionId": sessionId,
"UserId": userId,
"Message": message
}
}
var data = JSON.stringify(envelope);
$.ajax({
type: "POST",
url: "/Logging/Write",
data: data,
datatype: "application/json",
success: function (result) {
return result;
},
error: function (request, status, error) {
return error;
}
});
};
return {
Start: Start
};
}();
According to Firebug the data is passed as
JSON
SessionStart Object { SessionId="sessionIdVal", UserId=123, Message="messageValue"}
Message "messageValue"
SessionId "sessionIdVal"
UserId 123
The controller gets called, but the properties in the view model are always null. I've tried several variations on the theme, nothing seems to work.
Try wrapping your data in a literal with the name as envelope so it will be picked up by the Model Binder:
data: { envelope: data },
UPDATE
Remove the call to JSON.stringify(), it is not strictly necessary to serialize the object literal.

Resources