Fork me on GitHub
DNN Apps - Demo-Zone
Discover DNN-Apps - simple and elegant, easy to customize

1. Show all Authors

This just gets all authors from the DB and shows them. It also has a special "new" button which will pre-fill the new entity

  • Daniel Mettler
  • Benjamin Gemperle
  • Raphael Müller

2. Various Sorting Mechanisms

Show all authors sorted in various ways

  • Sorted FullName A-Z
    1. Benjamin Gemperle
    2. Daniel Mettler
    3. Raphael Müller
  • Now with reversed sort
    1. Raphael Müller
    2. Daniel Mettler
    3. Benjamin Gemperle
  • And now with multi-field sort (first url ascending, then name descending)
    1. Raphael Müller on http://2sexycontent.org/
    2. Daniel Mettler on http://www.2sic.com/
    3. Benjamin Gemperle on http://www.2sic.com/
  • Now sorted by EntityId (also works w/EntityTitle)
    1. Daniel Mettler (2351)
    2. Benjamin Gemperle (2352)
    3. Raphael Müller (2353)
  • Sorting a List using LINQ (applying a different sort than before)
    1. Daniel Mettler
    2. Benjamin Gemperle
    3. Raphael Müller

3. Get Data and Filter by ID, Type or both

The following table shows the results of the code. The first examples just get data based on simple criteria (like: is author, has the ID 2351, etc.). The last examples chain the filters, so they look for an ID within the previous filter Authors.

Statistics

Pipeline Filter parameters Result Count
Cache / Root Source 67
Content-Type Filter Author 3
ID Filter 2351 1
Multiple-IDs Filter 2351,2353 2
Chain Type and ID Filter (should work) Author & 2351 1
Chain Type and ID-Filter (should not work) Categories & 2351 0

4. Data filtered by an entity-Attribute

Show only authors with the Website = "http://www.2sic.com/"

  • Daniel Mettler
  • Benjamin Gemperle

5. Filter by QueryString parameter in URL

Click on an author to place it's ID in the URL and then see it's details. The filter uses the token [QueryString:Author] which automatically picks up the correct value.

No author selected

6. Access related / referenced information

Get courses, show them with related (child) categories

  • Learn DNN by Daniel Mettler
    Categories: 2SexyContent , HTML 5 , CSS 3 ,
  • 2SexyContent EAV and Responsive Design by Benjamin Gemperle
    Categories: CSS 3 , 2SexyContent , HTML 5 , Razor ,
  • 2SexyContent Lists-Training by Daniel Mettler
    Categories: knockoutJS , CSS 3 , Razor ,
  • 2SexyContent Relationships Training by Raphael Müller
    Categories: Razor ,
  • Learn cooking (uncategorize) by unknown
    Categories:

Get categories with relating (parent) courses

  • 2SexyContent
    1. Learn DNN
    2. 2SexyContent EAV and Responsive Design
  • Razor
    1. 2SexyContent EAV and Responsive Design
    2. 2SexyContent Lists-Training
    3. 2SexyContent Relationships Training
  • HTML 5
    1. Learn DNN
    2. 2SexyContent EAV and Responsive Design
  • CSS 3
    1. Learn DNN
    2. 2SexyContent EAV and Responsive Design
    3. 2SexyContent Lists-Training
  • jQuery
  • knockoutJS
    1. 2SexyContent Lists-Training

Look inside

Content Item

These are the values a content-editor can manage.
Name Type Value
Title System.String 1. Show all Authors 1. Show all Authors


Presentation Item

These are additional, optional presentation instructions a content-editor can manage. If none are entered, a default set (predefined by the designer) will be used.

No Presentation parameters specified, using default presentation for this item.


Template file

<div class="BasicContentWithPreview">
	<h1 class="sc-element">@Content.Title @Content.Toolbar</h1>
	<p>
		This just gets all authors from the DB and shows them. It also has a special "new" button which will pre-fill the new entity
	</p>
    <ul>
        
        @if (DotNetNuke.Common.Globals.IsEditMode())
        {
            // todo: fix with new syntax for toolbars in 6.2
            <li>
                Create new
                <ul class='sc-menu' data-toolbar='[{ "attributeSetName": "Author", "action": "new", "prefill": {"Website":"http://www.2sic.com/"} }]'></ul>
            </li>
        }

        @foreach (var author in AsDynamic(App.Data["Author"]))
        {
            <li>@author.FullName</li>
        }
    </ul>
</div>

Look inside

Content Item

These are the values a content-editor can manage.
Name Type Value
Title System.String 2. Various Sorting Mechanisms 2. Various Sorting Mechanisms


Presentation Item

These are additional, optional presentation instructions a content-editor can manage. If none are entered, a default set (predefined by the designer) will be used.

No Presentation parameters specified, using default presentation for this item.


Template file

@using ToSic.Eav.DataSources
@functions
{
    // Note: this code requires 2sxc version 6.2 to work

    // Prepare the data - get all categories through the pipeline
    public override void CustomizeData()
    {
        // Sort by FullName
        var sortedAuthors = CreateSource<ValueSort>(App.Data["Author"]);
        sortedAuthors.Attributes = "FullName";
        Data.Attach("SortByFullName", sortedAuthors);

        // Sort by Fullname descending
        var sortedAuthorsDesc = CreateSource<ValueSort>(App.Data["Author"]);
        sortedAuthorsDesc.Attributes = "FullName";
        sortedAuthorsDesc.Directions = "desc";
        Data.Attach("SortByFullNameDesc", sortedAuthorsDesc);

        // Sort by 2 fields
        var sortedAuthorsMult = CreateSource<ValueSort>(App.Data["Author"]);
        sortedAuthorsMult.Attributes = "Website,FullName";
        sortedAuthorsMult.Directions = "asc, desc";
        Data.Attach("SortByMultiple", sortedAuthorsMult);

        // sort by internal EntityId
        var sortedAuthorsById = CreateSource<ValueSort>(App.Data["Author"]);
        sortedAuthorsById.Attributes = "EntityId";
        Data.Attach("SortById", sortedAuthorsById);
    }

}
<div class="BasicContentWithPreview sc-element">
	@Content.Toolbar
	<h1><span>@Content.Title</span></h1>

	<p>Show all authors sorted in various ways</p>
	<ul>
		<li>Sorted FullName A-Z
			<ol>
				@foreach (var a in AsDynamic(Data["SortByFullName"]))
				{
					<li>@a.FullName</li>;
				}
			</ol>
		</li>
		<li>Now with reversed sort
			<ol>
				@foreach (var a in AsDynamic(Data["SortByFullNameDesc"]))
				{
					<li>@a.FullName</li>;
				}
			</ol>			
		</li>
		<li>And now with multi-field sort (first url ascending, then name descending)
			<ol>
				@foreach (var a in AsDynamic(Data["SortByMultiple"]))
				{
					<li>@a.FullName on <a href="@a.Website">@a.Website</a></li>;
				}
			</ol>
		</li>
		<li>
			Now sorted by EntityId (also works w/EntityTitle)
			<ol>
				@foreach (var a in AsDynamic(Data["SortById"]))
				{
					<li>@a.FullName (@a.EntityId)</li>;
				}
			</ol>
		</li>	
		<li>
			Sorting a List using LINQ (applying a different sort than before)
			<ol>
				@foreach (var a in AsDynamic(Data["SortByFullName"]).OrderBy(x => x.EntityId))
				{
					<li>@a.FullName</li>;
				}
			</ol>
		</li>
	</ul>
</div>

Look inside

Content Item

These are the values a content-editor can manage.
Name Type Value
Title System.String 3. Get Data and Filter by ID, Type or both 3. Get Data and Filter by ID, Type or both


Presentation Item

These are additional, optional presentation instructions a content-editor can manage. If none are entered, a default set (predefined by the designer) will be used.

No Presentation parameters specified, using default presentation for this item.


Template file

@using ToSic.Eav.DataSources

<div class="BasicContentWithPreview sc-element">
	@Content.Toolbar
	<h1 class="Title Purple"><span>@Content.Title</span></h1>

	@{
		// get the DataSource of the current app (the in-memory cache) - it's like accessing the entire DB directly
		var entireCache = CreateSource();

	    var allAuthors = App.Data["Author"];
        Data.Attach("Authors", allAuthors);
	    var allCategories = App.Data["Category"];
        Data.Attach("Categories", allCategories);
		
        // Find some IDs to use as filters in the next lines of code (first and last)
		var firstAuthorId = allAuthors.List.FirstOrDefault().Value.EntityId; 
		var lastAuthorId = allAuthors.List.LastOrDefault().Value.EntityId; 

		// A source which can filter by one or more IDs
		var filterById = CreateSource<EntityIdFilter>();
        filterById.EntityIds = firstAuthorId.ToString();
        Data.Attach("FilterId", filterById);
        
        var filterByManyIds = CreateSource<EntityIdFilter>();
		filterByManyIds.EntityIds = firstAuthorId + "," + lastAuthorId; 
        Data.Attach("FilterManyIds", filterByManyIds);

		// Now the magic! chain pipelines :)
		var authorWithId = CreateSource<EntityIdFilter>(allAuthors); // create filter, which attaches to the Out of the previous data source
		authorWithId.EntityIds = firstAuthorId.ToString(); // should work, it's an author
        Data.Attach("TypeAndIdFilterWorks", authorWithId);

		// Another chain - but this one will deliver an empty list
		var authorWithSimpleContentId = CreateSource<EntityIdFilter>(allCategories);
		authorWithSimpleContentId.EntityIds = firstAuthorId.ToString(); // should NOT work, it's a SimpleContent Entity, not! an author
        Data.Attach("TypeAndIdFilterFails", authorWithSimpleContentId);
        
        // An important note
        // Such data-preparation code should usually be inside a PrepareData section, not inline
        // I just placed it inline, because the output-code below sometimes shows stream-configuration (like the ID it filtered)
        // But usally you want to hide such internal pipeline configurations in the PrepareData and you usually don't access the stream-config again
        // So don't do it like this at home :)
	}

	<div>
		<p>
			The following table shows the results of the code. The first examples just get data based on simple criteria (like: is author, has the ID @firstAuthorId, etc.). The last examples <em>chain</em> the filters, so they look for an ID <em>within</em> the previous filter Authors.
		</p>
		<h2>Statistics</h2>
		<table style="padding: 2px" width="100%">
			<tr>
				<th style="text-align: left">Pipeline</th>
				<th style="text-align: left">Filter parameters</th>
				<th style="text-align: left">Result Count</th>
			</tr>
			<tr>
				<td style="width: 400px">Cache / Root Source</td>
				<td></td>
				<td>@entireCache.Out["Default"].List.Count</td>
			</tr>
			<tr>
				<td>Content-Type Filter</td>
				<td><em>Author</em></td>
				<td>@Data["Authors"].List.Count</td>
			</tr>
			<tr>
				<td>ID Filter</td>
				<td><em>@filterById.EntityIds</em></td>
				<td>@Data["FilterId"].List.Count</td>
			</tr>
			<tr>
				<td>Multiple-IDs Filter</td>
				<td><em>@filterByManyIds.EntityIds</em></td>
				<td>@Data["FilterManyIds"].List.Count</td>
			</tr>
			<tr>
				<td>Chain Type and ID Filter (should work)</td>
				<td><em>Author</em> &amp; <em>@authorWithId.EntityIds</em></td>
				<td>@Data["TypeAndIdFilterWorks"].List.Count</td>
			</tr>
			<tr>
				<td>Chain Type and ID-Filter (should not work)</td>
				<td><em>Categories</em> &amp; <em>@authorWithSimpleContentId.EntityIds</em> </td>
				<td>@Data["TypeAndIdFilterFails"].List.Count</td>
			</tr>
		</table>
	</div>
</div>

Look inside

Content Item

These are the values a content-editor can manage.
Name Type Value
Title System.String 4. Data filtered by an entity-Attribute 4. Data filtered by an entity-Attribute


Presentation Item

These are additional, optional presentation instructions a content-editor can manage. If none are entered, a default set (predefined by the designer) will be used.

No Presentation parameters specified, using default presentation for this item.


Template file

@using ToSic.Eav.DataSources
@functions
{
    private string attrToFilter = "Website";
    private string filterValue = "http://www.2sic.com/";

    // Note: this code requires 2sxc version 6.2 to work

    // Prepare the data - get all categories through the pipeline
    public override void CustomizeData()
    {
        // Now the magic! chain pipelines - combine an App.Data["Author"] which is a pipeline with the next one
        var filteredAuthors = CreateSource<ValueFilter>(App.Data["Author"]); // create filter, which attaches to the Out of the previous data source
        filteredAuthors.Attribute = attrToFilter;
        filteredAuthors.Value = filterValue;
        Data.Attach("Filtered", filteredAuthors);
    }

}
<div class="sc-element">
	@Content.Toolbar
	<h1 class="Title Purple"><span>@Content.Title</span></h1>

	<p>Show only authors with the <em>@attrToFilter</em> = "@filterValue"</p>

	<ul>
		@foreach (var a in AsDynamic(Data["Filtered"]))
		{
			<li>@a.FullName</li>;
		}
	</ul>
</div>

Look inside

Content Item

These are the values a content-editor can manage.
Name Type Value
Title System.String 5. Filter by QueryString parameter in URL 5. Filter by QueryString parameter in URL


Presentation Item

These are additional, optional presentation instructions a content-editor can manage. If none are entered, a default set (predefined by the designer) will be used.

No Presentation parameters specified, using default presentation for this item.


Template file

@using ToSic.Eav.DataSources
@functions
{
    // Note: this code requires 2sxc version 6.2 to work

    // Prepare the data - get all categories through the pipeline
    public override void CustomizeData()
    {
        // Now filter for the URL-Param if it exists...
        // the following syntax uses the property-providers
        var authorFilter = CreateSource<EntityIdFilter>();	// create filter, which attaches to the Out of the previous data source
        authorFilter.EntityIds = "[QueryString:Author]";		// this will get resolved automatically

        Data.Attach("Details", authorFilter);
    }
}
<div class="BasicContentWithPreview sc-element">
	@Content.Toolbar
	<h1 class="Title Purple"><span>@Content.Title</span></h1>

	<p>Click on an author to place it's ID in the URL and then see it's details. The filter uses the token [QueryString:Author] which automatically picks up the correct value.</p>

	<ul>
		@foreach (var author in AsDynamic(App.Data["Author"]))
		{
			<li><a href="?author=@author.EntityId">@author.FullName</a>
				@if (DotNetNuke.Common.Globals.IsEditMode())
				{
					<ul class='sc-menu' data-toolbar='[{ "entityId": @author.EntityId, "action": "edit" }]' style="display: inline; position: static"></ul>
				}
		</li>;
		}
		<li><a href="?">Unselect</a></li>
	</ul>
	
	@if (Data["Details"].List.Count > 0)
	{
        var authorDetails = AsDynamic(Data["Details"]).First();
	    <p>
	        Filter was resolved to @((Data["Details"].Source as EntityIdFilter).EntityIds) 
	        so it found @authorDetails.FullName
	    </p>
		<img src="@authorDetails.Photo?w=200"/>
	}
	else
	{
		<p>No author selected</p>
	}
</div>

Look inside

Content Item

These are the values a content-editor can manage.
Name Type Value
Title System.String 6. Access related / referenced information 6. Access related / referenced information


Presentation Item

These are additional, optional presentation instructions a content-editor can manage. If none are entered, a default set (predefined by the designer) will be used.

No Presentation parameters specified, using default presentation for this item.


Template file

<div class="BasicContentWithPreview sc-element">
	@Content.Toolbar
	<h1><span>@Content.Title</span></h1>
	<h2>Get courses, show them with related (child) categories</h2>

    <ul>
		@foreach (var course in AsDynamic(App.Data["Course"]))
		{
			<li>
				<strong>@course.Title @course.Toolbar</strong> 
				@if (course.Author != null)
				{
					<text> by  @(course.Author.Count > 0 ? course.Author[0].FullName : "unknown")</text>
				}
				@if (course.Categories != null)
				{<br/>
					<em>Categories: 
						@foreach (var cat in course.Categories)
						{
							@cat.Name
							<text>,</text>
						}
					</em>
				}
				else
				{
					<br/><em>no category</em>
				}
			</li>
		}
	</ul>
	

	<h2>
		Get categories with relating (parent) courses
	</h2>
	@{
		// A source which can filter by Content-Type (EntityType)
	    var allCategories = App.Data["Category"];
	}
	<ul>
		@foreach (var cat in allCategories.List)
		{
			// Here's the short version for the list of parent courses
			var courses = cat.Value.Relationships.AllParents	// all parents, no matter what entity-type
				.Where(c => c.Type.Name == "Course");			// now only the courses

			var category = AsDynamic(cat);
			<li>
				<strong>@category.Name</strong>
				<ol>
					@foreach (var course in AsDynamic(courses))
					{
						<li>@course.Title</li>
					}
				</ol>
			</li>
		}
	</ul></div>
2serve . 2invent . 2create is 2be.