Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 197 lines (139 sloc) 6.851 kb
d67b4cc @groue Guides/helpers.md refactoring + Insert Guides/localization.md in the doc...
authored
1 [up](../../../../tree/master/Guides/sample_code), [next](localization.md)
438ce09 @groue indexes.md guide
authored
2
3 Indexes
4 =======
5
e741dbc @groue Rewrite indexes sample code with filters (WIP)
authored
6 In a genuine Mustache way
f9dc2e2 @groue Restore indexes.md
authored
7 -------------------------
e741dbc @groue Rewrite indexes sample code with filters (WIP)
authored
8
438ce09 @groue indexes.md guide
authored
9 Mustache is a simple template language. Its [specification](https://github.com/mustache/spec) does not provide any built-in access to loop indexes. It does not provide any way to render a section at the beginning of the loop, and another section at the end. It does not help you render different sections for odd and even indexes.
10
11 If your goal is to design your templates so that they are compatible with [other Mustache implementations](https://github.com/defunkt/mustache/wiki/Other-Mustache-implementations), the best way to render indices and provide custom looping logic is to have each of your data objects provide with its index, regardless of how tedious it may be for you to prepare the rendered data.
12
e741dbc @groue Rewrite indexes sample code with filters (WIP)
authored
13 For instance, instead of `[ { name:'Alice' }, { name:'Bob' } ]`, you would provide: `[ { name:'Alice', position:1, isFirst:true, isOdd:true }, { name:'Bob', position:2, isFirst:false, isOdd:false } ]`.
438ce09 @groue indexes.md guide
authored
14
bc112a1 @groue Rewrite indexes sample code with filters (WIP)
authored
15
1d8cb17 @groue Rewritten indexes.md guide, so that it matches the code refactoring of 5...
authored
16 GRMustache solution
17 -------------------
438ce09 @groue indexes.md guide
authored
18
19f0f57 @groue Link from guide to sample project
authored
19 **[Download the code](../../../../tree/master/Guides/sample_code/indexes)**
3f50ab0 @groue Links to sample code projects hosted at https://github.com/groue/GRMusta...
authored
20
1d8cb17 @groue Rewritten indexes.md guide, so that it matches the code refactoring of 5...
authored
21 You can have Mustache templates render positional keys like `position` or `isFirst` for you, and avoid preparing your data.
438ce09 @groue indexes.md guide
authored
22
657c934 @groue Mandatory warning against other Mustache implementations
authored
23 **However, it may be tedious or impossible for other Mustache implementations to produce the same rendering.**
24
25 So check again the genuine Mustache way, above. Or keep on reading, now that you are warned.
26
e3ca5bd @groue Rewrite indexes sample code with filters (WIP)
authored
27 ### The template
28
bc112a1 @groue Rewrite indexes sample code with filters (WIP)
authored
29 Below we'll implement the special keys `position`, `isFirst`, and `isOdd`. We'll render the following template:
438ce09 @groue indexes.md guide
authored
30
59c121a @groue Collection Indexes Sample Code update
authored
31 `Document.mustache`:
32
438ce09 @groue indexes.md guide
authored
33 <ul>
bc112a1 @groue Rewrite indexes sample code with filters (WIP)
authored
34 {{# withPosition(people) }}
1d8cb17 @groue Rewritten indexes.md guide, so that it matches the code refactoring of 5...
authored
35 <li class="{{# isOdd }}odd{{/ isOdd }} {{# isFirst }}first{{/ isFirst }}">
bc112a1 @groue Rewrite indexes sample code with filters (WIP)
authored
36 {{ position }}:{{ name }}
37 </li>
38 {{/ withPosition(people) }}
438ce09 @groue indexes.md guide
authored
39 </ul>
40
59c121a @groue Collection Indexes Sample Code update
authored
41 Final rendering:
438ce09 @groue indexes.md guide
authored
42
43 <ul>
bc112a1 @groue Rewrite indexes sample code with filters (WIP)
authored
44 <li class="odd first">
45 1:Alice
46 </li>
47 <li class=" ">
48 2:Bob
49 </li>
50 <li class="odd ">
51 3:Craig
52 </li>
438ce09 @groue indexes.md guide
authored
53 </ul>
bc112a1 @groue Rewrite indexes sample code with filters (WIP)
authored
54
55
1d8cb17 @groue Rewritten indexes.md guide, so that it matches the code refactoring of 5...
authored
56 Our people array will be a plain array filled with plain people who don't know anything but their name. The support for the special positional keys will be brought by the `withPosition` [filter](../filters.md).
bc112a1 @groue Rewrite indexes sample code with filters (WIP)
authored
57
e3ca5bd @groue Rewrite indexes sample code with filters (WIP)
authored
58 ### The rendering
59
1d8cb17 @groue Rewritten indexes.md guide, so that it matches the code refactoring of 5...
authored
60 Let's first assume that the filter is already implemented, ready to be used. It comes as a `PositionFilter` class that is documented this way:
438ce09 @groue indexes.md guide
authored
61
62 ```objc
bc112a1 @groue Rewrite indexes sample code with filters (WIP)
authored
63 /**
59c121a @groue Collection Indexes Sample Code update
authored
64 * A GRMustache filter that render its array argument with the extra following
65 * keys defined for each item:
bc112a1 @groue Rewrite indexes sample code with filters (WIP)
authored
66 *
67 * - position: returns the 1-based index of the item
68 * - isOdd: returns YES if the position of the item is odd
69 * - isFirst: returns YES if the item is at position 1
70 */
71 @interface PositionFilter : NSObject<GRMustacheFilter>
72 @end
73 ```
74
59c121a @groue Collection Indexes Sample Code update
authored
75 Well, it looks quite a good fit for our task. We have everything we need to render our template:
438ce09 @groue indexes.md guide
authored
76
59c121a @groue Collection Indexes Sample Code update
authored
77 `Render.m`:
bc112a1 @groue Rewrite indexes sample code with filters (WIP)
authored
78
79 ```objc
59c121a @groue Collection Indexes Sample Code update
authored
80 id data = @{
81 @"people": @[
82 @{ @"name": @"Alice" },
83 @{ @"name": @"Bob" },
84 @{ @"name": @"Craig" },
85 ],
86 @"withPosition": [PositionFilter new]
87 };
88
89 NSString *rendering = [GRMustacheTemplate renderObject:data
90 fromResource:@"Document"
91 bundle:nil
92 error:NULL];
438ce09 @groue indexes.md guide
authored
93 ```
94
e3ca5bd @groue Rewrite indexes sample code with filters (WIP)
authored
95 ### The filter implementation
96
1d8cb17 @groue Rewritten indexes.md guide, so that it matches the code refactoring of 5...
authored
97 You may just skip the rest of this document, and [download the `PositionFilter` class](../../../../tree/master/Guides/sample_code/indexes). It should be trivial to adapt, should you need the `isLast` property, for example.
98
99 Let's now implement this nifty `PositionFilter` class.
e741dbc @groue Rewrite indexes sample code with filters (WIP)
authored
100
101 We have already seen above its declaration: it's simply a class that conforms to the GRMustacheFilter protocol:
102
103 ```objc
59c121a @groue Collection Indexes Sample Code update
authored
104 /**
105 * A GRMustache filter that render its array argument with the extra following
106 * keys defined for each item:
107 *
108 * - position: returns the 1-based index of the item
109 * - isOdd: returns YES if the position of the item is odd
110 * - isFirst: returns YES if the item is at position 1
111 */
e741dbc @groue Rewrite indexes sample code with filters (WIP)
authored
112 @interface PositionFilter : NSObject<GRMustacheFilter>
113 @end
114 ```
115
59c121a @groue Collection Indexes Sample Code update
authored
116 As such, it must implement the `transformedValue:` method, that returns the result of the filter. That result will perform a custom rendering of its array argument.
1d8cb17 @groue Rewritten indexes.md guide, so that it matches the code refactoring of 5...
authored
117
59c121a @groue Collection Indexes Sample Code update
authored
118 You provide custom rendering with objects that conform to the `GRMustacheRendering` protocol (see the [Rendering Objects Guide](../rendering_objects.md)). Our custom rendering object will render the section tag as many times as it has items, extending the [context stack](../runtime.md) with both a dictionary containing the special keys, and the array items that will provide the `name` key:
e741dbc @groue Rewrite indexes sample code with filters (WIP)
authored
119
120 ```objc
121 @implementation PositionFilter
122
123 /**
59c121a @groue Collection Indexes Sample Code update
authored
124 * The transformedValue: method is required by the GRMustacheFilter protocol.
125 *
126 * Don't provide any type checking, and assume the filter argument is an array:
e741dbc @groue Rewrite indexes sample code with filters (WIP)
authored
127 */
59c121a @groue Collection Indexes Sample Code update
authored
128
129 - (id)transformedValue:(NSArray *)array
e741dbc @groue Rewrite indexes sample code with filters (WIP)
authored
130 {
131 /**
59c121a @groue Collection Indexes Sample Code update
authored
132 * We want to provide custom rendering of the array.
133 *
134 * So let's provide an object that does custom rendering.
e741dbc @groue Rewrite indexes sample code with filters (WIP)
authored
135 */
136
59c121a @groue Collection Indexes Sample Code update
authored
137 return [GRMustache renderingObjectWithBlock:^NSString *(GRMustacheTag *tag, GRMustacheContext *context, BOOL *HTMLSafe, NSError *__autoreleasing *error) {
138
139 /**
140 * We are going to render the tag once for each item. We need a buffer
141 * to store all those renderings:
142 */
143
144 NSMutableString *buffer = [NSMutableString string];
145
146
147 /**
148 * For each item...
149 */
150
151 [array enumerateObjectsUsingBlock:^(id item, NSUInteger index, BOOL *stop) {
152
153 /**
154 * Have our "specials" keys enter the context stack:
155 */
156
157 id specials = @{
158 @"position": @(index + 1),
159 @"isFirst" : @(index == 0),
160 @"isOdd" : @(index % 2 == 0),
161 };
162 GRMustacheContext *itemContext = [context contextByAddingObject:specials];
163
164
165 /**
166 * Have the item itself enter the context stack (so that the `name`
167 * key can render):
168 */
169
170 itemContext = [itemContext contextByAddingObject:item];
171
172
173 /**
174 * Append the item rendering to our buffer:
175 */
176
177 NSString *itemRendering = [tag renderContentWithContext:itemContext HTMLSafe:HTMLSafe error:error];
178 [buffer appendString:itemRendering];
179 }];
180
181
182 /**
183 * Done
184 */
185
186 return buffer;
e741dbc @groue Rewrite indexes sample code with filters (WIP)
authored
187 }];
188 }
189
190 @end
191 ```
192
438ce09 @groue indexes.md guide
authored
193
c1aaf13 @groue More links from guides to sample projects
authored
194 **[Download the code](../../../../tree/master/Guides/sample_code/indexes)**
195
d67b4cc @groue Guides/helpers.md refactoring + Insert Guides/localization.md in the doc...
authored
196 [up](../../../../tree/master/Guides/sample_code), [next](localization.md)
Something went wrong with that request. Please try again.