I have several jqgrids running and all are functioning fine. However, when I do a search, I am only displaying ten search results per page. Whenever there are more than ten results, clicking on page two has no effect on the grid. Here is one of my controller actions, pay particular attention to the if satatement where search is true....
EDIT
I think I may have found a clue as to what may be causing my issue. You see I have several subgrids under the main grid. In terms of my java code I have object-A which has a list of object-B
, thus A has a subgrid of B. The way i am building up the json string to feed to the grid is by iterating over the list of B contained in A. I did not write a query of some kind to say order by, and limit the results etc.
So i guess the real question should be how to build a finder on a collection so that the contents can be arranged and ordered as i wish?
Here is the action I am calling for one of my entities described as B above. Pay particular attention to where i said person.getContacts()
#RequestMapping(value = "contactjsondata/{pId}", method = RequestMethod.GET)
public #ResponseBody String contactjsondata(#PathVariable("pId") Long personId, Model uiModel, HttpServletRequest httpServletRequest) {
Person person = Person.findPerson(personId);
String column = "id";
if(httpServletRequest.getParameter("sidx") != null){
column = httpServletRequest.getParameter("sidx");
}
String orderType = "DESC";
if(httpServletRequest.getParameter("sord") != null){
orderType = httpServletRequest.getParameter("sord").toUpperCase();
}
int page = 1;
if(Integer.parseInt(httpServletRequest.getParameter("page")) >= 1){
page = Integer.parseInt(httpServletRequest.getParameter("page"));
}
int limitAmount = 10;
int limitStart = limitAmount*page - limitAmount;
List<Contact> contacts = new ArrayList<Contact>(person.getContacts());
double tally = Math.ceil(contacts.size()/10.0d);
int totalPages = (int)tally;
int records = contacts.size();
StringBuilder sb = new StringBuilder();
sb.append("{\"page\":\"").append(page).append("\", \"records\":\"").append(records).append("\", \"total\":\"").append(totalPages).append("\", \"rows\":[");
boolean first = true;
for (Contact c: contacts) {
sb.append(first ? "" : ",");
if (first) {
first = false;
}
sb.append(String.format("{\"id\":\"%s\", \"cell\":[\"%s\", \"%s\", \"%s\"]}",c.getId(), c.getId(), c.getContactType().getName() ,c.getContactValue()));
}
sb.append("]}");
return sb.toString();
}
To fix the issue with pagination you need to replace the following block of code
for (Contact c: contacts) {
sb.append(first ? "" : ",");
if (first) {
first = false;
}
sb.append(String.format("{\"id\":\"%s\", \"cell\":[\"%s\", \"%s\", \"%s\"]}",c.getId(), c.getId(), c.getContactType().getName() ,c.getContactValue()));
}
with:
for (int i=limitStart; i<Math.min(records, limitStart+limitAmount); i++){
Contact c = contacts[i];
sb.append(first ? "" : ",");
if (first) {
first = false;
}
sb.append(String.format("{\"id\":\"%s\", \"cell\":[\"%s\", \"%s\", \"%s\"]}",c.getId(), c.getId(), c.getContactType().getName() ,c.getContactValue()));
}
Another option is using loadonce:true to let the jqGrid handle pagination and sorting. In this case you don't need to make changes described above
Related
I am working for a mobile application and using Spring Boot as a backend and building REST APIs. So now, I need to implement like and dislike feature. That is if a user hits like (thumbs up icon) then count should be increased and that count should be displayed there and if hits dislike (thumbs down icon) then like count should be decreased and count should be displayed then also. But what I wrote for like and dislike is not as expected as it should be.
Actual working should be as follows:
1. If user A hits like to post A, then count of post A should be increased to 1.
2. If user B also hits like to post A then count of post A should be increased from 1 to 2. (means total like count of Post A is 2 now)
3. If user A again hits like button then it will be counted as dislike and count should get decreased from 2 to 1. (Now current count should be 1 again for post A).
So the like-dislike feature should work this way. But my code is not working as expected.
Below is my REST controller:
#RequestMapping(value = RestApiUrl.likepost, method = {RequestMethod.POST, RequestMethod.GET }, produces = {MediaType.APPLICATION_JSON_VALUE })
public ResponseEntity<?> likepost(HttpServletRequest request, #RequestParam("userid") String userid, #RequestParam("postid") String smsid) {
CustomResponse = ResponseFactory.getResponse(request);
int lcount = 0, dcount = 0, likcount = 0, postlike = 0;
FavouritePost favPost = null;
Post messageid = null, newpost = null;
try {
Long postid = Long.parseLong(smsid);
Long uid = Long.parseLong(userid);
User userbyid = userDao.findByUserid(uid);
messageid = postDao.findByPostid(postid);
postlike = messageid.getLike_count();
favPost = favouritePostDao.findByPostidAndUserid(messageid, userbyid);
if(favPost == null) {
favPost = new FavouritePost();
likcount = favPost.getLikecount();
lcount = likcount + 1;
favPost.setUserid(userbyid);
favPost.setCreatedby(userbyid);
favPost.setPostid(messageid);
favPost.setLikecount(lcount);
favouritePostDao.save(favPost);
messageid.setModifiedby(userbyid);
messageid.setModifieddate(new Date());
messageid.setLike_count(postlike+1);
newpost = postDao.save(messageid);
CustomResponse.setResponse(newpost);
CustomResponse.setStatus(CustomStatus.OK);
CustomResponse.setStatusCode(CustomStatus.OK_CODE);
CustomResponse.setResponseMessage(CustomStatus.SuccessMsg);
}else {
dcount = favPost.getDislikecount();
favPost.setUserid(userbyid);
favPost.setModifiedby(userbyid);
favPost.setModifieddate(new Date());;
favPost.setPostid(messageid);
favPost.setDislikecount(dcount+1);;
favouritePostDao.save(favPost);
messageid.setModifiedby(userbyid);
messageid.setModifieddate(new Date());
if(postlike > 0) {
int count =postlike-1;
messageid.setLike_count(count);
}else {
int count =postlike+1;
messageid.setLike_count(count);
}
newpost = postDao.save(messageid);
CustomResponse.setResponse(newpost);
CustomResponse.setStatus(CustomStatus.OK);
CustomResponse.setStatusCode(CustomStatus.OK_CODE);
CustomResponse.setResponseMessage(CustomStatus.SuccessMsg);
}
} catch (Exception e) {
e.printStackTrace();
CustomResponse.setResponse("Error occurred! please try again");
CustomResponse.setStatus(CustomStatus.Error);
CustomResponse.setStatusCode(CustomStatus.Error_CODE);
CustomResponse.setResponseMessage(CustomStatus.ErrorMsg);
}
return new ResponseEntity<ResponseDao>(CustomResponse, HttpStatus.OK);
}
Please help me in the implementation of like-dislike feature for a mobile application. A concept/idea would be great of how to do this.
I have an MVC application with a dynamic table on one of the pages, which the users defines how many columns the table has, the columns order and where to get the data from for each field.
I have written some very bad code in order to keep it dynamic and now I would like it to be more efficient.
My problem is that I don't know how to define the columns I should get back into my IEnumerable on runtime. My main issue is that I don't know how many columns I might have.
I have a reference to a class which gets the field's text. I also have a dictionary of each field's order with the exact property It should get the data from.
My code should look something like that:
var docsRes3 = from d in docs
select new[]
{
for (int i=0; i<numOfCols; i++)
{
gen.getFieldText(d, res.FieldSourceDic[i]);
}
};
where:
docs = List from which I would like to get only specific fields
res.FieldSourceDic = Dictionary in which the key is the order of the column and the value is the property
gen.getFieldText = The function which gets the entity and the property and returns the value
Obviously, it doesn't work.
I also tried
StringBuilder fieldsSB = new StringBuilder();
for (int i = 0; i < numOfCols; i++)
{
string field = "d." + res.FieldSourceDic[i] + ".ToString()";
if (!string.IsNullOrEmpty(fieldsSB.ToString()))
{
fieldsSB.Append(",");
}
fieldsSB.Append(field);
}
var docsRes2 = from d in docs
select new[] { fieldsSB.ToString() };
It also didn't work.
The only thing that worked for me so far was:
List<string[]> docsRes = new List<string[]>();
foreach (NewOriginDocumentManagment d in docs)
{
string[] row = new string[numOfCols];
for (int i = 0; i < numOfCols; i++)
{
row[i] = gen.getFieldText(d, res.FieldSourceDic[i]);
}
docsRes.Add(row);
}
Any idea how can I pass the linq the list of fields and it'll cut the needed data out of it efficiently?
Thanks, Hoe I was clear about what I need....
Try following:
var docsRes3 = from d in docs
select (
from k in res.FieldSourceDic.Keys.Take(numOfCols)
select gen.getFieldText(d, res.FieldSourceDic[k]));
I got my answer with some help from the following link:
http://www.codeproject.com/Questions/141367/Dynamic-Columns-from-List-using-LINQ
First I created a string array of all properties:
//Creats a string of all properties as defined in the XML
//Columns order must be started at 0. No skips are allowed
StringBuilder fieldsSB = new StringBuilder();
for (int i = 0; i < numOfCols; i++)
{
string field = res.FieldSourceDic[i];
if (!string.IsNullOrEmpty(fieldsSB.ToString()))
{
fieldsSB.Append(",");
}
fieldsSB.Append(field);
}
var cols = fieldsSB.ToString().Split(',');
//Gets the data for each row dynamically
var docsRes = docs.Select(d => GetProps(d, cols));
than I created the GetProps function, which is using my own function as described in the question:
private static dynamic GetProps(object d, IEnumerable<string> props)
{
if (d == null)
{
return null;
}
DynamicGridGenerator gen = new DynamicGridGenerator();
List<string> res = new List<string>();
foreach (var p in props)
{
res.Add(gen.getFieldText(d, p));
}
return res;
}
i have a single textbox named Keywords.
User can enter multiple strings for search.
How this is possible in mvc3?
I am using nhibernate as ORM.
Can i create criteria for this?
Edited Scenario
I have partial view to search job based on following values:
Keywords(multiple strings), Industry(cascading dropdown with functional area )//working well ,FunctionalArea//working well
Loaction(multiple locations), Experience//working well
In Controller i am retrieving these values from form collection.
What datatype should i use for keywords and location (string or string[] )?
public ActionResult SearchResult(FormCollection formCollection)
{
IList<Jobs> JobsSearchResultList = new List<Jobs>();
//string[] keywords = null;
string location = null;
int? industry = 0;
int? functionaArea = 0;
int? experience = 0;
string keywords = null;
if (formCollection["txtKeyword"] != "")
{
keywords = formCollection["txtKeyword"];
}
//if (formCollection["txtKeyword"] != "")
//{
// keywordAry = formCollection["txtKeyword"].Split(' ');
// foreach (string keyword in keywordAry)
// {
// string value = keyword;
// }
//}
......retrieving other values from formcollection
....
//Now passing these values to Service method where i have criteria for job search
JobsSearchResultList = oEasyJobsService.GetJobsOnSearchExists(keywords,industry,functionaArea,location,experience);
return View(JobsSearchResultList);
}
In Services i have done like:
public IList<EASYJobs> GetJobsOnSearchExists(string keywords, int? industryId, int? functionalAreaId, string location, int? experience)
{
IList<JobLocation> locationlist = new List<JobLocation>();
IList<Jobs> JobsList = null;
var disjunction = Expression.Disjunction();
ICriteria query = session.CreateCriteria(typeof(Jobs), "EJobs");
if (keywords != null)
{
foreach (string keyword in keywords)
{
string pattern = String.Format("%{0}%", keyword);
disjunction
.Add(Restrictions.InsensitiveLike("Jobs.keywords", pattern,MatchMode.Anywhere))
.Add(Restrictions.InsensitiveLike("YJobs.PostTitle",pattern,MatchMode.Anywhere));
}
query.Add(disjunction)
.Add(Expression.Eq("EASYJobs.Industry.IndustryId", industryId))
.Add(Expression.Eq("Jobs.FunctionalArea.FunctionalAreaId", functionalAreaId))
.Add(Expression.Eq("Jobs.RequiredExperience", experience)));
}
else
{..
}
JobsList = criteria.List<Jobs>();
}
Problems i am facing are:
In controller if i use string[],then Split(',') does not split the string with specified separator.It passes string as it is to Service.
2.In services i am trying to replace string with %{0}% ,strings with spaces are replaced/concat() here with given delimeter.
But the problem here is It always return the whole job list means not giving the required output.
Pleas help ...
As long as you have a delimiter you can break the input into pieces on you should be able to create an or expression with the parts. You can use a disjunction to combine an arbitrary number of criteria using OR's.
var criteria = session.CreateCriteria<TestObject>();
Junction disjunction = Restrictions.Disjunction();
var input = "key words";
foreach (var keyword in input.Split(" "))
{
ICriterion criterion = Restrictions.Eq("PropertyName", keyword);
disjunction.Add(criterion);
}
criteria.Add(disjunction);
Multiple keywords with special characters or extra spaces are replaced with single space with Regex expressions.
And then keywords are separated with Split("").
Its working as required....
if (!string.IsNullOrEmpty(keywords))
{
keywords = keywords.Trim();
keywords = System.Text.RegularExpressions.Regex.Replace(keywords, #"[^0-9a-zA-Z\._\s]", " ");
keywords = System.Text.RegularExpressions.Regex.Replace(keywords, #"[\s]+", " ");
if (keywords.IndexOf(" ") > 0)
{
string[] arr = keywords.Split(" ".ToCharArray());
for (int i = 0; i < arr.Length; i++)
{
if (!string.IsNullOrEmpty(arr[i]))
{
criteria.Add(Restrictions.Disjunction()
.Add(Expression.Like("EASYJobs.keywords", arr[i], MatchMode.Anywhere)));
}
}
}
else
{
criteria.Add(Restrictions.Disjunction()
.Add(Expression.Like("EASYJobs.keywords", keywords, MatchMode.Anywhere)));
}
}
While looking though some code of the project I'm working on, I've come across a pretty hefty method which does
the following:
public string DataField(int id, string fieldName)
{
var data = _dataRepository.Find(id);
if (data != null)
{
if (data.A == null)
{
data.A = fieldName;
_dataRepository.InsertOrUpdate(data);
return "A";
}
if (data.B == null)
{
data.B = fieldName;
_dataRepository.InsertOrUpdate(data);
return "B";
}
// keep going data.C through data.Z doing the exact same code
}
}
Obviously having 26 if statements just to determine if a property is null and then to update that property and do a database call is
probably very naive in implementation. What would be a better way of doing this unit of work?
Thankfully C# is able to inspect and assign class members dynamically, so one option would be to create a map list and iterate over that.
public string DataField(int id, string fieldName)
{
var data = _dataRepository.Find(id);
List<string> props = new List<string>();
props.Add("A");
props.Add("B");
props.Add("C");
if (data != null)
{
Type t = typeof(data).GetType();
foreach (String entry in props) {
PropertyInfo pi = t.GetProperty(entry);
if (pi.GetValue(data) == null) {
pi.SetValue(data, fieldName);
_dataRepository.InsertOrUpdate(data);
return entry;
}
}
}
}
You could just loop through all the character from 'A' to 'Z'. It gets difficult because you want to access an attribute of your 'data' object with the corresponding name, but that should (as far as I know) be possible through the C# reflection functionality.
While you get rid of the consecutive if-statements this still won't make your code nice :P
there is a fancy linq solution for your problem using reflection:
but as it was said before: your datastructure is not very well thought through
public String DataField(int id, string fieldName)
{
var data = new { Z = "test", B="asd"};
Type p = data.GetType();
var value = (from System.Reflection.PropertyInfo fi
in p.GetProperties().OrderBy((fi) => fi.Name)
where fi.Name.Length == 1 && fi.GetValue(data, null) != null
select fi.Name).FirstOrDefault();
return value;
}
ta taaaaaaaaa
like that you get the property but the update is not yet done.
var data = _dataRepository.Find(id);
If possible, you should use another DataType without those 26 properties. That new DataType should have 1 property and the Find method should return an instance of that new DataType; then, you could get rid of the 26 if in a more natural way.
To return "A", "B" ... "Z", you could use this:
return (char)65; //In this example this si an "A"
And work with some transformation from data.Value to a number between 65 and 90 (A to Z).
Since you always set the lowest alphabet field first and return, you can use an additional field in your class that tracks the first available field. For example, this can be an integer lowest_alphabet_unset and you'd update it whenever you set data.{X}:
Init:
lowest_alphabet_unset = 0;
In DataField:
lowest_alphabet_unset ++;
switch (lowest_alphabet_unset) {
case 1:
/* A is free */
/* do something */
return 'A';
[...]
case 7:
/* A through F taken */
data.G = fieldName;
_dataRepository.InsertOrUpdate(data);
return 'G';
[...]
}
N.B. -- do not use, if data is object rather that structure.
what comes to my mind is that, if A-Z are all same type, then you could theoretically access memory directly to check for non null values.
start = &data;
for (i = 0; i < 26; i++){
if ((typeof_elem) *(start + sizeof(elem)*i) != null){
*(start + sizeof(elem)*i) = fieldName;
return (char) (65 + i);
}
}
not tested but to give an idea ;)
Ok, I found this, which will allow me to do this:
public IList<Item> GetItems(string orderbyColumn)
{
return _repository.GetItems().OrderBy(orderByColumn).ToList();
}
Is this the best way to do "dynamic" ordering? I want to be able to pass the column name as a string (and the sort direction) to my Service, and have it order the correct way.
That's certainly a viable way of doing dynamic sorting. Ch00k provided another option in his answer to this question about "Strongly typed dynamic Linq sorting". I personally prefer Ch00k's method, as there's some compile-time checking involved and there's very little extra code involved.
If you've already decided that it must be a string, then your options are somewhat limited. The Dynamic LINQ library would indeed do the job, or if you want t know how it all works, look at this previous answer which builds an Expression from the string at runtime.
At the moment the code only accepts a single member and has separate methods for ascending / descending, but from this example it should be fairly simple to pass a more complex string and split it; essentially as:
IQueryable<T> query = ...
string[] portions = orderBy.Split(' '); // split on space, arbitrarily
if(portions.Length == 0) throw new ArgumentException();
IOrderedQueryable<T> orderedQuery = query.OrderBy(portions[0]);
for(int i = 1 ; i < portions.Length ; i++) { // note we already did the zeroth
orderedQuery = orderedQuery.ThenBy(portions[i]);
}
return orderedQuery;
If you're just after dynamic sorting without the full Dynamic-Linq stuff you can check out a post I wrote about this a while back: click
EDIT: I don't really blog anymore so here's the actual extension method:
public static IQueryable<TEntity> OrderBy<TEntity>(this IQueryable<TEntity> source, string sortExpression) where TEntity : class
{
if (string.IsNullOrEmpty(sortExpression))
return source; // nothing to sort on
var entityType = typeof(TEntity);
string ascSortMethodName = "OrderBy";
string descSortMethodName = "OrderByDescending";
string[] sortExpressionParts = sortExpression.Split(' ');
string sortProperty = sortExpressionParts[0];
string sortMethod = ascSortMethodName;
if (sortExpressionParts.Length > 1 && sortExpressionParts[1] == "DESC")
sortMethod = descSortMethodName;
var property = entityType.GetProperty(sortProperty);
var parameter = Expression.Parameter(entityType, "p");
var propertyAccess = Expression.MakeMemberAccess(parameter, property);
var orderByExp = Expression.Lambda(propertyAccess, parameter);
MethodCallExpression resultExp = Expression.Call(
typeof(Queryable),
sortMethod,
new Type[] { entityType, property.PropertyType },
source.Expression,
Expression.Quote(orderByExp));
return source.Provider.CreateQuery<TEntity>(resultExp);
}