Skip to content

Commit 0a78f43

Browse files
Support v-for="(item, index)"
This adds rudimentary support for iterating over a value with the optional second argument for the index. (Because lists and objects are so similar in PHP, this also doubles as support for iterating over an object with the optional second argument for the key; the optional third argument for the index in that case is not supported, though.) Note that, due to the limited JS evaluation in this templating engine, there’s not a whole lot you can do with the index. In the WikibaseLexeme use case, the index is only actually used in a part of the template that’s never server-side rendered; the loop still has to be declared using the index form even for the PHP renderer, though. The unrelated change from v-else="" to v-else in the fixtures was generated by `npm run-script populate-fixtures`, presumably due to a newer Vue.js version now being used – we don’t commit the package-lock.json (yet?). I figured I might as well add it, since one of the fixtures is changed anyways to test the feature.
1 parent 1e455f7 commit 0a78f43

File tree

4 files changed

+41
-6
lines changed

4 files changed

+41
-6
lines changed

src/Component.php

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -240,10 +240,21 @@ private function handleFor( DOMNode $node, array $data ) {
240240
list( $itemName, $listName ) = explode( ' in ', $node->getAttribute( 'v-for' ) );
241241
$node->removeAttribute( 'v-for' );
242242

243-
foreach ( $data[$listName] as $item ) {
243+
if ( preg_match( '/\((?P<itemName>[^,]+)\s*,\s*(?P<keyName>[^\)]+)\)/', $itemName, $matches ) ) {
244+
$itemName = $matches['itemName'];
245+
$keyName = $matches['keyName'];
246+
} else {
247+
$keyName = null;
248+
}
249+
250+
foreach ( $data[$listName] as $key => $item ) {
244251
$newNode = $node->cloneNode( true );
245252
$node->parentNode->insertBefore( $newNode, $node );
246-
$this->handleNode( $newNode, array_merge( $data, [ $itemName => $item ] ) );
253+
$newData = array_merge( $data, [ $itemName => $item ] );
254+
if ( $keyName !== null ) {
255+
$newData[$keyName] = $key;
256+
}
257+
$this->handleNode( $newNode, $newData );
247258
}
248259

249260
$this->removeNode( $node );

tests/integration/fixture/gloss_widget.html

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@
33
<div class="wikibase-lexeme-sense-glosses-list">
44
<table class="wikibase-lexeme-sense-glosses-table">
55
<tbody>
6-
<tr v-for="gloss in glosses" class="wikibase-lexeme-sense-gloss">
6+
<tr v-for="(gloss, index) in glosses" class="wikibase-lexeme-sense-gloss">
77
<td class="wikibase-lexeme-sense-gloss-language">
88
<span v-if="!inEditMode">{{gloss.language}}</span>
9-
<input v-else="" class="wikibase-lexeme-sense-gloss-language-input" v-model="gloss.language" :disabled="isSaving">
9+
<input v-else class="wikibase-lexeme-sense-gloss-language-input" v-model="gloss.language" :disabled="isSaving">
1010
</td>
1111
<td class="wikibase-lexeme-sense-gloss-value">
1212
<span v-if="!inEditMode" :dir="gloss.language|directionality" :lang="gloss.language">{{gloss.value}} <span class="wikibase-lexeme-sense-glosses-sense-id">({{senseId}})</span></span>
13-
<input v-else="" class="wikibase-lexeme-sense-gloss-value-input" v-model="gloss.value" :disabled="isSaving">
13+
<input v-else class="wikibase-lexeme-sense-gloss-value-input" v-model="gloss.value" :disabled="isSaving" :autofocus="index == glosses.length - 1">
1414
</td>
1515
</tr>
1616
</tbody>

tests/integration/fixture/lemma_widget.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
<span class="lemma-widget_lemma-language">{{lemma.language}}</span>
88
</li>
99
</ul>
10-
<div v-else="">
10+
<div v-else>
1111
<div class="lemma-widget_edit-area">
1212
<ul class="lemma-widget_lemma-list">
1313
<li v-for="lemma in lemmas" class="lemma-widget_lemma-edit-box">

tests/php/TemplatingTest.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,30 @@ public function templateWithForLoopMustache_RendersCorrectValues() {
271271
assertThat( $result, is( equalTo( '<p><a>1</a><a>2</a></p>' ) ) );
272272
}
273273

274+
/**
275+
* @test
276+
*/
277+
public function templateWithForLoopWithIndex_RendersValuesAndIndices() {
278+
$result = $this->createAndRender(
279+
'<p><a v-for="(item, index) in list">{{index}}: {{item}}</a></p>',
280+
[ 'list' => [ 10, 20 ] ]
281+
);
282+
283+
assertThat( $result, is( equalTo( '<p><a>0: 10</a><a>1: 20</a></p>' ) ) );
284+
}
285+
286+
/**
287+
* @test
288+
*/
289+
public function templateWithForLoopWithKey_RendersValuesAndKeys() {
290+
$result = $this->createAndRender(
291+
'<p><a v-for="(item, key) in list">{{key}}: {{item}}</a></p>',
292+
[ 'list' => [ 'ten' => 10, 'twenty' => 20 ] ]
293+
);
294+
295+
assertThat( $result, is( equalTo( '<p><a>ten: 10</a><a>twenty: 20</a></p>' ) ) );
296+
}
297+
274298
/**
275299
* @test
276300
*/

0 commit comments

Comments
 (0)