Kendo treeview expander not coming - asp.net-mvc

i am creating one Kendo treeview as written below
#(Html.Kendo().TreeView()
.Name("treeview")
.Template("<a class='edit-link' onclick=javascript:EditNode(#= item.id #) href='\\#'>#= item.text #</a> <a class='add-link' onclick=javascript:AddNode(#= item.id #) href='\\#'>Add</a>")
.HtmlAttributes(new { #class = "demo-section" })
.DataSource(source =>
{
source.Read(read => read.Action("Read_TemplateData", "Role"));
})
)
and in the controller action i am returning like
public ActionResult Read_TemplateData(string id)
{
IEnumerable<KendoTreeviewModel> result;
var AllPrivileges = ContextService.GetAllPrivilege(Evry.Ecompanion.Web.Common.SessionManager.AuthorizedInfo.UserId);
if (string.IsNullOrEmpty(id))
{
result = AllPrivileges.Where(p => p.Id == p.ParentPrivilegeId).Select(p => new KendoTreeviewModel { text = p.Name, id = p.Id,expanded=false, items = GetChilderns(p.Id) }).ToList();
}
else
{
result = AllPrivileges.Where(p => p.ParentPrivilegeId == Convert.ToInt32(id, CultureInfo.InvariantCulture) && p.Id != Convert.ToInt32(id, CultureInfo.InvariantCulture)).Select(p => new KendoTreeviewModel { text = p.Name, id = p.Id}).ToList();
}
return Json(result, JsonRequestBehavior.AllowGet);
}
public List<KendoTreeviewModel> GetChilderns(int id)
{
var AllPrivileges = ContextService.GetAllPrivilege(Evry.Ecompanion.Web.Common.SessionManager.AuthorizedInfo.UserId);
return AllPrivileges.Where(p => p.ParentPrivilegeId == Convert.ToInt32(id, CultureInfo.InvariantCulture) && p.Id != Convert.ToInt32(id, CultureInfo.InvariantCulture)).Select(p => new KendoTreeviewModel { text = p.Name, id = p.Id }).ToList();
}
and the viewmodel is like
public class KendoTreeviewModel
{
[DataMember]
public int id { get; set; }
[DataMember]
public string text { get; set; }
[DataMember]
public bool expanded { get; set; }
[DataMember]
public List<KendoTreeviewModel> items { get; set; }
}
in the result the Parent and child lists are coming, but the expander in the treeview is not coming
the output is coming without treeview expander, only parent nodes are displaying.
please anybody help me in resolving the issue.
Thanks in advance,
Rudresh

you are not passing Id to your controller
source.Read(read => read.Action("Read_TemplateData", "Role", new{id=#= item.id #}));
You need hasChildren property in order to get the child records
in KendoTreeviewModel class add this property hasChildren then
change
result = AllPrivileges.Where(p => p.Id == p.ParentPrivilegeId).Select(p => new KendoTreeviewModel { text = p.Name, id = p.Id,expanded=false, items = GetChilderns(p.Id) }).ToList();
to
result = AllPrivileges.Where(p => p.Id == p.ParentPrivilegeId).Select(p => new KendoTreeviewModel { text = p.Name, id = p.Id,expanded=false, items = GetChilderns(p.Id),
hasChildren = GetChilderns(p.Id).count() > 0}).ToList();

Related

Retrieving Children from Multiple Parent Types, and Associating Them

What is the most efficient way to
a) retrieve all children objects from multiple parent types, and
b) know what the parent type is and the exact parent Id for each child?
Currently this is what I'm doing and it's incredibly inefficient, at least the part where I find the specific parent of each child.
public class ChildModel
{
public int Id { get; set; }
public string Name { get; set; }
}
public class ParentType1Model
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<ChildModel> Children { get; set; }
}
public class ParentType2Model
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<ChildModel> Children { get; set; }
}
//Get all ChildModels from ParentType1
var parentType1Children = db.ParentType1Models
.SelectMany(x => x.Children)
.ToList();
listOfChildModels.AddRange(parentType1Children);
//Get all ChildModels from ParentType2
var parentType2Children = db.ParentType2Models
.SelectMany(x => x.Children)
.ToList();
listOfChildModels.AddRange(parentType2Children);
//Find the parent for each ChildModel
foreach (var child in listOfChildModels)
{
ParentType1Model parentType1ModelCheck = null;
ParentType2Model parentType2ModelCheck = null;
parentType1ModelCheck = await db.ParentType1Models
.Where(p => p.Children
.Any(i => i.Id == child.Id))
.FirstOrDefaultAsync();
//If first check is null, then move to second check
if (taskProjectModelCheck == null)
{
parentType2ModelCheck = await db.ParentType2Models
.Where(p => p.Children
.Any(i => i.Id == child.Id))
.FirstOrDefaultAsync();
}
//Now record the parent type and parent Id in an object containing the original ChildModel and it's parent's info (to be used later for various things)
ChildViewModel childViewModel = new ChildViewModel();
childViewModel.ChildModel = child;
if (parentType1ModelCheck != null)
{
childViewModel.ParentType = "ParentType1";
childViewModel.ParentModelId = parentType1ModelCheck.Id;
}
else if (parentType2ModelCheck != null)
{
childViewModel.ParentType = "ParentType2";
childViewModel.ParentModelId = parentType2ModelCheck.Id;
}
}
How about something like this?
var ids1 = from p in db.ParentType1Models
from c in p.Children
select new
{
parentId = p.Id,
parentName = p.Name,
childName = c.Name,
childId = c.Id,
ParentType = "One"
};
var ids2 = from p in db.ParentType2Models
from c in p.Children
select new
{
parentId = p.Id,
parentName = p.Name,
childName = c.Name,
childId = c.Id,
ParentType = "Two"
};
var results = ids1.Union(ids2).ToList();
I ended up using raw SQL, and it is extremely fast.
By writing a query directly against the database, I was able to go straight to the many to many relationship tables that get created by Entity Framework when I set up the ParentTypeXModels and ChildModels.
result = dbContext.Database.SqlQuery<ANewChildObject>(
"select
ParentModelId = pm.Id,
Id = c.Id,
ParentType = 'ParentType1'
from dbo.ChildModels c
JOIN dbo.ParentType1ModelsChildModels pmT ON c.Id = pmT.ChildModel_Id
JOIN dbo.ParentType1Models pm on pmT.ParentType1Model_Id = pm.Id
UNION ALL
select
ParentModelId = pm.Id,
Id = c.Id,
ParentType = 'ParentType2'
from dbo.ChildModels c
JOIN dbo.ParentType2ModelsChildModels pmT ON c.Id = pmT.ChildModel_Id
JOIN dbo.ParentType2Models pm on pmT.ParentType2Model_Id = pm.Id"
).ToList();

Viewmodel with conditional aggregation (Sums)

I have a viewmodel
public class RecTotal
{
public string PayType { get; set; }
public decimal TotalPrice { get; set; }
public string Category { get; set; }
}
public class ReconcileViewModel
{
public IEnumerable<RecTotal> RecTotals { get; set; }
public IEnumerable<RecInvoiceLineItem> LineItems { get; set; }
}
How do I create sums of the categories and create a new RecTotal record for each one. Ex:
ReconcileViewModel VM = new ReconcileViewModel();
foreach(POSItemCategory cat in db.POSItemCategories)
{
recLineItems.Where(p => p.Category == cat.ID).Sum(p => p.InvPrice);
}
The end result i'm looking for is something like
VM.RecTotal.Add(Sum(TotalPrice), foreach(Category)
I know I'm close but I just cant quite get it.
I found a way to do this, but it is "Ugly" in my opinion and there has to be a better way to do it....
var test = new List<RecTotal>();
foreach (POSItemCategory cat in db.POSItemCategories)
{
test.Add(new RecTotal
{
NumberOfItems = recLineItems.Where(p => p.Category == cat.ID).Count(),
TotalPrice = recLineItems.Where(p => p.Category == cat.ID).Sum(p => p.InvPrice),
PayType = "All",
Category = cat.Name,
NumberOfInvoices = recLineItems.Where(p => p.Category == cat.ID).Select(p => p.InvID).Distinct().Count()
});
};
VM.RecTotals = test;
Please let me know if there is a better way of doing this.
you can try this
var testdata = new List<RecTotal>();
testdata = recLineItems.Where(x => db.POSItemCategories.Select(a=>a.ID).Contains(x.Category))
.GroupBy(x => x.Category)
.Select(
x =>
new RecTotal()
{
Category = x.Key,
PayType = "All",
TotalPrice = x.Sum(z => z.InvPrice),
NumberOfItems = x.Count(),
NumberOfInvoices = x.Select(p => p.InvID).Distinct().Count()
}).ToList();

.Join .Group Lambda multiple table

I need to convert:
SELECT Author.AuthorName, Author.AuthorSurname , Category.CategoryName, COUNT(Record.IdCategory) AS Ilosc
FROM ((Record
INNER JOIN Author ON Author.Id = Record.IdAuthor)
INNER JOIN Category ON Category.Id = Record.IdCategory)
GROUP BY AuthorName, AuthorSurname, CategoryName
Order by Ilosc ASC
To lambda.
I have created
public class SortModel
{
public string Imie { get; set; }
public string Nazwisko { get; set; }
public string Kategoria { get; set; }
}
For now i wrote this code but i need to add .groupby:
public List<SortModel> GetAuthorCategories()
{
var context = new KolekcjaPlytEntities2();
List<SortModel> queryAllCustomers = context.Record
.Join( context.Author, r => r.IdAuthor, a => a.Id, (r, a) => new {r, a})
.Join(context.Category, c => c.r.IdCategory, cn => cn.Id, (c, cn) => new SortModel()
{
Imie = c.a.AuthorName,
Nazwisko = c.a.AuthorSurname,
Kategoria = cn.CategoryName,
})
.ToList();
return queryAllCustomers;
}
Thanks.
You could use LINQ query expression like this one.
List<SortModel> queryAllCustomers = (from r in context.Record
join a in context.Author on r.IdAuthor equals a.Id
join c in context.Category on r.IdCategory equals c.Id
group new {a, c} by new {a.AuthorName, a.AuthorSurname , c.CategoryName} into gruopAC
let countCategory= gruopAC.Count()
orderby countCategory
select new SortModel
{
Imie=gruopAC.Key.AuthorName,
Nazwisko =gruopAC.Key.AuthorSurname ,
Kategoria =gruopAC.Key.CategoryName,
Ilosc=countCategory}).ToList()
Suppose you have
public class SortModel
{
public string Imie { get; set; }
public string Nazwisko { get; set; }
public string Kategoria { get; set; }
public int Ilosc { get; set; }
}
You can try this code:
public List<SortModel> GetAuthorCategories()
{
var context = new KolekcjaPlytEntities2();
List<SortModel> queryAllCustomers = context.Record
.Join(context.Author, r => r.IdAuthor, a => a.Id, (r, a) => new {r, a})
.Join(context.Category, ar => ar.r.IdCategory, c => c.Id, (ar, c) => new {
r = ar.r,
a = ar.a,
c = c
})
// Here you have a IEnumerable<dynamic> of items { a = Author, c = Category, r = Record }
// All items with same { a.Id, c.Id } are grouped
.GroupBy(x => new { x.a.Id, x.c.Id }, (x, items) => new SortModel()
{
// First() cannot return null, we have inner join everywhere
Imie = items.First().a.AuthorName,
Nazwisko = items.First().a.AuthorSurname,
Kategoria = items.First().c.CategoryName,
Ilosc = items.Count()
})
.ToList();
return queryAllCustomers;
}

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();

How to get Count in Lambda

I have three models (Applicant, Meeting, City) and I joined three of them. I want to get Count by grouping MeetingId in Applicant model. Here are my models and method I use for populating Dropdownlist in Controller. So, like the "Expired" property in the Controller, how can I obtain the count for the MeetingId by grouping on "TotalMeetingById" property?
Applicant Model:
public class Applicant
{
public int ApplicantID { get; set; }
public DateTime? SubmitDate { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public int MeetingId { get; set; }
}
Meeting Model:
public class Meeting
{
public int MeetingID { get; set; }
public string MeetingName { get; set; }
public DateTime MeetingStartDate { get; set; }
public DateTime? MeetingEndDate { get; set; }
public int? TotalParticipant { get; set; }
public int? MeetingCityId { get; set; }
public int? ParticipantCityAId { get; set; }
public int? ParticipantCityBId { get; set; }
}
City Model:
public class City
{
public int CityID { get; set; }
public string CityName { get; set; }
}
Controller:
private void PopulateDropDownList()
{
var meetingsQuery = repository.Meetings
.GroupJoin(repository.Cities, m => m.MeetingCityId, c => c.CityID, (m, c) => new { m, cA = c.DefaultIfEmpty() })
.SelectMany(z => z.cA.Select(cA => new { m = z.m, cA }))
.GroupJoin(repository.Cities, m => m.m.ParticipantCityAId, c => c.CityID, (m, c) => new { m.m, m.cA, cB = c.DefaultIfEmpty() })
.SelectMany(w => w.cB.Select(cB => new { m = w.m, cA = w.cA, cB }))
.GroupJoin(repository.Cities, m => m.m.ParticipantCityBId, c => c.CityID, (m, c) => new { m.m, m.cA, m.cB, cC = c.DefaultIfEmpty() })
.SelectMany(t => t.cC.Select(cC => new { m = t.m, cA = t.cA, cB = t.cB, cC }))
.Select(
m =>
new
{
CityID = m.cA.CityID,
CityName = m.cA.CityName,
MeetingDate = m.m.MeetingStartDate,
MeetingName = m.m.MeetingName,
NameofMeetingCityIdA = m.cA != null ? m.cA.CityName : null,
NameofMeetingCityIdB = m.cB != null ? m.cB.CityName : null,
NameofMeetingCityIdC = m.cC != null ? m.cC.CityName : null
})
.OrderBy(x => x.CityID)
.AsEnumerable()
.Select(
i => new
{
Value = i.CityID.ToString(),
DisplayValue = string.Format("{0} ({1:dd MMMM yyyy})", i.NameofMeetingCityIdA, i.MeetingDate),
Expired = i.MeetingDate < DateTime.UtcNow,
TotalMeetingById= ??? >>> I cannot get the total count for the related MeetingId at here
}
).ToList();
var selectItems = new List<MyHelpers.MySelectItem>(meetingsQuery.Count);
foreach (var record in meetingsQuery)
{
var item = new MyHelpers.MySelectItem
{
Text = record.DisplayValue,
Value = record.Value
};
if (record.Expired)
{
item.Class = "disabled";
item.Disabled = "disabled";
}
selectItems.Add(item);
}
ViewBag.MeetingData = selectItems;
}
Here are sample data for models:
Applicant:
ApplicantID : 100
SubmitDate : 01/11/2013
Name : Christof
Surname : Jahnsen
MeetingId : 1
Meeting:
MeetingID : 1
MeetingName : City Information Days
MeetingStartDate : 01/01/2014
MeetingEndDate : 02/01/2014
TotalParticipant : 2 (for example)
MeetingCityId : 500
ParticipantCityAId : 501
ParticipantCityBId : 502
City:
CityID : 500 / 501 / 502
CityName : London / Paris / NY
Update -----------------------------------------------------------------------
Razor:
#Html.LabelFor(m => m.Applicant.MeetingId)
#Html.MyDropdownListFor(m => m.Applicant.MeetingId, ViewBag.MeetingData as List<MyHelpers.MySelectItem>, "---- Select ----",
new { name = "meetingId", id = "meetingId" })
#Html.ValidationMessageFor(m => m.Applicant.MeetingId, null, new { #class = "ValidationErrors" })
Controller:
public ViewResult Add()
{
PopulateDropDownList();
ApplicantViewModel model = new ApplicantViewModel
{
Applicant = new Applicant(),
Applicants = repository.Applicants,
Lookups = repository.Lookups,
Cities = repository.Cities
.ToList()
};
return View(model);
}
[HttpPost]
public ActionResult Add(ApplicantViewModel model)
{
ApplicantViewModel viewModel;
if (ModelState.IsValid)
{
model.Applicant.SubmitDate = DateTime.Now;
repository.SaveApplicant(model.Applicant);
PopulateDropDownList(model.Applicant);
return View("Completed", ViewBag.ApplicantId = model.Applicant.ApplicantID);
}
else
{
// there is something wrong with the data values
PopulateDropDownList();
TempData["message"] = "Please try again.";
viewModel = new ApplicantViewModel
{
Applicant = new Applicant(),
Applicants = repository.Applicants,
Lookups = repository.Lookups,
Cities = repository.Cities
.ToList()
};
return View(viewModel);
}
}
You need grouping, so use something like this
var meetingsQuery = from meeting in repository.Meetings
join cityA in repository.Cities on meeting.MeetingCityId equals cityA.CityID into CitiesA
join cityB in repository.Cities on meeting.ParticipantCityAId equals cityB.CityID into CitiesB
join cityC in repository.Cities on meeting.ParticipantCityBId equals cityC.CityID into citiesC
from cityA in citiesA.DefaultIfEmpty()
from cityB in citiesB.DefaultIfEmpty()
from cityC in citiesC.DefaultIfEmpty()
orderby cityA.CityID
select new
{
CityID = cityA.CityID,
CityName = cityA.CityName,
MeetingDate = meeting.MeetingStartDate,
MeetingName = meeting.MeetingName,
NameofMeetingCityIdA = cityA != null ? cityA.CityName : null,
NameofMeetingCityIdB = cityB != null ? cityB.CityName : null,
NameofMeetingCityIdC = cityC != null ? cityC.CityName : null
}
var meetings = from meeting in meetingsQuery.AsEnumerable()
group meeting by new {
meeting.CityID,
meeting.MeetingDate,
meeting.NameofMeetingCityIdA
} into grouppedMeeting
select new {
Value = grouppedMeeting.Key.CityID.ToString(),
DisplayValue = string.Format("{0} ({1:dd MMMM yyyy})", grouppedMeeting.Key.NameofMeetingCityIdA, grouppedMeeting.Key.MeetingDate),
Expired = grouppedMeeting.Key.MeetingDate < DateTime.UtcNow,
TotalMeetingById= grouppedMeeting.Count()
}
UPDATE
in this code
// there is something wrong with the data values
PopulateDropDownList();
TempData["message"] = "Please try again.";
viewModel = new ApplicantViewModel
{
Applicant = new Applicant(),
Applicants = repository.Applicants,
Lookups = repository.Lookups,
Cities = repository.Cities
.ToList()
};
return View(viewModel);
you don't mark any item as selected, you only add items to viewbag
Finally I solved the problem with the help of using an external method out of Lambda expression.
private void PopulateMeetingsDropDownList(object selectedMeetings = null)
{
var meetingsQuery = repository.Meetings
.GroupJoin(repository.Cities, m => m.MeetingCityId, c => c.CityID, (m, c) => new { m, cA = c.DefaultIfEmpty() })
.SelectMany(z => z.cA.Select(cA => new { m = z.m, cA }))
.GroupJoin(repository.Cities, m => m.m.ParticipantCityAId, c => c.CityID, (m, c) => new { m.m, m.cA, cB = c.DefaultIfEmpty() })
.SelectMany(w => w.cB.Select(cB => new { m = w.m, cA = w.cA, cB }))
.GroupJoin(repository.Cities, m => m.m.ParticipantCityBId, c => c.CityID, (m, c) => new { m.m, m.cA, m.cB, cC = c.DefaultIfEmpty() })
.SelectMany(t => t.cC.Select(cC => new { m = t.m, cA = t.cA, cB = t.cB, cC }))
.Select(
m =>
new
{
TotalParticipant = m.m.TotalParticipant,
MeetingID = m.m.MeetingID,
CityID = m.cA.CityID,
CityName = m.cA.CityName,
MeetingDate = m.m.MeetingStartDate,
MeetingName = m.m.MeetingName,
NameofMeetingCityIdA = m.cA != null ? m.cA.CityName : null,
NameofMeetingCityIdB = m.cB != null ? m.cB.CityName : null,
NameofMeetingCityIdC = m.cC != null ? m.cC.CityName : null
})
.OrderBy(x => x.CityName)
.AsEnumerable()
.Select(
i => new
{
Value = i.MeetingID.ToString(),
DisplayValue = string.Format("{0} ({1:dd MMMM yyyy})", i.NameofMeetingCityIdA, i.MeetingDate)),
Expired = i.MeetingDate < DateTime.UtcNow,
MaksimumCount = i.TotalParticipant,
CurrentCount = GetMeetingCount(i.MeetingID)
}
).ToList();
var selectItems = new List<MyHelpers.MySelectItem>(meetingsQuery.Count);
foreach (var record in meetingsQuery)
{
var item = new MyHelpers.MySelectItem
{
Text = record.DisplayValue,
Value = record.Value
};
//If Meeting Date is expired or Count for the current record >= Total Participant
if (record.Expired || record.CurrentCount >= record.MaksimumCount)
{
item.Class = "disabled";
item.Disabled = "disabled";
}
selectItems.Add(item);
}
ViewBag.MeetingData = selectItems;
}
public int GetMeetingCount(int meetingId)
{
return repository.Applicants.Count(x => x.MeetingId == meetingId);
}
The first running of the code I encountered "There is already an open DataReader associated with this Command which must be closed first." error. But adding "MultipleActiveResultSets=True;" parameter to teh ConnectionString solved this problem and now it works properly.

Resources