Play Framework Template list only top 5 - list

In Play framework how do I list only a certain number of object from database instead of all.
Suppose that I have this Post class that has a #OneToMany relation with Comments just like this
public class Post extends Model {
#ManyToOne
public User user;
public String name;
public String description;
public String image;
public Date created_date;
#OneToMany(mappedBy="post", cascade=CascadeType.ALL)
public List<Comment> comments;
....
}
How do I only list top 5 comments for each post at the template? I've done this, but it shows all comments
#{list items:post.comments, as:'comment'}
<p>${comment.comment}</p>
#{/list}
Thanks

You can just use standard Java to get the sub list
#{list items:post.comments.subList(0,5), as:'comment'}
<p>${comment.comment}</p>
#{/list}
The above will return an array index out of bounds if there are less than 5 comments though, so you can either put some more logic in the template (as below), or you could create a getter method in your Post model that gets the top5 comments, and just call this instead (which is probably the cleaner and preferred option.
The extra logic in the template would look like
#{list items:post.comments.subList(0, Math.min(5, post.comments.size())), as:'comment'}
<p>${comment.comment}</p>
#{/list}
If you agree that this is too much logic in your view, and want to encapsulate it in your Model, you could do the following.
The extra logic in your view may look like
public List<Comment> getTop5() {
return comments.subList(0, Math.min(5, comments.size());
}
And then your controller would be
#{list items:post.top5, as:'comment'}
<p>${comment.comment}</p>
#{/list}

Related

List or IEnumerable for .NET Core Model?

Let's say I have a view with a model defined as #model IEnumerable<ViewModel> On the controller, this data is provided by entity framework and is thus an IQueryable.
I want to iterate through the data like this:
#if (Model != null && Model.Count() > 0)
{
#foreach (var item in Model)
{
<tr>
<td>
#item.firstProp
</td>
<td>
#item.secondProp
</td>
</tr>
}
}
else
{
<tr>
<td>
No data to display.
</td>
</tr>
}
I only want to iterate if there is at least one item, otherwise I want to show a different message. Because I'm using an IEnumerable, checking the count requires a trip to the database, and a second trip to iterate the foreach loop. I could always use a List instead, but I almost always see models defined using IEnumerable. Is using List a good solution, or should IEnumerable always be used when defining models?
First the difference between List<T>, IEnumerable<T> and IQueryable<T>.
The content of List<T> will always be loaded into memory, because it uses an array in the background.
The content of IEnumerable<T> will only load the requested item into the memory. Compiler sets up a state machine during compiling a method with IEnumerable<T> that has a yield return T. So only one item at a time will be loaded into memory in this case.
IQueryable<T> is "special" version of IEnumerable<T>. Specifically designed to query data sources, and implemented by data providers. Like EF, NHibernate. So when you tell EF to fetch the data with .ToListAsync<T>() EF will only then go the databas and execute the generated query.
See the docs for more info about IQueryable<T>.
Personly I use ICollection<T> with HasSet implementation to improve sorting and querying in memory.
For example:
public class MyModel
{
public ICollection<SomeSubModel> SomeSubModels { get; private set; } = new HasSet<SomeSubModel>();
}
(Additional if you have a large list it is good practice to use pagination.)
Here is a nice article, you can check it, it explores the usages of IEnumerable, IList, and IQueryable, differences between them:
IEnumerable is useful when we want to iterate the collection of objects which deals with in-process memory.
IQueryable is useful when we want to iterate a collection of objects which deals with ad-hoc queries against the data source or remote database, like SQL Server.
IList is useful when we want to perform any operation like Add,Remove or Get item at specific index position in the collection.
Personally, I prefer to use the ICollection in the data model, and use it to read/update the related entities from the database. Besides, we all should know that IQueryable is inherited from IEnumerable, so whatever IEnumerable can do, we can achieve with IQueryable as well.
public class Course
{
public int CourseID { get; set; }
public ICollection<Enrollment> Enrollments { get; set; }
public ICollection<CourseAssignment> CourseAssignments { get; set; }
}
Then, in the controller, use the ToList or ToListAsync method to return the data to view.
public async Task<IActionResult> Index()
{
var courses = _context.Courses
.Include(c => c.Department)
.AsNoTracking();
return View(await courses.ToListAsync());
}
Finally, use IEnumerable to display the model.
#model IEnumerable<ContosoUniversity.Models.Course>
#foreach (var item in Model)
{
}

How to make KendoNumericTextBox wrapper to render Required model attribute?

I'm in an MVC6 project and trying to add a simple Kendo NumericTextBox widget using provided HtmlHelpers.
My model looks like this:
public class DataViewModel
{
[Required]
public double MyNumber {Get; Set;}
....
}
My view:
...
#(Html.Kendo.NumericTextBoxFor(m=>m.MyNumber)
...
)
But Input tag generated from this code doesn't include the "required" attribute so client validator doesn't check for completness.
Any ideas on how to get the required validation working in client?
I experienced the same problem and asked Telerik people about this. Their answer is that MVC6 is still in pre-release and changing a lot, so they will wait to production release to check for this issues.
Meanwhile, a workaround would be this:
#(Html.Kendo.NumericTextBoxFor(m=>m.MyNumber)
.HtmlAttributes(new {required="required"})
...
)

Map two templates for different sites

We are developing a multisite sitecore solution where each sites can have have their own News as well as able to display the combined news from other Sites.
Problem:
Each site have their unique News requirements where 90% of the template fields matches but rest 10% are different.
For example, Site-A has news template with Authors drop down list where Author List are authored on Configuration Node. Where as Site-B has news template where Author is a FREE TEXT Field.
Therefore, when Glass Mapper automatically tries to Map Authors field it fails for Free Text one.
Solution:
This can be resolved either by creating a Author as drop down on all Sites but Product owners don't want this.
The other solution is manual mapping of news fields from both sources or use AUTOMAP etc.
Desired Solution:
Glassmapper automatically resolves and populates the Author Text Field or Drop Down Field on the fly.
Is above possible?
Thank you.
I would solve this by "fluent configuration", http://glass.lu/Mapper/Sc/Tutorials/Tutorial8.aspx.
Combined with the new Delegate feature added to the Glass Mapper recently.
The Delegate feature was originally introduced and described here: http://cardinalcore.co.uk/2014/07/02/controlling-glass-fields-from-your-own-code/
Nuget package for the Delegate feature: https://www.nuget.org/packages/Cardinal.Glass.Extensions.Mapping/
You can use Infer types as follows:
public interface IBaseNews
{
string Author {get; set;}
//List all other shared fields below
}
[SitecoreType(TemplateId="....", AutoMap = true)]
public class NewsSiteA : IBaseNews
{
[SitecoreField]
public string Author {get; set;}
//List all fields which are unique for SiteA
}
[SitecoreType(TemplateId="....", AutoMap = true)]
public class NewsSiteB : IBaseNews
{
[SitecoreField]
public string Author {get; set;}
//List all fields which are unique for SiteB
}
Now, Your code should be:
IBaseNews newsClass = NewsItem.GlassCast<IBaseNews>(true,true);
//You can use Author property now
Firstly, I would recommend updating to the latest version of Glass for many other reasons including the delegate feature.
From the infer type example in the comment - you shouldn't use GlassCast, use CreateType(Item item) from the sitecore service / context. If you adopt the version with Delegate in, there is now an official Cast(Item item) on the sitecore service instead.
Also the example there uses a would not solve the difference in type. Delegate would make this very easy. Remember with delegate that there is no lazy loading, this shouldn't matter in this case.
public interface INews
{
// All my other fields
string Author { get; set; }
}
The fluent configuration would be something like (to be done in GlassScCustom)
SitecoreType<INews> = new SitecoreType<INews>();
sitecoreType.Delegate(y => y.Author).GetValue(GetAuthor);
fluentConfig.Add(sitecoreType);
private string GetAuthor(SitecoreDataMappingContext arg)
{
Item item = arg.Item;
if(item.TemplateID == <templateid>)
{
// return the value from the drop link
}
return item["Authors"];
}

grails populating g:select from query

Trying to become a grails convert I have begun converting an existing application to Grails and Groovy. It works very well but I get stuck on the conversion of select tags.
I have a domain class:
package todo
class Person {
String ssn
String firstname
String familyname
String role
String emailname
String emailserver
...
When creating a new "todo" task an owner may be assigned from those persons in the system who are developers and I get this working (a fairly direct translation from PHP):
<select id="owner" name="owner">
<option>Noboby ...</option>
<g:each in="${Person.list()}">
<g:if test="${it?.role=='developer'}">
<option value="${it?.id}">${it?.firstname} ${it?.familyname}</option>
</g:if>
</g:each>
</select>
But every attempt to make it more "Grails-ish" fails. How can it be moulded into Grails v2.2.1 code? I spent hours reading, trying, failing.
If you woulkd like to make it more Grails style, you should perform all your logic within controllers \ services not in the view.
Assuming you have a view createTodo in the folder person and the PersonController, then modify your createTodo action like this:
class PersonController {
def createTodo() {
def developers = Person.findAllWhere(role: 'developer')
[developers: developers, ... /* your other values */]
}
}
So you don't need to handle with database operations in your view.
Next step is to use the g:select tag like this:
<g:select name="owner" from="${developers}" optionValue="${{'${it.firstName} ${it.familyName}'}}" noSelection="['null':'Nobody ...']" optionKey="id" value="${personInstance?.id}" />
Try this code:
<g:select optionKey="id" from="${Person.findAllByRole('developer')}" optionValue="${{it.fullName}}" value="${yourDomainInstance?.person?.id}" noSelection="['null':'Nobody']"></g:select>
And in your class:
class Person {
....
String getFullName(){
it?.firstname+' '+ it?.familyname
}
static transients = ['fullName']
....
}
See g:select tag for more details
Finally, I got it working as I want to and it works (almost) according to the #"Mr. Cat" solution. One little detail, though, 'it' does not exist in the class so the getFullName method had to become:
String getFullName(){
this?.firstname+' '+ this?.familyname
}
Up and working, thank you for all help.

What is ScaffoldColumn and RegularExpression attributes

I am trying to learn MVC4 and i've come to this chapter called validation.
I came to know about DataAnnotations and they have pretty neat attributes to do some server side validation. In book they have only explained about [Required] and [Datatype] attribute. However in asp.net website i saw something called ScaffoldColumn and RegularExpression.
Can someone explain what they are, even though I know little what RegularExpression does.
Also are there any other important validation attributes I should know?
Scaffold Column dictates if when adding a view based on that datamodel it should/not scaffold the column. So forexample your model's id field is a good candidate for you to specify ScaffoldColumn(false), and other foreign key fields etc.
I you specify a regular expression, then if you scaffold a new view for that model,edit customer for example, a regex or regular expression on field will enforce that entered data must match that format.
You can read about ScaffoldColumnAttribute Class here
[MetadataType(typeof(ProductMetadata))]
public partial class Product
{
}
public class ProductMetadata
{
[ScaffoldColumn(true)]
public object ProductID;
[ScaffoldColumn(false)]
public object ThumbnailPhotoFileName;
}
And about RegularExpressionAttribute Class you can read here.
using System;
using System.Web.DynamicData;
using System.ComponentModel.DataAnnotations;
[MetadataType(typeof(CustomerMetaData))]
public partial class Customer
{
}
public class CustomerMetaData
{
// Allow up to 40 uppercase and lowercase
// characters. Use custom error.
[RegularExpression(#"^[a-zA-Z''-'\s]{1,40}$",
ErrorMessage = "Characters are not allowed.")]
public object FirstName;
// Allow up to 40 uppercase and lowercase
// characters. Use standard error.
[RegularExpression(#"^[a-zA-Z''-'\s]{1,40}$")]
public object LastName;
}