Add support for index in each tags
It was requested that the current index could be accessed in the each tag.
This commit is contained in:
parent
3795a77354
commit
d7a0ab3b38
10
README.md
10
README.md
|
@ -86,6 +86,16 @@ If you need to print out a block of text for each item in a collection, use the
|
|||
{{/each}}
|
||||
|
||||
Within the context of the **each** block, the scope changes to the current item. So, in the example above, `Name` would refer to a property in the `Customer` class.
|
||||
|
||||
Additionally, you can access the current index into the collection being enumerated using the **index** tag.
|
||||
|
||||
<ul>
|
||||
{{#each Items}}
|
||||
<li class="list-item{{#index}}" value="{{Value}}">{{Description}}</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
|
||||
This will build an HTML list, building a list of items with `Description` and `Value` properties. Additionally, the `index` tag is used to create a CSS class with increasing numbers.
|
||||
|
||||
## The 'with' tag
|
||||
Within a block of text, you may refer to a same top-level placeholder over and over. You can cut down the amount of text by using the **with** tag.
|
||||
|
|
|
@ -990,6 +990,20 @@ Last";
|
|||
Assert.AreEqual("Before123After", result, "The wrong text was generated.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// We can use the index tag to get the current iteration.
|
||||
/// </summary>
|
||||
[TestMethod]
|
||||
public void TestCompile_Each_Index_PrintsIndexOfItem()
|
||||
{
|
||||
FormatCompiler parser = new FormatCompiler();
|
||||
const string format = "<ul>{{#each this}}<li value=\"{{this}}\">Item {{#index}}</li>{{/each}}</ul>";
|
||||
Generator generator = parser.Compile(format);
|
||||
string result = generator.Render(new int[] { 1, 2, 3 });
|
||||
const string expected = @"<ul><li value=""1"">Item 0</li><li value=""2"">Item 1</li><li value=""3"">Item 2</li></ul>";
|
||||
Assert.AreEqual(expected, result, "The wrong text was generated.");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region With
|
||||
|
@ -1038,7 +1052,7 @@ Last";
|
|||
return new TagParameter[] { new TagParameter("param") { IsRequired = false, DefaultValue = 123 } };
|
||||
}
|
||||
|
||||
public override void GetText(TextWriter writer, Dictionary<string, object> arguments)
|
||||
public override void GetText(TextWriter writer, Dictionary<string, object> arguments, object contextData)
|
||||
{
|
||||
writer.Write(arguments["param"]);
|
||||
}
|
||||
|
|
|
@ -31,5 +31,5 @@ using System.Runtime.InteropServices;
|
|||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
[assembly: AssemblyVersion("0.1.1.0")]
|
||||
[assembly: AssemblyFileVersion("0.1.1.0")]
|
||||
[assembly: AssemblyVersion("0.1.2.0")]
|
||||
[assembly: AssemblyFileVersion("0.1.2.0")]
|
||||
|
|
|
@ -72,7 +72,7 @@ namespace Mustache
|
|||
}
|
||||
}
|
||||
|
||||
void IGenerator.GetText(KeyScope scope, TextWriter writer)
|
||||
void IGenerator.GetText(KeyScope scope, TextWriter writer, object contextData)
|
||||
{
|
||||
Dictionary<string, object> arguments = _arguments.GetArguments(scope);
|
||||
IEnumerable<NestedContext> contexts = _definition.GetChildContext(writer, scope, arguments);
|
||||
|
@ -93,7 +93,7 @@ namespace Mustache
|
|||
{
|
||||
foreach (IGenerator generator in generators)
|
||||
{
|
||||
generator.GetText(context.KeyScope ?? scope, context.Writer ?? writer);
|
||||
generator.GetText(context.KeyScope ?? scope, context.Writer ?? writer, context.Data);
|
||||
if (context.WriterNeedsConsidated)
|
||||
{
|
||||
writer.Write(_definition.ConsolidateWriter(context.Writer ?? writer, arguments));
|
||||
|
|
|
@ -54,9 +54,11 @@ namespace Mustache
|
|||
{
|
||||
yield break;
|
||||
}
|
||||
int index = 0;
|
||||
foreach (object item in enumerable)
|
||||
{
|
||||
yield return new NestedContext() { KeyScope = scope.CreateChildScope(item), Writer = writer };
|
||||
yield return new NestedContext() { KeyScope = scope.CreateChildScope(item), Writer = writer, Data = index };
|
||||
++index;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -66,7 +68,7 @@ namespace Mustache
|
|||
/// <returns>The name of the tags that are in scope.</returns>
|
||||
protected override IEnumerable<string> GetChildTags()
|
||||
{
|
||||
return new string[] { };
|
||||
return new string[] { "index" };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -33,6 +33,8 @@ namespace Mustache
|
|||
_tagLookup.Add(elseDefinition.Name, elseDefinition);
|
||||
EachTagDefinition eachDefinition = new EachTagDefinition();
|
||||
_tagLookup.Add(eachDefinition.Name, eachDefinition);
|
||||
IndexTagDefinition indexDefinition = new IndexTagDefinition();
|
||||
_tagLookup.Add(indexDefinition.Name, indexDefinition);
|
||||
WithTagDefinition withDefinition = new WithTagDefinition();
|
||||
_tagLookup.Add(withDefinition.Name, withDefinition);
|
||||
}
|
||||
|
|
|
@ -80,7 +80,7 @@ namespace Mustache
|
|||
scope.KeyNotFound += handler;
|
||||
}
|
||||
StringWriter writer = new StringWriter(provider);
|
||||
_generator.GetText(scope, writer);
|
||||
_generator.GetText(scope, writer, null);
|
||||
return writer.ToString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,8 @@ namespace Mustache
|
|||
/// </summary>
|
||||
/// <param name="scope">The current lexical scope of the keys.</param>
|
||||
/// <param name="writer">The text writer to send all text to.</param>
|
||||
/// <param name="contextData">The data associated to the context.</param>
|
||||
/// <returns>The generated text.</returns>
|
||||
void GetText(KeyScope scope, TextWriter writer);
|
||||
void GetText(KeyScope scope, TextWriter writer, object contextData);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Mustache
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines a tag that outputs the current index within an each loop.
|
||||
/// </summary>
|
||||
internal sealed class IndexTagDefinition : InlineTagDefinition
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of an IndexTagDefinition.
|
||||
/// </summary>
|
||||
public IndexTagDefinition()
|
||||
: base("index")
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether the tag only exists within the scope of its parent.
|
||||
/// </summary>
|
||||
protected override bool GetIsContextSensitive()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the text to output.
|
||||
/// </summary>
|
||||
/// <param name="writer">The writer to write the output to.</param>
|
||||
/// <param name="arguments">The arguments passed to the tag.</param>
|
||||
/// <param name="contextData">Extra data passed along with the context.</param>
|
||||
public override void GetText(TextWriter writer, Dictionary<string, object> arguments, object contextData)
|
||||
{
|
||||
int index = (int)contextData;
|
||||
writer.Write(index);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -23,10 +23,10 @@ namespace Mustache
|
|||
_arguments = arguments;
|
||||
}
|
||||
|
||||
void IGenerator.GetText(KeyScope scope, TextWriter writer)
|
||||
void IGenerator.GetText(KeyScope scope, TextWriter writer, object contextData)
|
||||
{
|
||||
Dictionary<string, object> arguments = _arguments.GetArguments(scope);
|
||||
_definition.GetText(writer, arguments);
|
||||
_definition.GetText(writer, arguments, contextData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ namespace Mustache
|
|||
return formatBuilder.ToString();
|
||||
}
|
||||
|
||||
void IGenerator.GetText(KeyScope scope, TextWriter writer)
|
||||
void IGenerator.GetText(KeyScope scope, TextWriter writer, object contextData)
|
||||
{
|
||||
object value = scope.Find(_key);
|
||||
writer.Write(_format, value);
|
||||
|
|
|
@ -45,5 +45,10 @@ namespace Mustache
|
|||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets data associated with the context.
|
||||
/// </summary>
|
||||
public object Data { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,6 +34,6 @@ using System.Runtime.CompilerServices;
|
|||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("0.1.1.0")]
|
||||
[assembly: AssemblyFileVersion("0.1.1.0")]
|
||||
[assembly: AssemblyVersion("0.1.2.0")]
|
||||
[assembly: AssemblyFileVersion("0.1.2.0")]
|
||||
[assembly: InternalsVisibleTo("mustache-sharp.test")]
|
|
@ -46,7 +46,7 @@ namespace Mustache
|
|||
}
|
||||
}
|
||||
|
||||
void IGenerator.GetText(KeyScope scope, TextWriter writer)
|
||||
void IGenerator.GetText(KeyScope scope, TextWriter writer, object contextData)
|
||||
{
|
||||
writer.Write(Value);
|
||||
}
|
||||
|
|
|
@ -152,7 +152,8 @@ namespace Mustache
|
|||
/// </summary>
|
||||
/// <param name="writer">The text writer to write to.</param>
|
||||
/// <param name="arguments">The arguments passed to the tag.</param>
|
||||
public virtual void GetText(TextWriter writer, Dictionary<string, object> arguments)
|
||||
/// <param name="contextData">The data associated to the context.</param>
|
||||
public virtual void GetText(TextWriter writer, Dictionary<string, object> arguments, object contextData)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
<Compile Include="ContentTagDefinition.cs" />
|
||||
<Compile Include="Context.cs" />
|
||||
<Compile Include="ContextParameter.cs" />
|
||||
<Compile Include="IndexTagDefinition.cs" />
|
||||
<Compile Include="KeyFoundEventArgs.cs" />
|
||||
<Compile Include="InlineTagDefinition.cs" />
|
||||
<Compile Include="EachTagDefinition.cs" />
|
||||
|
|
Loading…
Reference in New Issue