Very often you have a list of items, and then a details-page showing just one item. In this example, we'll just use code to do this (so no visual query) - just so you understand the principle. This example splits the list/details templates into 3 files, which is easier to manage. File 1 choses what should happen, file 2 contains the list, and file 3 the details.
-
-
-
-
@inherits Custom.Hybrid.RazorTyped
@if (MyPage.Parameters.IsEmpty("id")) {
@Html.Partial("Coded-List.Strong.cshtml")
} else {
@Html.Partial("Coded-Details.Strong.cshtml", new { Id = MyPage.Parameters.Int("id") })
}
Source Code of Coded-List.Strong.cshtml
@inherits Custom.Hybrid.RazorTyped
@using AppCode.Data
<h3>List of Persons</h3>
<ul>
@foreach (var person in App.Data.GetAll<Persons>()) {
<li>
<a href='@Link.To(parameters: MyPage.Parameters.Set("id", person.Id))'>
@person.FirstName @person.LastName
</a>
</li>
}
</ul>
Source Code of Coded-Details.Strong.cshtml
@inherits Custom.Hybrid.RazorTyped
@using AppCode.Data
@{
// the ID is already given by the caller, so we just get that
var id = MyModel.Int("Id");
// find the person with this Id using LINQ
var person = App.Data.GetOne<Persons>(id);
}
@person.Picture("Mugshot", settings: "Square", width: 50, imgClass: "float-left", imgAttributes: new {
style = "border-radius: 50%"
})
<h3>Details of @person.FirstName @person.LastName</h3>
<a href='@Link.To(parameters: MyPage.Parameters.Remove("id"))'>back to list</a>
Source Code of Persons.cs
namespace AppCode.Data
{
public partial class Persons
{
/// <summary>
/// Custom property Presentation - as in these tutorials
/// the Person always uses a QuickRefContentPresentation content-type for the presentation
/// </summary>
public new QuickRefContentPresentation Presentation => _presentation ??= As<QuickRefContentPresentation>(base.Presentation);
private QuickRefContentPresentation _presentation;
}
}
Source Code of Persons.Generated.cs
// DO NOT MODIFY THIS FILE - IT IS AUTO-GENERATED
// See also: https://go.2sxc.org/copilot-data
// To extend it, create a "Persons.cs" with this contents:
/*
namespace AppCode.Data
{
public partial class Persons
{
// Add your own properties and methods here
}
}
*/
// Generator: CSharpDataModelsGenerator v17.08.00
// App/Edition: Tutorial-Razor/
// User: 2sic Web-Developer
// When: 2024-05-21 19:46:38Z
using System;
using System.Collections.Generic;
using System.Text.Json.Serialization;
using ToSic.Sxc.Adam;
using ToSic.Sxc.Data;
namespace AppCode.Data
{
// This is a generated class for Persons
// To extend/modify it, see instructions above.
/// <summary>
/// Persons data. <br/>
/// Generated 2024-05-21 19:46:38Z. Re-generate whenever you change the ContentType. <br/>
/// <br/>
/// Default properties such as `.Title` or `.Id` are provided in the base class. <br/>
/// Most properties have a simple access, such as `.Awards`. <br/>
/// For other properties or uses, use methods such as
/// .IsNotEmpty("FieldName"), .String("FieldName"), .Children(...), .Picture(...), .Html(...).
/// </summary>
public partial class Persons: AutoGenerated.ZAutoGenPersons
{ }
}
namespace AppCode.Data.AutoGenerated
{
/// <summary>
/// Auto-Generated base class for Default.Persons in separate namespace and special name to avoid accidental use.
/// </summary>
public abstract class ZAutoGenPersons: Custom.Data.CustomItem
{
/// <summary>
/// Awards as list of PersonAwards.
/// </summary>
/// <remarks>
/// Generated to return child-list child because field settings had Multi-Value=true. The type PersonAwards was specified in the field settings.
/// </remarks>
/// <returns>
/// An IEnumerable of specified type, but can be empty.
/// </returns>
public IEnumerable<PersonAwards> Awards => _awards ??= _item.Children<PersonAwards>("Awards");
private IEnumerable<PersonAwards> _awards;
/// <summary>
/// Biography as string. <br/>
/// For advanced manipulation like scrubHtml, use .String("Biography", scrubHtml: true) etc.
/// </summary>
public string Biography => _item.String("Biography", fallback: "");
/// <summary>
/// Birthday as DateTime.
/// </summary>
public DateTime Birthday => _item.DateTime("Birthday");
/// <summary>
/// FavoriteNumber as int. <br/>
/// To get other types use methods such as .Decimal("FavoriteNumber")
/// </summary>
public int FavoriteNumber => _item.Int("FavoriteNumber");
/// <summary>
/// FirstName as string. <br/>
/// For advanced manipulation like scrubHtml, use .String("FirstName", scrubHtml: true) etc.
/// </summary>
public string FirstName => _item.String("FirstName", fallback: "");
/// <summary>
/// Haters as single item of ITypedItem.
/// </summary>
/// <remarks>
/// Generated to only return 1 child because field settings had Multi-Value=false.
/// </remarks>
/// <returns>
/// A single item OR null if nothing found, so you can use ?? to provide alternate objects.
/// </returns>
public ITypedItem Haters => _haters ??= _item.Child("Haters");
private ITypedItem _haters;
/// <summary>
/// IsAlive as bool. <br/>
/// To get nullable use .Get("IsAlive") as bool?;
/// </summary>
public bool IsAlive => _item.Bool("IsAlive");
/// <summary>
/// LastName as string. <br/>
/// For advanced manipulation like scrubHtml, use .String("LastName", scrubHtml: true) etc.
/// </summary>
public string LastName => _item.String("LastName", fallback: "");
/// <summary>
/// Mugshot as link (url). <br/>
/// To get the underlying value like 'file:72' use String("Mugshot")
/// </summary>
public string Mugshot => _item.Url("Mugshot");
/// <summary>
/// Get the file object for Mugshot - or null if it's empty or not referencing a file.
/// </summary>
[JsonIgnore]
public IFile MugshotFile => _item.File("Mugshot");
/// <summary>
/// Get the folder object for Mugshot.
/// </summary>
[JsonIgnore]
public IFolder MugshotFolder => _item.Folder("Mugshot");
/// <summary>
/// Sex as string. <br/>
/// For advanced manipulation like scrubHtml, use .String("Sex", scrubHtml: true) etc.
/// </summary>
public string Sex => _item.String("Sex", fallback: "");
}
}