At least 3 ways I can think of that this could be done:-
1st (ideal) - in a single telerik grid which has around 8 columns, 1st col would list all table entries with the next 6 for displaying different dates submitted for each entry but not all necessarily having a value for each entry, final col would link to each entry on a separate page to allow new dates to be submitted via datepicker or to be edited.
Main problem is I need to be able to display each of the dates on the grid in different colours depending on each col, by this I mean I record a date in 1st col of which has a yearly renewal so if >6months then it's colour 1, >1month colour 2, <1month colour 3 and finally if past 1 year mark then colour 4.
There are also 2 different possible renewal lengths for the other col's.
2nd - Each different renewal length would get its own grid so 1st for 1y, 2nd for 2nd length and 3rd for 3rd length.
3rd (likely) - 4 grids to replace the colours it would simply display each category so 1 grid would show all entries which had more than 6months, grid 2 would show greater than 1month, grid 3 would show less than 1month and grid 4 would show past time length.
I have no clue how best to sort the dates out in a way that would do what I need it to but I figure either option 1 will be possible or option 3 is the simplest.
Edit -
using System
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace (...).Models.DTO
{
public class ...DTO
{
public int Id { get; set; }
public string Name { get; set; }
//public string C1D
//{
// get
// {
// if (C1D < DateTime.Today.AddDays(-183)) return "Green";
// }
//}
public string C1D
{
get
{
if ((C1D = DateTime.ParseExact(C1D, "yyyy/mm/dd", null)) < DateTime.Today.AddDays(-183)) return "Green";
}
set;
}
public string C2D { get; set; }
Here it shows how I have tried to setup C1D in 2 different ways and for C2D how I usually setup the cols which go into the telerik grid.
[GridAction]
public ActionResult _List(int? Id)
{
List<...DTO> ret = new List<...DTO>();
_db.(...).ToList().ForEach(x =>
{
ret.Add(new ...DTO
{
Id = x.Id,
Name = x.(...)Name,
C1D = (x.C1SD.HasValue) ? x.C1SD.Value.ToShortDateString() : "",
C2D = (x.C2SD.HasValue) ? x.C2SD.Value.ToShortDateString() : "",
This is how I would go about setting it up in the controller for displaying the data in the telerik grid.
Below is how I setup the view
<% Html.Telerik().Grid<(...).Models.DTO.(...)DTO>()
.Name("...List")
.DataKeys(dk => dk.Add(x => x.Id))
.Columns(c =>
{
c.Bound(x => x.Name);
c.Bound(x => x.C1D)
.Title("...");
c.Bound(x => x.C2D)
.Title("...");
c.Bound(x => x.C3D)
.Title("...");
c.Bound(x => x.C4D)
.Title("...");
c.Bound(x => x.C5D)
.Title("...");
c.Bound(x => x.C6D)
.Title("...");
c.Bound(x => x.C7D)
.Title("...");
})
.Sortable()
.Filterable()
.DataBinding(db => db.Ajax().Select("_List", "..."))
.Render();
%>
Edit 2 -
I've also tried
.ClientEvents(e => e.OnDataBound("onDataBound"))
function onDataBound(e) {
if (e.dataItem.C1D > DateTime.Today.AddDays(183)) {
e.cell.style.backgroundColor = "green";
}
if (e.dataItem.C1D > DateTime.Today.AddDays(30)) {
e.cell.style.backgroundColor = "orange";
}
if (e.dataItem.C1D > DateTime.Today) {
e.cell.style.backgroundColor = "red";
}
if (e.dataItem.C1D <= DateTime.Today) {
e.cell.style.backgroundColor = "purple";
}
}
and upon reaching this page it would break into code and say "Microsoft JScript runtime error: 'dataItem.C1D' is null or not an object" and "Microsoft JScript runtime error: 'cell.style' is null or not an object" and then display the page with all the dates in the grid so those items aren't null but is there otherwise some other code/format I should be using to perform this function?
And also looked at http://demos.telerik.com/aspnet-mvc/grid/customformatting in regards to .cellaction like below
.CellAction(cell =>
{
if (cell.Column.Title == "Title Name")
{
if (cell.DataItem.C1D > DateTime.Today.AddDays(183))
{
//Set the background of this cell only
cell.HtmlAttributes["style"] = "background:red;";
}
}
})
and I had to change .Name to .Title since it didn't recognise .Name, but I get the error msg "Error 1 Operator '>' cannot be applied to operands of type 'string' and 'System.DateTime' " so seems I won't be able to perform this complex a task in a cell action.
I've also posted this on the telerik forums attached to another question but so far no reply
http://www.telerik.com/community/forums/aspnet-mvc/grid/telerik-grid-row-custom-formatting-on-either-bit-int-string-field.aspx
Edit 3 -
Additional Controller code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using (Database Name).Models;
using (Database Name).Models.DTO;
using Telerik.Web.Mvc;
using Telerik.Web.Mvc.UI;
namespace (Database Name).Controllers
{
public class (Controller Name)Controller : Controller
{
(Database Name)Entities _db = new (Database Name)Entities();
public ActionResult List()
{
return View();
}
That's it now there's nothing left which I can possibly provide since there's nothing else which could have any kind of affect on the telerik grid so if there is still something else which might be hidden some place else that I may be missing then please explain what that might be since the only thing I haven't included is the code to do with the Create and Edit pages but all they involve is making each simple record then allowing the user to change the dates recorded.
Edit 3 :
When you do :
When you do _db.(...).ToList().ForEach(x =>
{
ret.Add(new ...DTO
{
Id = x.Id,
Name = x.(...)Name,
C1D = (x.C1SD.HasValue) ? x.C1SD.Value.ToShortDateString() : "",
C2D = (x.C2SD.HasValue) ? x.C2SD.Value.ToShortDateString() : "",
}
}
x would be the ObjectFromDB, you don't want to assign each properties of the DTO, you want to pass the baseObject (witch is x), then return the value you want from x.
If you can provide me with youre solution using putfile or something else I can take a look at it if you want to but right now I don't know how it would be possible to help you more than that...
End Edit 3
Can you put some code?
I'll go with solution 1.
You could add a css class to a using ClientTemplate, if it's > [timespan], I think that you should add a colum that is bound on a property that could return name of a css class or an empty string depending on the time span. Let say you have a DateCol1 property witch is a DateTime you could add a DateCol1Css property that goes like this :
public string DateCol1Css
{
get
{
if(DateCol1 < DateTime.Now.AddMonths(-1)) return "Color1"; //witch is less than a month
if(DateCol1 < DateTime.Now.AddMonths(-3)) return "Color2"; //witch is less than 3 months
if(DateCol1 < DateTime.Now.AddMonths(-6)) return "Color3"; //witch is less than 6 months
return "";
}
}
public string DateCol2Css
{
get
{
if (DateCol2 < DateTime.Now.AddDays(-10)) return "Color1"; //witch is less than 10 days
if (DateCol2 < DateTime.Now.AddDays(-30)) return "Color2"; //witch is less than 30 days
return "";
}
}
public string DateCol3Css
{
get
{
if (DateCol3 < DateTime.Now.AddMonths(-1)) return "Color1"; //witch is less than a month
if (DateCol3 < DateTime.Now.AddMonths(-3)) return "Color2"; //witch is less than 3 months
if (DateCol3 < DateTime.Now.AddMonths(-6)) return "Color3"; //witch is less than 6 months
return "";
}
}
And the grid should be like this :
<%= Html.Telerik().Grid<SerializableAdmin>()
.Name("Grid")
.Columns(colums =>
{
colums.Bound(c => c.FirstName);
colums.Bound(c => c.Id);
colums.Bound(c => c.Id).ClientTemplate("<span class=\"<#=DateCol1Css#>\"<#=DateCol1#></span>");
colums.Bound(c => c.Id).ClientTemplate("<span class=\"<#=DateCol2Css#>\"<#=DateCol2#></span>");
colums.Bound(c => c.Id).ClientTemplate("<span class=\"<#=DateCol3Css#>\"<#=DateCol3#></span>");
})
%>
Edit :
Take a look at this code, you pass the object from the database to your new object and add property with get only on the db object.
public class ObjectDTO
{
public ObjectFromDB BaseObject { get; set; }
public int Id
{
get { return BaseObject.Id; }
}
public string Name
{
get { return BaseObject.Name; }
}
public string C1D
{
get
{
if (BaseObject.C1SC.HasValue && BaseObject.C1SC < DateTime.Now.AddDays(-183)) return "Green";
return string.Empty;
}
}
public string C2D
{
get
{
if (BaseObject.C2SC.HasValue && BaseObject.C2SC < DateTime.Now.AddDays(-183)) return "Green";
return string.Empty;
}
}
}
[GridAction]
public ActionResult _List(int? Id)
{
List<ObjectDTO> ret = new List<ObjectDTO>();
_db.GetObjectFromDB().ToList().ForEach(x =>
{
ret.Add(new ObjectDTO { ObjectFromDB = x } );
});
}
For this code block, have you try to cast the string in datetime?
.CellAction(cell =>
{
if (cell.Column.Title == "Title Name")
{
if (!string.IsNullOrEmpty(cell.DataItem.C1D) && DateTime.ParseExact(cell.DataItem.C1D, "yyyy/mm/dd", null) > DateTime.Today.AddDays(183))
{
//Set the background of this cell only
cell.HtmlAttributes["style"] = "background:red;";
}
}
})
And your ...Dto property for the CssColor should be like this :
public class ...DTO
{
public int Id { get; set; }
public string Name { get; set; }
public string C1D
{
get
{
if (!C1SD.HasValue) return string.Empty;
return (DateTime.ParseExact(C1SD, "yyyy/mm/dd", null) < DateTime.Today.AddDays(-183)) ? "Green" : "";
}
}
}
So your GridAction would be like this :
[GridAction]
public ActionResult _List(int? Id)
{
List<...DTO> ret = _db.(...).ToList();
...
Let me know if it helps!
This was what I tried to do from the start
[GridAction]
public ActionResult _List(int? Id)
{
List<...DTO> ret = new List<...DTO>();
_db.(...).ToList().ForEach(x =>
{
ret.Add(new ...DTO
{
Id = x.Id,
Name = x.(...)Name,
C1D = (x.C1SD.HasValue) ? x.C1SD.Value.ToShortDateString() : "",
C2D = (x.C2SD.HasValue) ? x.C2SD.Value.ToShortDateString() : "",
Trick is to do all the calculations in the controller and leave the model and view very basic.
Model- left em all as string and basically did public string blah { get; set;} for each date col and then for each col you want to do something complex like my date calculations you would make an additional col, this would be for the colour/whatever feature you want heck you could even setup an admin function so if they don't have win auth or aren't in correct role etc then it would splarf the data or de-link a url link.
Controller- well as you can see above thats how I sorted out the dates showing up and now the surprisingly simple way to sort out the colour or w/e, (example thing blahDTO bdt = new blahDTO(); )
if (x.TestVal1 != null)
{
if ((x.TestVal1) > (DateTime.Today.AddMonths(6)))
{
bdt.Colourflag1 = "green";
}
Now it doesn't have to be green, it could be true false tom dick or jane w/e but it would just have to be a value assigned based on certain unique conditions.
View- when I realised it could be this easy I facepalmed myself, anyway yeh so c.Bound(x => x.Colourflag1).Hidden(true); next step
.ClientEvents(events => events.OnRowDataBound("onRowDataBound"))
<script type="text/javascript">
function onRowDataBound(e) {
if (e.dataItem.TestVal1 == "green") {
e.row.cells[1].style.backgroundColor = "green";
}
and hey presto you just turn the 1st row/col cell green and this can be twisted and used into w/e e.row.cell[?]. can be used for and you have a single cell do all magic ye ha rolled into 1.
Now I know my jscript code is wasteful since I'm sure at this point you could make the green be an object which would then affect the the next object so if yellow then it makes the background colour code fit in yellow.
If anybody has any questions or jscript advice feel free to ask/comment.
Related
I am trying to get the number of how many times player.userID shows in a list but I can't seem to figure out how, I have searched the internet for an hour now.
class ConfigData
{
[JsonProperty(PropertyName = "Ban")]
public uint ban = 3;
[JsonProperty(PropertyName = "Kick")]
public uint kick = 2;
[JsonProperty(PropertyName = "Banned Message")]
public string kickMessage = "You are banned";
}
class StoredData
{
public List<ulong> Reports = new List<ulong>();
public List<ulong> Banned = new List<ulong>();
public List<ulong> Kicked = new List<ulong>();
}
void OnPlayerConnected(BasePlayer player)
{
int count = storedData.Reports.Count(reportedID => reportedID == player.userID);
Puts($"{player.userID} has {count} reports");
if (count >= configData.ban)
{
storedData.Banned.Add(player.userID);
SaveData();
return;
}
if (storedData.Banned.Contains(player.userID))
{
Network.Net.sv.Kick(player.net.connection, rust.QuoteSafe(configData.kickMessage));
return;
}
else
{
return;
}
}
I can post the full code if needed.
The Count method accepts a lambda that tells it the condition on which to count.
Since your reports are just a list of user IDs, all you need to do is:
int count = storedData.Reports.Count(reportedID => reportedID == player.userID);
if (count >= configData.ban) // NOTE: changed this to >=
{
...
}
As a side note, if it was a list of objects instead, and you wanted to compare to a property named someProperty, then it would be:
report => report.someProperty == player.userID.
A lambda is just a shorthand for a function; the part before the => is the parameter list (here, it just accepts a single parameter - the current element of storedData.Reports). The parameter name is arbitrary (your choice).
The part behind the => is the function body, with implicit return, so
reportedID == player.userID is like
{ return reportedID == player.userID; }.
The Count method basically walks through the IDs in Reports, and for each one, it asks the lambda if it should count it or not, by passing that ID to the lambda, and checking if the lambda returns true or false.
P.S.
In your code it says:
if (!storedData.Banned.Contains(player.userID)) { /* kick */ }
Are you sure you want to kick the players that are not in the banned list? Check the logic that relates to kicking/banning (maybe do some tests), it doesn't look quite right to me.
I have three classes:
public class Error
{
public List<ErrorOccurrenceDetails> Occurrences { get; set; }
}
public class ErrorOccurrenceDetails
{
public Dictionary<DateTime, ErrorTime> Times { get; set; }
}
public class ErrorTime
{
public string Version { get; set; }
}
There's an Error that has multiple Occurrences that happened in different Times. Each time can occur on a different Version.
I have a list of Errors. I need to remove errors which do not have provided version, for example if user only wants to see errors in version "1.0", other versions (such as "1.1", "1.2") need to be removed. However, if an error has occurrences on version "1.0" AND others, filter should delete only bad occurrences, not entire error.
I tried to do it this way:
private IList<Error> errors;
private void Filter(string filterVersion)
{
var errorsToRemove = new Dictionary<int, ErrorOccurrenceDetails>();
foreach (Error error in this.errors)
{
int index = this.errors.IndexOf(error);
var listOfSearchedItems = error.Occurences.ToList();
listOfSearchedItems.RemoveAll(x => x.Times.Values.Any(y => y.Version != filterVersion));
var errorOccurences = error.Occurences.Except(listOfSearchedItems).ToList();
if (errorsToRemove.ContainsKey(index))
{
errorsToRemove[index].AddRange(errorOccurences);
}
else
{
errorsToRemove.Add(index, errorOccurences);
}
}
}
I'm trying to put all errors that need to be removed into errorsToRemove dictionary, where key is error index in this.errors, and value is a list of occurrences not on searched version.
It kinda works, but sometimes doesn't remove bad versions and causes some correct versions to also be removed, so there is a hole I haven't noticed.
Sample error list in this fiddle: https://dotnetfiddle.net/Kxq50i
Based on Heinzi's answer I decided to use a much simpler approach. I think I wanted to avoid Collection was modified; enumeration operation may not execute exception at all costs and started doing stupid things.
private IList<Error> errors;
private static void Filter(string filterVersion)
{
for (int index = 0; index < errors.Count; index++)
{
Error error = errors[index];
foreach (var occurrence in error.Occurrences)
{
var toRemove = occurrence.Times.Keys.Where(key => occurrence.Times[key].Version != filterVersion).ToList();
foreach (var key in toRemove)
{
occurrence.Times.Remove(key);
}
if (occurrence.Times.Count == 0)
{
errors[index] = null; // not deleted to prevent index shift, null is hidden in UI
}
}
}
}
The solution is updated in this fiddle.
The reason might be the following lines which might cause the items of the original error.Occurences to be removed:
var listOfSearchedItems = error.Occurences.ToList();
listOfSearchedItems.RemoveAll(x => x.Times.Values.Any(y => y.Version != filterVersion));
Try replacing those 2 lines with the one below:
var listOfSearchedItems = error.Occurences.Where(x => x.Times.Values.Any(y => y.Version == filterVersion)); // Note: Here we also replaced the "!=" with "=="
When using Linq, it is easier to think in terms of what to include rather than what you want to remove and write your code that way. For example:
private static IList<Error> Filter(string filterVersion)
{
var filtered = errors.Where(error => error.Occurrences.Any(occurrence => occurrence.Times.Any(kvp => kvp.Value.Version == filterVersion)))
.Select(error =>
{
return new Error
{
Occurrences = error.Occurrences
.Where(occurrence => occurrence.Times.Any(kvp => kvp.Value.Version == filterVersion))
.Select(occurrence =>
{
return new ErrorOccurrenceDetails
{
Times = new Dictionary<DateTime, ErrorTime>(occurrence.Times.Where(kvp => kvp.Value.Version == filterVersion))
};
})
.ToList()
};
})
.ToList();
return filtered;
}
Another possible benefit of this approach is that you are not modifying your original data, so you can apply different filters without having to re-read it.
This is for a .net core 3.1 application, using Blazor for front end.
I have a list of dates that I need to take, and then build an "analysis" report using those dates. The analysis basically needs to look at the dates and tell me how many dates fall on each day of the week, and also how many dates are in each month of the year. This fis for an Human Resources application where they are tracking employee absences.
I have a List that I've built, and I'm passing it into a method that then performs an analysis.
public class DateHourResponseModel
{
public DateTime Date { get; set; }
public int Hours { get; set; }
}
I figured I could then take that list, and create a list of "Responses", each for a different day of the week, and month of the year. I figured for "Type" I could just use the DateTime.DayOfWeek, DateTime.Month and get an into (0-6 for day of week, 1-12 for month) which is why I have the "IsMonth" bool on there.
public class AbsenceAnalysisResponse
{
public int Type { get; set; }
public bool IsMonth { get; set; }
public int Count { get; set; }
public int Hours { get; set; }
}
And This class, which is just a list of the above:
public class AbsenceAnalysis
{
public List<AbsenceAnalysisResponse> Responses { get; set; }
}
My question is: Is there a way to build this analysis report by doing a foreach on the list of dates that I start with? I haven't figured out a way to create this list without doing something like this:
var analysisResponses = new List<AbsenceAnalysisResponse>
{
new AbsenceAnalysisResponse
{
Type = 0,
IsMonth = false,
Count = dateHourModel.Count(x => (int)x.Date.DayOfWeek == 0),
Hours = dateHourModel.Where(x => (int)x.Date.DayOfWeek == 0).Sum(x => x.Hours)
},
I feel like an idiot because I know there has got to be a more elegant way of doing this, and maybe the problem is how I'm approaching it. I have the analysis working and displaying on the front end but I absolutely hate how I'm creating the list of "responses". I'm still pretty green behind the ears with this, and I don't know if I just haven't been searching the right questions online or what, but I haven't found anything where someone is doing something similar. Thanks for any help, and please let me know if there is any information I need to provide.
Something like this should work:
var models = new List<DateHourResponseModel>(); //Should be a filled list, not empty like this
var modelMap = new Dictionary<(int, bool), AbsenceAnalysisResponse>();
foreach (DateHourResponseModel dateHour in models)
{
Add(type: (int)dateHour.Date.DayOfWeek, isMonth: false);
Add(type: dateHour.Date.Month, isMonth: true);
void Add(int type, bool isMonth)
{
(int, bool) key = (type, isMonth);
//Try to get existing responses
if(!modelMap.TryGetValue(key, out AbsenceAnalysisResponse response))
{
//Create if first time adding to it
modelMap[key] = response = new AbsenceAnalysisResponse
{
Type = type,
IsMonth = isMonth,
Count = 0,
Hours = 0
};
}
response.Count += 1;
response.Hours += dateHour.Hours;
}
}
//convert to list, can order if needed with .OrderBy()
List<AbsenceAnalysisResponse> analysisResponses = modelMap.Values.ToList();
The idea would be to loop through each model and add/modify to the list. Instead of searching through the list, a dictionary can be used with a unique key. In this case type + isMonth, in tuple form, but it could also be a string "{type}-{isMonth}" or something. If the key is not found then it will be created, otherwise just modified. At the end, turn the Dictionary into a list of its values. There are other ways of doing this, but this should be a good approach
Just wanted to post another solution I found while tinkering with this. I really liked Gekctek's answer, and used that initially. I think this one might be slightly more readable? Happy to receive any feedback.
private AbsenceAnalysis GetAbsenceAnalysisFromData(List<DateHourResponseModel> dateHourModel)
{
var analysis = new List<AbsenceAnalysisResponse>();
foreach (var data in dateHourModel)
{
var week = analysis.FirstOrDefault(x =>
x.Type == (int)data.Date.DayOfWeek && x.IsMonth == false);
var month = analysis.FirstOrDefault(x =>
x.Type == (int)data.Date.Month && x.IsMonth == true);
if (week == null)
{
week = new AbsenceAnalysisResponse
{
Count = 0,
Hours = 0,
IsMonth = false,
Type = (int)data.Date.DayOfWeek
};
analysis.Add(week);
}
if (month == null)
{
month = new AbsenceAnalysisResponse
{
Count = 0,
Hours = 0,
IsMonth = true,
Type = data.Date.Month
};
analysis.Add(month);
}
week.Count += 1;
week.Hours += data.Hours;
month.Count += 1;
month.Hours += data.Hours;
}
I have a silverlight app using Prism practices; the current code does a search by first name or last name or gender. regaring the names, I would like to alter the code to somethng like 3 characters because now it is searching as long as one character is found the name will display so you can see the issue, can I adjust the code here to only select those with a 3 character match? lets leave alone the issue of a name with less than 3 but we can allow anything there then.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace PBM.Web.Classes
{
public class Search
{
public static IQueryable<Patient> GetSearchQueryPatient(IQueryable<Patient> pSearchQuery, Patient pPatient)
{
if (!string.IsNullOrEmpty(pPatient.FirstName))
{
pSearchQuery = pSearchQuery.Where(item => item.FirstName.Contains(pPatient.FirstName));
}
if (!string.IsNullOrEmpty(pPatient.LastName))
{
pSearchQuery = pSearchQuery.Where(item => item.LastName.Contains(pPatient.LastName));
}
if (pPatient.Gender.HasValue && pPatient.Gender.Value > 0)
{
pSearchQuery = pSearchQuery.Where(item => item.Gender.Value == pPatient.Gender.Value);
}
pSearchQuery = pSearchQuery.OrderBy(item => item.FirstName).ThenBy(item => item.LastName);
return pSearchQuery;
}
}
}
If I've read your requirement and sample code correctly, simply add a length check to your tests should work:
if (!string.IsNullOrEmpty(pPatient.FirstName) && pPatient.FirstName.Length > 2)
{
pSearchQuery = pSearchQuery.Where(item => item.FirstName.Contains(pPatient.FirstName));
}
It does mean that if the name is less than 3 characters it won't match at all, so what you want to do is then check if this search returned anything and if not do the simple any length search:
if (!string.IsNullOrEmpty(pPatient.FirstName))
{
// First look for a 3 or more character match
if (pPatient.FirstName.Length > 2)
{
pSearchQuery = pSearchQuery.Where(item => item.FirstName.Contains(pPatient.FirstName));
}
// If didn't find anything do the simple search
if (!pSearchQuery.Any())
{
pSearchQuery = pSearchQuery.Where(item => item.FirstName.Contains(pPatient.FirstName));
}
}
I am using the latest version Telerik MVC controls. I am using ASP.NET MVC 3 with razor.
I have a grid that lists all of my grant applications. I am wanting to use a grid that loads these grant applications via AJAX. I also need to create a client template column that has action links. These action links can vary depending on the state of each grant application.
I worked through the article at: http://gedgei.wordpress.com/2011/07/02/telerik-mvc-grid-actionlink-column/. I implemented the code as is and it works, I can create a client template column with a link in it. In my scenario I need to be able to pass in 2 parameters to the helper method, like:
column.ActionLink("Open", "Edit", "GrantApplication", item => new { id = item.Id, applicationStateId = item.GrantApplicationStateType.Id });
How I eventually implement this method in the end will change, but for now I am playing with these 2 input parameters to see how they are passed through and how I can retrieve them in the helper method.
The first question that I have regarding the article, why does the writer do the following:
var builder = factory.Template(x =>
{
var actionUrl = urlHelper.Action(action, controller, routeValues.Compile().Invoke(x));
return string.Format(#"{1}", actionUrl, linkText);
});
I can only assume that this is the server side template that is created? But nothing displays in the grid, so how do I skip this part and go directly to the client template (this is what I actually need).
The following part is also confusing because when the first parameter (id) check comes through then it is of type ParameterExpression so it goes into the true part of the if, but when the second parameter (grant application state id) comes in then it is of another type (not sure what) so then it goes into the false part of the if statement:
switch (argument.NodeType)
{
case ExpressionType.Constant:
value = ((ConstantExpression)argument).Value;
break;
case ExpressionType.MemberAccess:
MemberExpression memberExpression = (MemberExpression)argument;
if (memberExpression.Expression is ParameterExpression)
value = string.Format("<#= {0} #>", memberExpression.Member.Name);
else
value = GetValue(memberExpression);
break;
default:
throw new InvalidOperationException("Unknown expression type!");
}
When the second paramenter values goes into the false part of the if statement it fails here:
value = GetValue(memberExpression);
..and gives the following error message which I have no idea what it is:
variable 'item' of type MyProject.ViewModels.GrantApplicationListViewModel' referenced from scope '', but it is not defined
Here is my view model:
public class GrantApplicationListViewModel
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string FullNameDisplay
{
get { return FirstName + " " + LastName; }
}
public DateTime CreatedDate { get; set; }
public GrantApplicationStateType GrantApplicationStateType { get; set; }
}
Here is my partial grid declaration in my view:
#(Html.Telerik()
.Grid<GrantApplicationListViewModel>()
.Name("grdGrantApplications")
.Columns(column =>
{
column.Bound(x => x.Id)
.ClientTemplate(
"<label class=\"reference-number\">" + "<#= Id #>" + "</label>"
)
.Title("Ref #")
.Width(70);
column.Bound(x => x.FullNameDisplay)
.Title("Owner")
.Width(200);
column.Bound(x => x.GrantApplicationStateType.Name)
.Title("Status")
.Width(90);
//column.ActionLink("Edit", "Edit", "GrantApplication", item => new { id = item.Id });
column.ActionLink("Open", "Edit", "GrantApplication", item => new { id = item.Id, applicationStateId = item.GrantApplicationStateType.Id });
})
.DataBinding(dataBinding => dataBinding.Ajax().Select("AjaxGrantApplicationsBinding", "Home"))
.Pageable(paging => paging.PageSize(30))
.TableHtmlAttributes(new { #class = "telerik-grid" })
)
What I am trying to achieve with the above is code is something to the effect of:
if grant application id = 1
then return Edit link and View link
else
then return Details link
How would I do the above? Is the code in that article the only way to do it? Isn't there a more simplar way? I did Google and couldn't find much help on what I want to do. Has any one else come across something like this?
If all you want is the client template to display different content based on the application id, it would be simpler to just put a conditional in the client template.
column.Bound(x => x.Id)
.ClientTemplate("<# if (Id == 1 ) { #> Edit Link and View Link <# } else { #> Details Link <# } #>");
The Edit, View, and Details links would be put in the same way they are put in without the conditional.